TapeSingleThreadInterface.hpp 9.34 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 "castor/mediachanger/MediaChangerFacade.hpp"
32
#include "castor/log/LogContext.hpp"
33
#include "common/threading/BlockingQueue.hpp"
34
#include "common/processCap/ProcessCap.hpp"
35
#include "common/threading/Threading.hpp"
36
#include "castor/tape/tapeserver/daemon/Session.hpp"
37
#include "castor/tape/tapeserver/daemon/TapeSessionStats.hpp"
38
#include "castor/tape/tapeserver/daemon/VolumeInfo.hpp"
39
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
Victor Kotlyar's avatar
Victor Kotlyar committed
40
#include "common/Timer.hpp"
41

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

47
  // Forward declaration
David COME's avatar
David COME committed
48
  class TapeServerReporter;
49
50
51
52
53
  /** 
   * 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
   */
54
template <class Task>
55
class TapeSingleThreadInterface : private cta::threading::Thread
56
{
57
private :
58
59
60
  /**
   * Utility to change the capabilities of the current tape thread
   */
61
  cta::server::ProcessCap &m_capUtils;
62
protected:
63
  ///the queue of tasks 
64
  cta::threading::BlockingQueue<Task *> m_tasks;
65
66
67
68
69
  
  /**
   * An interface to manipulate the drive to manipulate the tape
   * with the requested vid 
   */
70
  castor::tape::tapeserver::drive::DriveInterface & m_drive;
71
  
72
  /** Reference to the mount interface */
73
  mediachanger::MediaChangerFacade & m_mc;
74
  
75
  /** Reference to the Global reporting interface */
76
  TapeServerReporter & m_initialProcess;
77
  
78
79
80
81
  ///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 
82
  castor::log::LogContext m_logContext;
83
  
84
  VolumeInfo m_volInfo;
85
86
  
  /**
Eric Cano's avatar
WIP    
Eric Cano committed
87
   * Integer to notify the tapeserver if the drive has to be put down or not.
88
   */
89
  Session::EndOfSessionAction m_hardwareStatus;
Eric Cano's avatar
WIP    
Eric Cano committed
90
91
  
  /** Session statistics */
92
  TapeSessionStats m_stats;
93
 
94
95
96
97
  /**
   * This function will try to set the cap_sys_rawio capability that is needed
   * for by tape thread to access /dev/nst
   */
98
99
  void setCapabilities(){
    try {
100
      m_capUtils.setProcText("cap_sys_rawio+ep");
101
      log::LogContext::ScopedParam sp(m_logContext,
102
        log::Param("capabilities", m_capUtils.getProcText()));
103
      m_logContext.log(LOG_INFO, "Set process capabilities for using tape");
104
    } catch(const cta::exception::Exception &ne) {
105
      m_logContext.log(LOG_ERR,
106
        "Failed to set process capabilities for using the tape ");
107
108
    }
  }
109
  
Eric Cano's avatar
WIP    
Eric Cano committed
110
  /**
111
   * Try to mount the tape for read-only access, get an exception if it fails 
112
   */
113
  void mountTapeReadOnly(){
114
    castor::log::ScopedParamContainer scoped(m_logContext); 
115
    scoped.add("TPVID",m_volInfo.vid)
116
          .add("drive_Slot",m_drive.config.getLibrarySlot().str());
117
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
118
      cta::utils::Timer timer;
119
        m_mc.mountTapeReadOnly(m_volInfo.vid, m_drive.config.getLibrarySlot());
120
        const std::string modeAsString = "R";
121
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
122
        if(mediachanger::TAPE_LIBRARY_TYPE_MANUAL !=
123
          m_drive.config.getLibrarySlot().getLibraryType()) {
124
125
          m_logContext.log(LOG_INFO, "Tape mounted for read-only access");
        }
126
    }
127
128
    catch (cta::exception::Exception & ex) {
      scoped.add("exception_message", ex.getMessageValue());
129
130
131
132
133
134
135
136
137
138
139
      m_logContext.log(LOG_ERR,
        "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(){
    castor::log::ScopedParamContainer scoped(m_logContext); 
140
    scoped.add("TPVID",m_volInfo.vid)
141
          .add("drive_Slot",m_drive.config.getLibrarySlot().str());
142
    try {
Victor Kotlyar's avatar
Victor Kotlyar committed
143
      cta::utils::Timer timer;
144
        m_mc.mountTapeReadWrite(m_volInfo.vid, m_drive.config.getLibrarySlot());
145
        const std::string modeAsString = "RW";
146
        scoped.add("MCMountTime",timer.secs()).add("mode",modeAsString);
147
148
        m_logContext.log(LOG_INFO, "Tape mounted for read/write access");
    }
149
150
    catch (cta::exception::Exception & ex) {
      scoped.add("exception_message", ex.getMessageValue());
151
152
      m_logContext.log(LOG_ERR,
        "Failed to mount the tape for read/write access");
153
154
155
156
157
158
159
160
161
162
163
164
165
      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 
   * to tell us he acknowledge it has indeed a tap (get an ex exception in 
   * case of timeout)
   */
  void waitForDrive(){
    try{
Victor Kotlyar's avatar
Victor Kotlyar committed
166
      cta::utils::Timer timer;
167
168
      // wait 600 drive is ready
      m_drive.waitUntilReady(600);
169
      log::LogContext::ScopedParam sp0(m_logContext, log::Param("loadTime", timer.secs()));
170
171
    }catch(const cta::exception::Exception& e){
      log::LogContext::ScopedParam sp01(m_logContext, log::Param("exception_message", e.getMessageValue()));
172
      m_logContext.log(LOG_INFO, "Got timeout or error while waiting for drive to be ready.");
173
174
175
      throw;
    }
  }
176
177
178
179
  
  /**
   * After waiting for the drive, we will dump the tape alert log content, if
   * not empty 
180
   * @return true if any alert was detected
181
   */
182
  bool logTapeAlerts() {
183
184
    std::vector<uint16_t> tapeAlertCodes = m_drive.getTapeAlertCodes();
    if (tapeAlertCodes.empty()) return false;
185
    size_t alertNumber = 0;
186
    // Log tape alerts in the logs.
187
    std::vector<std::string> tapeAlerts = m_drive.getTapeAlerts(tapeAlertCodes);
188
189
190
191
192
193
194
195
196
    for (std::vector<std::string>::iterator ta=tapeAlerts.begin();
            ta!=tapeAlerts.end();ta++)
    {
      log::ScopedParamContainer params(m_logContext);
      params.add("tapeAlert",*ta)
            .add("tapeAlertNumber", alertNumber++)
            .add("tapeAlertCount", tapeAlerts.size());
      m_logContext.log(LOG_WARNING, "Tape alert detected");
    }
197
    // Add tape alerts in the tape log parameters
198
    std::vector<std::string> tapeAlertsCompact = m_drive.getTapeAlertsCompact(tapeAlertCodes);
199
200
201
202
203
204
    for (std::vector<std::string>::iterator tac=tapeAlertsCompact.begin();
            tac!=tapeAlertsCompact.end();tac++)
    {
      countTapeLogError(std::string("Error_")+*tac);
    }
    return true;
205
  }
206
207
208
209
210
211
212
213
  
  /**
   * 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;
  
214
public:
215
  
216
217
  Session::EndOfSessionAction getHardwareStatus() const {
    return m_hardwareStatus;
218
  }
219
220
221
  /**
   * Push into the class a sentinel value to trigger to end the the thread.
   */
222
  void finish() { m_tasks.push(NULL); }
223
224
225
226
227
  
  /**
   * Push a new task into the internal queue
   * @param t the task to push
   */
228
229
  void push(Task * t) { m_tasks.push(t); }
  
230
231
232
  /**
   * Start the threads
   */
233
234
  virtual void startThreads(){ start(); }
  
235
236
237
  /**
   *  Wait for the thread to finish
   */
Eric Cano's avatar
WIP    
Eric Cano committed
238
239
240
241
242
243
244
245
246
247
248
249
250
  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; 
  }

251
252
253
254
  /**
   * Constructor
   * @param drive An interface to manipulate the drive to manipulate the tape
   * with the requested vid
255
   * @param mc The media changer (=robot) that will (un)load/(un)mount the tape
256
257
258
259
   * @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
260
   */
261
  TapeSingleThreadInterface(castor::tape::tapeserver::drive::DriveInterface & drive,
262
    mediachanger::MediaChangerFacade &mc,
263
    TapeServerReporter & tsr,
264
    const VolumeInfo& volInfo,
265
    cta::server::ProcessCap &capUtils,castor::log::LogContext & lc):m_capUtils(capUtils),
266
    m_drive(drive), m_mc(mc), m_initialProcess(tsr), m_vid(volInfo.vid), m_logContext(lc),
267
    m_volInfo(volInfo),m_hardwareStatus(Session::MARK_DRIVE_AS_UP) {}
268
}; // class TapeSingleThreadInterface
269

270
271
272
273
} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace castor
274