TapeSingleThreadInterface.hpp 10.8 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/****************************************************************************** 
 *
 * This file is part of the Castor project.
 * See http://castor.web.cern.ch/castor
 *
 * Copyright (C) 2003  CERN
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * 
 *
 * @author Castor Dev team, castor-dev@cern.ch
 *****************************************************************************/
23
24
25
26
27
28
/* 
 * Author: dcome
 *
 * Created on March 18, 2014, 4:28 PM
 */

29
#pragma once
30

31
#include "mediachanger/MediaChangerFacade.hpp"
Victor Kotlyar's avatar
Victor Kotlyar committed
32
#include "common/log/LogContext.hpp"
33
#include "common/threading/BlockingQueue.hpp"
34
#include "common/processCap/ProcessCap.hpp"
35
#include "common/threading/Thread.hpp"
36
37
38
39
#include "Session.hpp"
#include "TapeSessionStats.hpp"
#include "VolumeInfo.hpp"
#include "tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp"
40
#include "tapeserver/castor/tape/tapeserver/daemon/EncryptionControl.hpp"
Victor Kotlyar's avatar
Victor Kotlyar committed
41
#include "common/Timer.hpp"
42

43
44
namespace castor     {
namespace tape       {
45
namespace tapeserver {
46
47
namespace daemon     {

48
  // Forward declaration
David COME's avatar
David COME committed
49
  class TapeServerReporter;
50
51
52
53
54
  /** 
   * This class is the base class for the 2 classes that will be executing 
   * all tape-{read|write} tasks. The template parameter Task is the type of 
   * task we are expecting : TapeReadTask or TapeWriteTask
   */
55
template <class Task>
56
class TapeSingleThreadInterface : private cta::threading::Thread
57
{
58
private :
59
60
61
  /**
   * Utility to change the capabilities of the current tape thread
   */
62
  cta::server::ProcessCap &m_capUtils;
63
protected:
64
  ///the queue of tasks 
65
  cta::threading::BlockingQueue<Task *> m_tasks;
66
67
68
69
70
  
  /**
   * An interface to manipulate the drive to manipulate the tape
   * with the requested vid 
   */
71
  castor::tape::tapeserver::drive::DriveInterface & m_drive;
72
  
73
  /** Reference to the mount interface */
74
  cta::mediachanger::MediaChangerFacade & m_mc;
75
  
76
  /** Reference to the Global reporting interface */
77
  TapeServerReporter & m_initialProcess;
78
  
79
80
81
82
  ///The volumeID of the tape on which we want to operate  
  const std::string m_vid;

  ///log context, for ... logging purpose, copied du to thread mechanism 
Victor Kotlyar's avatar
Victor Kotlyar committed
83
  cta::log::LogContext m_logContext;
84
  
85
  VolumeInfo m_volInfo;
86
87
  
  /**
Eric Cano's avatar
WIP    
Eric Cano committed
88
   * Integer to notify the tapeserver if the drive has to be put down or not.
89
   */
90
  Session::EndOfSessionAction m_hardwareStatus;
Eric Cano's avatar
WIP    
Eric Cano committed
91
92
  
  /** Session statistics */
93
  TapeSessionStats m_stats;
94
95
96

  /** Encryption helper object */
  EncryptionControl m_encryptionControl;
97
98
99
  
  /** Tape load timeout after which the mount is considered failed. */
  uint32_t m_tapeLoadTimeout;
100
 
Eric Cano's avatar
WIP    
Eric Cano committed
101
  /**
102
   * Try to mount the tape for read-only access, get an exception if it fails 
103
   */
104
  void mountTapeReadOnly(){
Victor Kotlyar's avatar
Victor Kotlyar committed
105
    cta::log::ScopedParamContainer scoped(m_logContext); 
106
    scoped.add("drive_Slot",m_drive.config.librarySlot().str());
107
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
108
      cta::utils::Timer timer;
109
        m_mc.mountTapeReadOnly(m_volInfo.vid, m_drive.config.librarySlot());
110
        const std::string modeAsString = "R";
111
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
112
        if(cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL !=
113
          m_drive.config.librarySlot().getLibraryType()) {
Victor Kotlyar's avatar
Victor Kotlyar committed
114
          m_logContext.log(cta::log::INFO, "Tape mounted for read-only access");
115
        }
116
    }
117
    catch (cta::exception::Exception & ex) {
118
      scoped.add("exceptionMessage", ex.getMessageValue());
Victor Kotlyar's avatar
Victor Kotlyar committed
119
      m_logContext.log(cta::log::ERR,
120
121
122
123
124
125
126
127
128
        "Failed to mount the tape for read-only access");
      throw;
    }
  }

