TapeSingleThreadInterface.hpp 10.7 KB
Newer Older
1
2
/*
 * @project        The CERN Tape Archive (CTA)
3
 * @copyright      Copyright(C) 2003-2021 CERN
4
5
6
7
 * @license        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 3 of the License, or
 *                 (at your option) any later version.
8
 *
9
10
11
12
 *                 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.
13
 *
14
15
16
 *                 You should have received a copy of the GNU General Public License
 *                 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
17
18
19
20
21
22
/* 
 * Author: dcome
 *
 * Created on March 18, 2014, 4:28 PM
 */

23
#pragma once
24

25
#include "mediachanger/MediaChangerFacade.hpp"
Victor Kotlyar's avatar
Victor Kotlyar committed
26
#include "common/log/LogContext.hpp"
27
#include "common/threading/BlockingQueue.hpp"
28
#include "common/processCap/ProcessCap.hpp"
29
#include "common/threading/Thread.hpp"
30
31
32
33
#include "Session.hpp"
#include "TapeSessionStats.hpp"
#include "VolumeInfo.hpp"
#include "tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp"
34
#include "tapeserver/castor/tape/tapeserver/daemon/EncryptionControl.hpp"
Victor Kotlyar's avatar
Victor Kotlyar committed
35
#include "common/Timer.hpp"
36