  /**
   * Try to mount the tape for read/write access, get an exception if it fails 
   */
  void mountTapeReadWrite(){
Victor Kotlyar's avatar
Victor Kotlyar committed
129
    cta::log::ScopedParamContainer scoped(m_logContext); 
130
    scoped.add("drive_Slot",m_drive.config.librarySlot().str());
131
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
132
      cta::utils::Timer timer;
133
        m_mc.mountTapeReadWrite(m_volInfo.vid, m_drive.config.librarySlot());
134
        const std::string modeAsString = "RW";
135
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
Victor Kotlyar's avatar
Victor Kotlyar committed
136
        m_logContext.log(cta::log::INFO, "Tape mounted for read/write access");
137
    }
138
    catch (cta::exception::Exception & ex) {
139
      scoped.add("exceptionMessage", ex.getMessageValue());
Victor Kotlyar's avatar
Victor Kotlyar committed
140
      m_logContext.log(cta::log::ERR,
141
        "Failed to mount the tape for read/write access");
142
143
144
145
146
147
148
149
      throw;
    }
  }
  
  /**
   * After mounting the tape, the drive will say it has no tape inside,
   * because there was no tape the first time it was opened... 
   * That function will wait a certain amount of time for the drive 
150
   * to tell us he acknowledge it has indeed a tape (get an ex exception in 
151
152
153
   * case of timeout)
   */
  void waitForDrive(){
154
    cta::utils::Timer tapeLoadTime;
155
    try{
156
157
      // wait tapeLoadTimeout seconds for drive to be ready (the mount call is synchronous, so this just the load operation.
      m_drive.waitUntilReady(m_tapeLoadTimeout);
158
    }catch(const cta::exception::Exception& e){
159
160
161
162
163
      cta::log::ScopedParamContainer spc(m_logContext);
      spc.add("exceptionMessage",e.getMessageValue())
         .add("configuredTapeLoadTimeout",m_tapeLoadTimeout)
         .add("tapeLoadTime",tapeLoadTime.secs());
      m_logContext.log(cta::log::ERR, "Got timeout or error while waiting for drive to be ready.");
164
165
166
      throw;
    }
  }
167
168
169
170
  
  /**
   * After waiting for the drive, we will dump the tape alert log content, if
   * not empty 
171
   * @return true if any alert was detected
172
   */
173
  bool logTapeAlerts() {
174
175
    std::vector<uint16_t> tapeAlertCodes = m_drive.getTapeAlertCodes();
    if (tapeAlertCodes.empty()) return false;
176
    size_t alertNumber = 0;
177
    // Log tape alerts in the logs.
178
    std::vector<std::string> tapeAlerts = m_drive.getTapeAlerts(tapeAlertCodes);
179
180
181
    for (std::vector<std::string>::iterator ta=tapeAlerts.begin();
            ta!=tapeAlerts.end();ta++)
    {
Victor Kotlyar's avatar
Victor Kotlyar committed
182
      cta::log::ScopedParamContainer params(m_logContext);
183
184
185
      params.add("tapeAlert",*ta)
            .add("tapeAlertNumber", alertNumber++)
            .add("tapeAlertCount", tapeAlerts.size());
Victor Kotlyar's avatar
Victor Kotlyar committed
186
      m_logContext.log(cta::log::WARNING, "Tape alert detected");
187
    }
188
    // Add tape alerts in the tape log parameters
189
    std::vector<std::string> tapeAlertsCompact = m_drive.getTapeAlertsCompact(tapeAlertCodes);
190
191
192
193
194
195
    for (std::vector<std::string>::iterator tac=tapeAlertsCompact.begin();
            tac!=tapeAlertsCompact.end();tac++)
    {
      countTapeLogError(std::string("Error_")+*tac);
    }
    return true;
196
  }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

  /**
   * Log SCSI metrics for session.
   */
  virtual void logSCSIMetrics() = 0;

  /**
   * Function iterating through the map of available SCSI metrics and logging them.
   */
  void logSCSIStats(const std::string & logTitle, size_t metricsHashLength) {
    if(metricsHashLength == 0) { // skip logging entirely if hash is empty.
      m_logContext.log(cta::log::INFO, "SCSI Statistics could not be acquired from drive");
      return;
    }
    m_logContext.log(cta::log::INFO, logTitle);
  }

  /**
   * Function appending Tape VID, drive manufacturer and model and firmware version to the Scoped Container passed.
   */
  void appendDriveAndTapeInfoToScopedParams(cta::log::ScopedParamContainer &scopedContainer) {
    drive::deviceInfo di = m_drive.getDeviceInfo();
    scopedContainer.add("driveManufacturer", di.vendor);
    scopedContainer.add("driveType", di.product);
    scopedContainer.add("firmwareVersion", m_drive.getDriveFirmwareVersion());
222
    scopedContainer.add("serialNumber", m_drive.getDeviceInfo().serialNumber);
223
224
225
226
227
228
229
230
231
232
233
234
  }

  /**
   * Function appending SCSI Metrics to the Scoped Container passed.
   */
  template<class N>
  static void appendMetricsToScopedParams( cta::log::ScopedParamContainer &scopedContainer, const std::map<std::string,N> & metricsHash) {
     for(auto it = metricsHash.cbegin(); it != metricsHash.end(); it++) {
      scopedContainer.add(it->first, it->second);
     }
   }

235
236
237
238
239
240
241
  /**
   * Helper virtual function allowing the access to the m_watchdog member
   * in the inherited classes (TapeReadSingleThread and TapeWriteSingleThread)
   * @param error
   */
  virtual void countTapeLogError(const std::string & error) = 0;
  
242
public:
243
  
244
245
  Session::EndOfSessionAction getHardwareStatus() const {
    return m_hardwareStatus;
246
  }
247
248
249
  /**
   * Push into the class a sentinel value to trigger to end the the thread.
   */
250
  void finish() { m_tasks.push(NULL); }
251
252
253
254
255
  
  /**
   * Push a new task into the internal queue
   * @param t the task to push
   */
256
257
  void push(Task * t) { m_tasks.push(t); }
  
258
259
260
  /**
   * Start the threads
   */
261
262
  virtual void startThreads(){ start(); }
  
263
264
265
  /**
   *  Wait for the thread to finish
   */
Eric Cano's avatar
WIP    
Eric Cano committed
266
267
268
269
270
271
272
273
274
275
276
277
278
  virtual void waitThreads() { wait(); }
  
  /**
   * Allows to pre-set the time spent waiting for instructions, spent before
   * the tape thread is started. This is for timing the synchronous task 
   * injection done before session startup.
   * This function MUST be called before starting the thread.
   * @param secs time in seconds (double)
   */
  virtual void setWaitForInstructionsTime(double secs) { 
    m_stats.waitInstructionsTime = secs; 
  }

279
280
281
282
  virtual castor::tape::tapeserver::drive::DriveInterface* getDriveReference() {
    return &m_drive;
  }

283
284
285
286
  /**
   * Constructor
   * @param drive An interface to manipulate the drive to manipulate the tape
   * with the requested vid
287
   * @param mc The media changer (=robot) that will (un)load/(un)mount the tape
288
289
290
291
   * @param gsr
   * @param volInfo All we need to know about the tape we are manipulating 
   * @param capUtils
   * @param lc lc The log context, later on copied
292
   * @param tapeLoadTimeout the timeout after which the mount of the tape is considered failed
293
   */
294
  TapeSingleThreadInterface(castor::tape::tapeserver::drive::DriveInterface & drive,
295
    cta::mediachanger::MediaChangerFacade &mc,
296
    TapeServerReporter & tsr,
297
    const VolumeInfo& volInfo,
298
    cta::server::ProcessCap &capUtils,cta::log::LogContext & lc,          
299
    const std::string & externalEncryptionKeyScript, const uint32_t tapeLoadTimeout):m_capUtils(capUtils),
300
    m_drive(drive), m_mc(mc), m_initialProcess(tsr), m_vid(volInfo.vid), m_logContext(lc),
301
    m_volInfo(volInfo),m_hardwareStatus(Session::MARK_DRIVE_AS_UP),
302
    m_encryptionControl(externalEncryptionKeyScript),m_tapeLoadTimeout(tapeLoadTimeout) {}
303
}; // class TapeSingleThreadInterface
304

305
306
307
308
} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace castor
309