37
38
namespace castor     {
namespace tape       {
39
namespace tapeserver {
40
41
namespace daemon     {

42
  // Forward declaration
David COME's avatar
David COME committed
43
  class TapeServerReporter;
44
45
46
47
48
  /** 
   * 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
   */
49
template <class Task>
50
class TapeSingleThreadInterface : private cta::threading::Thread
51
{
52
private :
53
54
55
  /**
   * Utility to change the capabilities of the current tape thread
   */
56
  cta::server::ProcessCap &m_capUtils;
57
protected:
58
  ///the queue of tasks 
59
  cta::threading::BlockingQueue<Task *> m_tasks;
60
61
62
63
64
  
  /**
   * An interface to manipulate the drive to manipulate the tape
   * with the requested vid 
   */
65
  castor::tape::tapeserver::drive::DriveInterface & m_drive;
66
  
67
  /** Reference to the mount interface */
68
  cta::mediachanger::MediaChangerFacade & m_mc;
69
  
70
  /** Reference to the Global reporting interface */
71
  TapeServerReporter & m_initialProcess;
72
  
73
74
75
76
  ///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
77
  cta::log::LogContext m_logContext;
78
  
79
  VolumeInfo m_volInfo;
80
81
  
  /**
Eric Cano's avatar
WIP    
Eric Cano committed
82
   * Integer to notify the tapeserver if the drive has to be put down or not.
83
   */
84
  Session::EndOfSessionAction m_hardwareStatus;
Eric Cano's avatar
WIP    
Eric Cano committed
85
86
  
  /** Session statistics */
87
  TapeSessionStats m_stats;
88
89
90

  /** Encryption helper object */
  EncryptionControl m_encryptionControl;
91
92
93
  
  /** Tape load timeout after which the mount is considered failed. */
  uint32_t m_tapeLoadTimeout;
94
 
Eric Cano's avatar
WIP    
Eric Cano committed
95
  /**
96
   * Try to mount the tape for read-only access, get an exception if it fails 
97
   */
98
  void mountTapeReadOnly(){
Victor Kotlyar's avatar
Victor Kotlyar committed
99
    cta::log::ScopedParamContainer scoped(m_logContext); 
100
    scoped.add("drive_Slot",m_drive.config.librarySlot().str());
101
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
102
      cta::utils::Timer timer;
103
        m_mc.mountTapeReadOnly(m_volInfo.vid, m_drive.config.librarySlot());
104
        const std::string modeAsString = "R";
105
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
106
        if(cta::mediachanger::TAPE_LIBRARY_TYPE_MANUAL !=
107
          m_drive.config.librarySlot().getLibraryType()) {
Victor Kotlyar's avatar
Victor Kotlyar committed
108
          m_logContext.log(cta::log::INFO, "Tape mounted for read-only access");
109
        }
110
    }
111
    catch (cta::exception::Exception & ex) {
112
      scoped.add("exceptionMessage", ex.getMessageValue());
Victor Kotlyar's avatar
Victor Kotlyar committed
113
      m_logContext.log(cta::log::ERR,
114
115
116
117
118
119
120
121
122
        "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
123
    cta::log::ScopedParamContainer scoped(m_logContext); 
124
    scoped.add("drive_Slot",m_drive.config.librarySlot().str());
125
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
126
      cta::utils::Timer timer;
127
        m_mc.mountTapeReadWrite(m_volInfo.vid, m_drive.config.librarySlot());
128
        const std::string modeAsString = "RW";
129
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
Victor Kotlyar's avatar
Victor Kotlyar committed
130
        m_logContext.log(cta::log::INFO, "Tape mounted for read/write access");
131
    }
132
    catch (cta::exception::Exception & ex) {
133
      scoped.add("exceptionMessage", ex.getMessageValue());
Victor Kotlyar's avatar
Victor Kotlyar committed
134
      m_logContext.log(cta::log::ERR,
135
        "Failed to mount the tape for read/write access");
136
137
138
139
140
141
142
143
      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 
144
   * to tell us he acknowledge it has indeed a tape (get an ex exception in 
145
146
147
   * case of timeout)
   */
  void waitForDrive(){
148
    cta::utils::Timer tapeLoadTime;
149
    try{
150
151
      // wait tapeLoadTimeout seconds for drive to be ready (the mount call is synchronous, so this just the load operation.
      m_drive.waitUntilReady(m_tapeLoadTimeout);
152
    }catch(const cta::exception::Exception& e){
153
154
155
156
157
      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.");
158
159
160
      throw;
    }
  }
161
162
163
164
  
  /**
   * After waiting for the drive, we will dump the tape alert log content, if
   * not empty 
165
   * @return true if any alert was detected
166
   */
167
  bool logTapeAlerts() {
168
169
    std::vector<uint16_t> tapeAlertCodes = m_drive.getTapeAlertCodes();
    if (tapeAlertCodes.empty()) return false;
170
    size_t alertNumber = 0;
171
    // Log tape alerts in the logs.
172
    std::vector<std::string> tapeAlerts = m_drive.getTapeAlerts(tapeAlertCodes);
173
174
175
    for (std::vector<std::string>::iterator ta=tapeAlerts.begin();
            ta!=tapeAlerts.end();ta++)
    {
Victor Kotlyar's avatar
Victor Kotlyar committed
176
      cta::log::ScopedParamContainer params(m_logContext);
177
178
179
      params.add("tapeAlert",*ta)
            .add("tapeAlertNumber", alertNumber++)
            .add("tapeAlertCount", tapeAlerts.size());
Victor Kotlyar's avatar
Victor Kotlyar committed
180
      m_logContext.log(cta::log::WARNING, "Tape alert detected");
181
    }
182
    // Add tape alerts in the tape log parameters
183
    std::vector<std::string> tapeAlertsCompact = m_drive.getTapeAlertsCompact(tapeAlertCodes);
184
185
186
187
188
189
    for (std::vector<std::string>::iterator tac=tapeAlertsCompact.begin();
            tac!=tapeAlertsCompact.end();tac++)
    {
      countTapeLogError(std::string("Error_")+*tac);
    }
    return true;
190
  }
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215

  /**
   * 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());
216
    scopedContainer.add("serialNumber", m_drive.getDeviceInfo().serialNumber);
217
218
219
220
221
222
223
224
225
226
227
228
  }

  /**
   * 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);
     }
   }

229
230
231
232
233
234
235
  /**
   * 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;
  
236
public:
237
  
238
239
  Session::EndOfSessionAction getHardwareStatus() const {
    return m_hardwareStatus;
240
  }
241
242
243
  /**
   * Push into the class a sentinel value to trigger to end the the thread.
   */
244
  void finish() { m_tasks.push(NULL); }
245
246
247
248
249
  
  /**
   * Push a new task into the internal queue
   * @param t the task to push
   */
250
251
  void push(Task * t) { m_tasks.push(t); }
  
252
253
254
  /**
   * Start the threads
   */
255
256
  virtual void startThreads(){ start(); }
  
257
258
259
  /**
   *  Wait for the thread to finish
   */
Eric Cano's avatar
WIP    
Eric Cano committed
260
261
262
263
264
265
266
267
268
269
270
271
272
  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; 
  }

273
274
275
276
  virtual castor::tape::tapeserver::drive::DriveInterface* getDriveReference() {
    return &m_drive;
  }

277
278
279
280
  /**
   * Constructor
   * @param drive An interface to manipulate the drive to manipulate the tape
   * with the requested vid
281
   * @param mc The media changer (=robot) that will (un)load/(un)mount the tape
282
283
284
285
   * @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
286
   * @param tapeLoadTimeout the timeout after which the mount of the tape is considered failed
287
   */
288
  TapeSingleThreadInterface(castor::tape::tapeserver::drive::DriveInterface & drive,
289
    cta::mediachanger::MediaChangerFacade &mc,
290
    TapeServerReporter & tsr,
291
    const VolumeInfo& volInfo,
292
    cta::server::ProcessCap &capUtils,cta::log::LogContext & lc,          
293
    const std::string & externalEncryptionKeyScript, const uint32_t tapeLoadTimeout):m_capUtils(capUtils),
294
    m_drive(drive), m_mc(mc), m_initialProcess(tsr), m_vid(volInfo.vid), m_logContext(lc),
295
    m_volInfo(volInfo),m_hardwareStatus(Session::MARK_DRIVE_AS_UP),
296
    m_encryptionControl(externalEncryptionKeyScript),m_tapeLoadTimeout(tapeLoadTimeout) {}
297
}; // class TapeSingleThreadInterface
298

299
300
301
302
} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace castor
303