DataTransferSession.cpp 28.3 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.
Eric Cano's avatar
Eric Cano committed
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.
Eric Cano's avatar
Eric Cano committed
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/>.
 */
Eric Cano's avatar
Eric Cano committed
17

Victor Kotlyar's avatar
Victor Kotlyar committed
18
19
#include "common/log/Logger.hpp"
#include "common/log/LogContext.hpp"
20
#include "common/threading/System.hpp"
21
#include "castor/tape/tapeserver/daemon/EmptyDriveProbe.hpp"
22
#include "castor/tape/tapeserver/daemon/DataTransferSession.hpp"
23
#include "castor/tape/tapeserver/daemon/DiskReadThreadPool.hpp"
24
#include "castor/tape/tapeserver/daemon/DiskWriteThreadPool.hpp"
25
26
27
28
#include "castor/tape/tapeserver/daemon/MigrationTaskInjector.hpp"
#include "castor/tape/tapeserver/daemon/RecallReportPacker.hpp"
#include "castor/tape/tapeserver/daemon/RecallTaskInjector.hpp"
#include "castor/tape/tapeserver/daemon/TapeWriteSingleThread.hpp"
29
#include "castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp"
30
#include "castor/tape/tapeserver/daemon/TapeServerReporter.hpp"
31
#include "castor/tape/tapeserver/daemon/VolumeInfo.hpp"
32
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
33
#include "castor/tape/tapeserver/SCSI/Device.hpp"
34
#include "common/exception/Exception.hpp"
35
#include "scheduler/RetrieveMount.hpp"
36
#include "castor/tape/tapeserver/RAO/RAOParams.hpp"
37

38
#include <google/protobuf/stubs/common.h>
39
#include <memory>
40

41
42
43
//------------------------------------------------------------------------------
//Constructor
//------------------------------------------------------------------------------
44
castor::tape::tapeserver::daemon::DataTransferSession::DataTransferSession(
45
    const std::string & hostname,
Victor Kotlyar's avatar
Victor Kotlyar committed
46
    cta::log::Logger & log,
47
    System::virtualWrapper & sysWrapper,
48
    const cta::tape::daemon::TpconfigLine & driveConfig,
49
    cta::mediachanger::MediaChangerFacade & mc,
50
    cta::tape::daemon::TapedProxy & initialProcess,
51
    cta::server::ProcessCap & capUtils,
52
    const DataTransferConfig & castorConf,
53
    cta::Scheduler & scheduler):
54
    m_log(log),
55
56
    m_sysWrapper(sysWrapper),
    m_driveConfig(driveConfig),
57
    m_castorConf(castorConf),
58
    m_driveInfo({driveConfig.unitName, cta::utils::getShortHostname(), driveConfig.logicalLibrary}),
59
    m_mc(mc),
60
    m_intialProcess(initialProcess),
61
    m_capUtils(capUtils),
62
    m_scheduler(scheduler)
63
    {
64
}
Eric Cano's avatar
Eric Cano committed
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//------------------------------------------------------------------------------
// setProcessCapabilities
//------------------------------------------------------------------------------
/**
 * This function will try to set the cap_sys_rawio capability that is needed
 * for by tape thread to access /dev/nst
 */
void castor::tape::tapeserver::daemon::DataTransferSession::setProcessCapabilities(
  const std::string &capabilities){
  cta::log::LogContext lc(m_log);
  try {
    m_capUtils.setProcText(capabilities);
    cta::log::LogContext::ScopedParam sp(lc,
      cta::log::Param("capabilities", m_capUtils.getProcText()));
    lc.log(cta::log::INFO, "Set process capabilities for using tape");
  } catch(const cta::exception::Exception &ne) {
    lc.log(cta::log::ERR,
      "Failed to set process capabilities for using the tape ");
  }
}

87
//------------------------------------------------------------------------------
88
//DataTransferSession::execute
89
//------------------------------------------------------------------------------
90
/**
91
 * Function's synopsis 
92
93
94
95
96
97
 * 1) Prepare the logging environment
 *  Create a sticky thread name, which will be overridden by the other threads
 * 2a) Get initial information from the client
 * 2b) Log The result
 * Then branch to the right execution
 */
98
99
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::execute() {
Eric Cano's avatar
Eric Cano committed
100
  // 1) Prepare the logging environment
Victor Kotlyar's avatar
Victor Kotlyar committed
101
  cta::log::LogContext lc(m_log);
102
  // Create a sticky thread name, which will be overridden by the other threads
Victor Kotlyar's avatar
Victor Kotlyar committed
103
  lc.pushOrReplace(cta::log::Param("thread", "MainThread"));
104
  lc.pushOrReplace(cta::log::Param("tapeDrive", m_driveConfig.unitName));
105
106

  setProcessCapabilities("cap_sys_rawio+ep");
107
108
  
  // 2a) Determine if we want to mount at all (for now)
109
110
111
  // This variable will allow us to see if we switched from down to up and start a
  // empty drive probe session if so.
  bool downUpTransition = false;
112
schedule:
113
114
  while (true) {
    try {
115
      auto desiredState = m_scheduler.getDesiredDriveState(m_driveConfig.unitName, lc);
116
      if (!desiredState.up) {
117
        downUpTransition  = true;
118
119
        // We wait a bit before polling the scheduler again.
        // TODO: parametrize the duration?
120
        m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, lc);
121
122
123
124
125
126
127
        sleep (5);
      } else {
        break;
      }
    } catch (cta::Scheduler::NoSuchDrive & e) {
      // The object store does not even know about this drive. We will report our state
      // (default status is down).
128
      m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, lc);
129
130
    }
  }
131
132
133
134
  // If we get here after seeing a down desired state, we are transitioning  from
  // down to up. In such a case, we will run an empty 
  if (downUpTransition) {
    downUpTransition = false;
135
    m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Probing, lc);
136
137
138
    castor::tape::tapeserver::daemon::EmptyDriveProbe emptyDriveProbe(m_log, m_driveConfig, m_sysWrapper);
    lc.log(cta::log::INFO, "Transition from down to up detected. Will check if a tape is in the drive.");
    if (!emptyDriveProbe.driveIsEmpty()) {
139
      m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, lc);
140
      cta::common::dataStructures::SecurityIdentity securityIdentity;
141
142
143
      cta::common::dataStructures::DesiredDriveState driveState;
      driveState.up = false;
      driveState.forceDown = false;
144
      std::string errorMsg = "A tape was detected in the drive. Putting the drive down.";
145
146
147
      cta::optional<std::string> probeErrorMsg = emptyDriveProbe.getProbeErrorMsg();
      if(probeErrorMsg)
        errorMsg = probeErrorMsg.value();
148
149
      int logLevel = cta::log::ERR;
      driveState.setReasonFromLogMsg(logLevel,errorMsg);
150
      m_scheduler.setDesiredDriveState(securityIdentity, m_driveConfig.unitName, driveState, lc);
151
      lc.log(logLevel, errorMsg);
152
153
154
155
156
      goto schedule;
    } else {
      lc.log(cta::log::INFO, "No tape detected in the drive. Proceeding with scheduling.");
    }
  }
157
  // 2b) Get initial mount information
158
  std::unique_ptr<cta::TapeMount> tapeMount;
159
160
  // As getting next mount could be long, we report the drive as up immediately.
  m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Up, lc);
161
  try {
162
163
    if (m_scheduler.getNextMountDryRun(m_driveConfig.logicalLibrary, m_driveConfig.unitName, lc))
      tapeMount.reset(m_scheduler.getNextMount(m_driveConfig.logicalLibrary, m_driveConfig.unitName, lc).release());
164
  } catch (cta::exception::Exception & e) {
Victor Kotlyar's avatar
Victor Kotlyar committed
165
    cta::log::ScopedParamContainer localParams(lc);
166
167
168
169
170
    std::string exceptionMsg = e.getMessageValue();
    int logLevel = cta::log::ERR;
    localParams.add("errorMessage", exceptionMsg);
    lc.log(logLevel, "Error while scheduling new mount. Putting the drive down. Stack trace follows.");
    lc.logBacktrace(logLevel, e.backtrace());
171
    m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, lc);
172
    cta::common::dataStructures::SecurityIdentity cliId;
173
174
175
    cta::common::dataStructures::DesiredDriveState driveState;
    driveState.up = false;
    driveState.forceDown = false;
176
    driveState.setReasonFromLogMsg(cta::log::ERR,exceptionMsg);
177
    m_scheduler.setDesiredDriveState(cliId, m_driveConfig.unitName, driveState, lc);
178
179
    return MARK_DRIVE_AS_DOWN;
  }
180
  // No mount to be done found, that was fast...
181
  if (!tapeMount.get()) {
182
    lc.log(cta::log::DEBUG, "No new mount found. (sleeping 10 seconds)");
183
    m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Up, lc);
184
185
186
    sleep (10);
    goto schedule;
    // return MARK_DRIVE_AS_UP;
187
  }
188
189
  m_volInfo.vid=tapeMount->getVid();
  m_volInfo.mountType=tapeMount->getMountType();
190
  m_volInfo.nbFiles=tapeMount->getNbFiles();
191
  m_volInfo.mountId=tapeMount->getMountTransactionId();
192
  // 2c) ... and log.
193
  // Make the DGN and TPVID parameter permanent.
Victor Kotlyar's avatar
Victor Kotlyar committed
194
  cta::log::ScopedParamContainer params(lc);
195
  params.add("tapeVid", m_volInfo.vid)
196
        .add("mountId", tapeMount->getMountTransactionId());
197
  {
Victor Kotlyar's avatar
Victor Kotlyar committed
198
    cta::log::ScopedParamContainer localParams(lc);
199
    localParams.add("tapebridgeTransId", tapeMount->getMountTransactionId())
200
               .add("mountType", mountTypeToString(m_volInfo.mountType));
Victor Kotlyar's avatar
Victor Kotlyar committed
201
    lc.log(cta::log::INFO, "Got volume from client");
202
  }
Eric Cano's avatar
Eric Cano committed
203
204
  
  // Depending on the type of session, branch into the right execution
205
  switch(m_volInfo.mountType) {
206
  case cta::common::dataStructures::MountType::Retrieve:
207
    return executeRead(lc, dynamic_cast<cta::RetrieveMount *>(tapeMount.get()));
208
209
  case cta::common::dataStructures::MountType::ArchiveForUser:
  case cta::common::dataStructures::MountType::ArchiveForRepack:
210
    return executeWrite(lc, dynamic_cast<cta::ArchiveMount *>(tapeMount.get()));
211
212

    
213
  case cta::common::dataStructures::MountType::Label:
214
    return executeLabel(lc, dynamic_cast<cta::LabelMount *>(tapeMount.get()));
215
  default:
216
    return MARK_DRIVE_AS_UP;
217
218
  }
}
219
//------------------------------------------------------------------------------
220
//DataTransferSession::executeRead
221
//------------------------------------------------------------------------------
222
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
Victor Kotlyar's avatar
Victor Kotlyar committed
223
 castor::tape::tapeserver::daemon::DataTransferSession::executeRead(cta::log::LogContext & lc, cta::RetrieveMount *retrieveMount) {
224
225
226
227
228
  // We are ready to start the session. We need to create the whole machinery 
  // in order to get the task injector ready to check if we actually have a 
  // file to recall.
  // findDrive does not throw exceptions (it catches them to log errors)
  // A NULL pointer is returned on failure
229
  retrieveMount->setFetchEosFreeSpaceScript(m_castorConf.fetchEosFreeSpaceScript);
230
  std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc,retrieveMount));
231
  if(!drive.get()) return MARK_DRIVE_AS_DOWN;    
232
233
234
235
  // We can now start instantiating all the components of the data path
  {
    // Allocate all the elements of the memory management (in proper order
    // to refer them to each other)
236
    RecallReportPacker rrp(retrieveMount, lc);
237
    rrp.disableBulk(); //no bulk needed anymore
238
    RecallWatchDog rwd(15,60*10,m_intialProcess,*retrieveMount,m_driveConfig.unitName,lc);
239
    
240
    RecallMemoryManager mm(m_castorConf.nbBufs, m_castorConf.bufsz,lc);
241
    TapeServerReporter tsr(m_intialProcess, m_driveConfig, 
242
            m_hostname, m_volInfo, lc);
243
244
    //we retrieved the detail from the client in execute, so at this point 
    //we can already report !
245
246
    tsr.reportState(cta::tape::session::SessionState::Mounting,
      cta::tape::session::SessionType::Retrieve);
247
    
248
    TapeReadSingleThread trst(*drive, m_mc, tsr, m_volInfo, 
249
        m_castorConf.bulkRequestRecallMaxFiles,m_capUtils,rwd,lc,rrp,
250
        m_castorConf.useLbp, m_castorConf.useRAO, m_castorConf.externalEncryptionKeyScript,*retrieveMount, m_castorConf.tapeLoadTimeout);
251
    DiskWriteThreadPool dwtp(m_castorConf.nbDiskThreads,
252
        rrp,
253
        rwd,
254
        lc,
255
256
        m_castorConf.xrootPrivateKey,
        m_castorConf.xrootTimeout);
257
    RecallTaskInjector rti(mm, trst, dwtp, *retrieveMount,
258
259
            m_castorConf.bulkRequestRecallMaxFiles,
            m_castorConf.bulkRequestRecallMaxBytes,lc);
260
261
262
    // Workaround for bug CASTOR-4829: tapegateway: should request positioning by blockid for recalls instead of fseq
    // In order to implement the fix, the task injector needs to know the type
    // of the client
263
    trst.setTaskInjector(&rti);
264
    rrp.setWatchdog(rwd);
265
    
266
267
    rti.setDriveInterface(trst.getDriveReference());

268
269
    // We are now ready to put everything in motion. First step is to check
    // we get any concrete job to be done from the client (via the task injector)
Victor Kotlyar's avatar
Victor Kotlyar committed
270
    cta::utils::Timer timer;
271
272
273

    // The RecallTaskInjector and the TapeReadSingleThread share the promise
    if (m_castorConf.useRAO) {
274
      castor::tape::tapeserver::rao::RAOParams raoDataConfig(m_castorConf.useRAO,m_castorConf.raoLtoAlgorithm, m_castorConf.raoLtoAlgorithmOptions,m_volInfo.vid);
275
      rti.initRAO(raoDataConfig, &m_scheduler.getCatalogue());
276
    }
277
278
    bool noFilesToRecall = false;
    if (rti.synchronousFetch(noFilesToRecall)) {  //adapt the recall task injector (starting from synchronousFetch)
279
      // We got something to recall. Time to start the machinery
Eric Cano's avatar
WIP    
Eric Cano committed
280
      trst.setWaitForInstructionsTime(timer.secs());
281
      rwd.startThread();
282
283
284
285
      trst.startThreads();
      dwtp.startThreads();
      rrp.startThreads();
      rti.startThreads();
286
      tsr.startThreads();
287
288
289
290
291
292
      // This thread is now going to be idle until the system unwinds at the end 
      // of the session
      // All client notifications are done by the report packer, including the
      // end of session
      rti.waitThreads();
      dwtp.waitThreads();
293
      rrp.setDiskDone();
294
      trst.waitThreads();
295
296
      rrp.setTapeDone();
      rrp.waitThread();
297
      tsr.waitThreads();
298
      rwd.stopAndWaitThread();
299
      return trst.getHardwareStatus();
300
301
302
    } else {
      // Just log this was an empty mount and that's it. The memory management
      // will be deallocated automatically.
303
304
305
306
307
308
309
310
311
      int priority = cta::log::ERR;
      std::string status = "success";
      if(noFilesToRecall){
        //If this is an empty mount because no files have been popped from the queue, it is just a warning
        priority = cta::log::WARNING;
        status = "failure";
      }
      
      lc.log(priority, "Aborting recall mount startup: empty mount");
312
313
314
315
316
317
318
      
      std::string mountId = retrieveMount->getMountTransactionId();
      std::string mountType = cta::common::dataStructures::toString(retrieveMount->getMountType());
      
      cta::log::Param errorMessageParam("errorMessage", "Aborted: empty recall mount");
      cta::log::Param mountIdParam("mountId", mountId);
      cta::log::Param mountTypeParam("mountType", mountType);
319
      cta::log::Param statusParam("status",status);
320
321
      
      cta::log::LogContext::ScopedParam sp1(lc, errorMessageParam);
322
      try {
323
        retrieveMount->abort();
324
325
        rwd.updateStats(TapeSessionStats());
        rwd.reportStats();
326
        std::list<cta::log::Param> paramList { errorMessageParam, mountIdParam, mountTypeParam, statusParam };
327
328
        m_intialProcess.addLogParams(m_driveConfig.unitName,paramList);
        cta::log::LogContext::ScopedParam sp08(lc, cta::log::Param("MountTransactionId", mountId));
Victor Kotlyar's avatar
Victor Kotlyar committed
329
        cta::log::LogContext::ScopedParam sp11(lc, cta::log::Param("errorMessage", "Aborted: empty recall mount"));
330
        lc.log(priority, "Notified client of end session with error");
331
      } catch(cta::exception::Exception & ex) {
Victor Kotlyar's avatar
Victor Kotlyar committed
332
333
        cta::log::LogContext::ScopedParam sp1(lc, cta::log::Param("notificationError", ex.getMessageValue()));
        lc.log(cta::log::ERR, "Failed to notified client of end session with error");
334
      }
335
336
      // Empty mount, hardware is OK
      return MARK_DRIVE_AS_UP;
337
338
339
    }
  }
}
340
//------------------------------------------------------------------------------
341
//DataTransferSession::executeWrite
342
//------------------------------------------------------------------------------
343
344
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(
Victor Kotlyar's avatar
Victor Kotlyar committed
345
  cta::log::LogContext & lc, cta::ArchiveMount *archiveMount) {
346
347
348
349
  // We are ready to start the session. We need to create the whole machinery 
  // in order to get the task injector ready to check if we actually have a 
  // file to migrate.
  // 1) Get hold of the drive error logs are done inside the findDrive function
350
  std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc,archiveMount));
351
  if (!drive.get()) return MARK_DRIVE_AS_DOWN;
352
353
  // Once we got hold of the drive, we can run the session
  {
354
    //dereferencing configLine is safe, because if configLine were not valid, 
355
    //then findDrive would have return NULL and we would have not end up there
356
    TapeServerReporter tsr(m_intialProcess, m_driveConfig, m_hostname,m_volInfo,lc);
357
    
358
359
    MigrationMemoryManager mm(m_castorConf.nbBufs,
        m_castorConf.bufsz,lc);
360
    MigrationReportPacker mrp(archiveMount, lc);
361
    MigrationWatchDog mwd(15,60*10,m_intialProcess,*archiveMount,m_driveConfig.unitName,lc);
362
    TapeWriteSingleThread twst(*drive,
363
        m_mc,
364
        tsr,
365
        mwd,
366
        m_volInfo,
367
368
        lc,
        mrp,
369
        m_capUtils,    
370
        m_castorConf.maxFilesBeforeFlush,
371
        m_castorConf.maxBytesBeforeFlush,
372
        m_castorConf.useLbp,
373
        m_castorConf.externalEncryptionKeyScript,
374
375
        *archiveMount,
        m_castorConf.tapeLoadTimeout);
376
 
377
378
379
    DiskReadThreadPool drtp(m_castorConf.nbDiskThreads,
        m_castorConf.bulkRequestMigrationMaxFiles,
        m_castorConf.bulkRequestMigrationMaxBytes,
380
        mwd,
381
        lc,
382
383
        m_castorConf.xrootPrivateKey,
        m_castorConf.xrootTimeout);
384
    MigrationTaskInjector mti(mm, drtp, twst, *archiveMount, 
385
386
            m_castorConf.bulkRequestMigrationMaxFiles,
            m_castorConf.bulkRequestMigrationMaxBytes,lc);
387
    drtp.setTaskInjector(&mti);
388
    twst.setTaskInjector(&mti);
389
    mrp.setWatchdog(mwd);
Victor Kotlyar's avatar
Victor Kotlyar committed
390
    cta::utils::Timer timer;
391

392
393
    bool noFilesToMigrate = false;
    if (mti.synchronousInjection(noFilesToMigrate)) {
394
      const uint64_t firstFseqFromClient = mti.firstFseqToWrite();
395
396
      
      //the last fseq written on the tape is the first file's fseq minus one
397
      twst.setlastFseq(firstFseqFromClient-1);
398
      
399
      //we retrieved the detail from the client in execute, so at this point 
400
401
402
      //we can report we will mount the tape.
      // TODO: create a "StartingSession" state as the mounting will happen in
      // the to-be-created tape thread.
403
      try {
404
405
        tsr.reportState(cta::tape::session::SessionState::Mounting, 
          cta::tape::session::SessionType::Archive);
406
      } catch (cta::exception::Exception & e) {
Victor Kotlyar's avatar
Victor Kotlyar committed
407
408
        cta::log::LogContext::ScopedParam sp1(lc, cta::log::Param("errorMessage", e.getMessage().str()));
        lc.log(cta::log::INFO, "Aborting the session after problem with mount details. Notifying the client.");
409
        mrp.synchronousReportEndWithErrors(e.getMessageValue(), 666, lc);
410
411
        return MARK_DRIVE_AS_UP;
      } catch (...) {
Victor Kotlyar's avatar
Victor Kotlyar committed
412
        lc.log(cta::log::INFO, "Aborting the session after problem with mount details (unknown exception). Notifying the client.");
413
        mrp.synchronousReportEndWithErrors("Unknown exception while checking session parameters with VMGR", 666, lc);
414
415
        return MARK_DRIVE_AS_UP;
      }
416

417
418
419
420
      // We have something to do: start the session by starting all the 
      // threads.
      mm.startThreads();
      drtp.startThreads();
421
      mwd.startThread();
Eric Cano's avatar
WIP    
Eric Cano committed
422
      twst.setWaitForInstructionsTime(timer.secs());
423
424
425
      twst.startThreads();
      mrp.startThreads();
      mti.startThreads();
426
      tsr.startThreads();
427
      
428
429
430
431
432
433
      // Synchronise with end of threads
      mti.waitThreads();
      mrp.waitThread();
      twst.waitThreads();
      drtp.waitThreads();
      mm.waitThreads();
434
      tsr.waitThreads();
435
      mwd.stopAndWaitThread();
436
437
      
      return twst.getHardwareStatus();
438
439
440
    } else {
      // Just log this was an empty mount and that's it. The memory management
      // will be deallocated automatically.
441
442
443
444
445
446
447
      int priority = cta::log::ERR;
      std::string status = "failure";
      if(noFilesToMigrate){
        priority = cta::log::WARNING;
        status = "success";
      }
      lc.log(priority, "Aborting migration mount startup: empty mount");
448
449
450
451
452
453
      
      std::string mountId = archiveMount->getMountTransactionId();
      std::string mountType = cta::common::dataStructures::toString(archiveMount->getMountType());
      cta::log::Param errorMessageParam("errorMessage", "Aborted: empty migration mount");
      cta::log::Param mountIdParam("mountId", mountId);
      cta::log::Param mountTypeParam("mountType",mountType);
454
      cta::log::Param statusParam("status", status);
455
      cta::log::LogContext::ScopedParam sp1(lc, errorMessageParam);
456
      try {
457
        archiveMount->complete();
458
459
        mwd.updateStats(TapeSessionStats());
        mwd.reportStats();
460
        std::list<cta::log::Param> paramList { errorMessageParam, mountIdParam, mountTypeParam, statusParam };
461
462
        m_intialProcess.addLogParams(m_driveConfig.unitName,paramList);
        cta::log::LogContext::ScopedParam sp1(lc, cta::log::Param("MountTransactionId", mountId));
463
        lc.log(priority, "Notified client of end session with error");
464
      } catch(cta::exception::Exception & ex) {
Victor Kotlyar's avatar
Victor Kotlyar committed
465
466
        cta::log::LogContext::ScopedParam sp1(lc, cta::log::Param("notificationError", ex.getMessageValue()));
        lc.log(cta::log::ERR, "Failed to notified client of end session with error");
467
      }
468
469
      // Empty mount, hardware safe
      return MARK_DRIVE_AS_UP;
470
    }
471
472
  }
}
473

474
//------------------------------------------------------------------------------
475
//DataTransferSession::executeLabel
476
477
478
//------------------------------------------------------------------------------
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::executeLabel(cta::log::LogContext& lc, cta::LabelMount* labelMount) {
479
  throw cta::exception::Exception("In DataTransferSession::executeLabel(): not implemented");
480
481
482
483
  // TODO
}


484
//------------------------------------------------------------------------------
485
//DataTransferSession::findDrive
486
//------------------------------------------------------------------------------
487
488
489
490
491
492
493
494
/*
 * Function synopsis  :
 *  1) Get hold of the drive and check it.
 *  --- Check If we did not find the drive in the tpConfig, we have a problem
 *  2) Try to find the drive 
 *    Log if we do not find it
 *  3) Try to open it, log if we fail
 */
495
/**
496
 * Try to find the drive that is described by m_request.driveUnit
497
498
499
 * @param lc For logging purpose
 * @return the drive if found, NULL otherwise
 */
500
castor::tape::tapeserver::drive::DriveInterface *
501
castor::tape::tapeserver::daemon::DataTransferSession::findDrive(const cta::tape::daemon::TpconfigLine
Victor Kotlyar's avatar
Victor Kotlyar committed
502
  &driveConfig, cta::log::LogContext&  lc, cta::TapeMount *mount) {
503
  // Find the drive in the system's SCSI devices
504
  castor::tape::SCSI::DeviceVector dv(m_sysWrapper);
505
506
  castor::tape::SCSI::DeviceInfo driveInfo;
  try {
507
    driveInfo = dv.findBySymlink(driveConfig.devFilename);
508
509
  } catch (castor::tape::SCSI::DeviceVector::NotFound & e) {
    // We could not find this drive in the system's SCSI devices
510
    cta::log::LogContext::ScopedParam sp09(lc, cta::log::Param("devFilename", driveConfig.devFilename));
Victor Kotlyar's avatar
Victor Kotlyar committed
511
    lc.log(cta::log::ERR, "Drive not found on this path");
512
    
513
514
    std::stringstream errMsg;
    errMsg << "Drive not found on this path" << lc;
515
    mount->abort();
Victor Kotlyar's avatar
Victor Kotlyar committed
516
517
518
    cta::log::LogContext::ScopedParam sp10(lc, cta::log::Param("tapebridgeTransId", mount->getMountTransactionId()));
    cta::log::LogContext::ScopedParam sp13(lc, cta::log::Param("errorMessage", errMsg.str()));
    lc.log(cta::log::ERR, "Notified client of end session with error");
519
    return NULL;
520
  } catch (cta::exception::Exception & e) {
521
    // We could not find this drive in the system's SCSI devices
522
    cta::log::LogContext::ScopedParam sp09(lc, cta::log::Param("devFilename", driveConfig.devFilename));
Victor Kotlyar's avatar
Victor Kotlyar committed
523
524
    cta::log::LogContext::ScopedParam sp10(lc, cta::log::Param("errorMessage", e.getMessageValue()));
    lc.log(cta::log::ERR, "Error looking to path to tape drive");
525
    
526
527
    std::stringstream errMsg;
    errMsg << "Error looking to path to tape drive: " << lc;
528
    mount->abort();
Victor Kotlyar's avatar
Victor Kotlyar committed
529
530
531
    cta::log::LogContext::ScopedParam sp11(lc, cta::log::Param("tapebridgeTransId", mount->getMountTransactionId()));
    cta::log::LogContext::ScopedParam sp14(lc, cta::log::Param("errorMessage", errMsg.str()));
    lc.log(cta::log::ERR, "Notified client of end session with error");
532
    return NULL;
533
534
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
535
    cta::log::LogContext::ScopedParam sp09(lc, cta::log::Param("devFilename", driveConfig.devFilename));
Victor Kotlyar's avatar
Victor Kotlyar committed
536
    lc.log(cta::log::ERR, "Unexpected exception while looking for drive");
537
    
538
539
    std::stringstream errMsg;
    errMsg << "Unexpected exception while looking for drive" << lc;
540
    mount->abort();
Victor Kotlyar's avatar
Victor Kotlyar committed
541
542
543
    cta::log::LogContext::ScopedParam sp10(lc, cta::log::Param("tapebridgeTransId", mount->getMountTransactionId()));
    cta::log::LogContext::ScopedParam sp13(lc, cta::log::Param("errorMessage", errMsg.str()));
    lc.log(cta::log::ERR, "Notified client of end session with error");
544
    return NULL;
545
546
  }
  try {
547
    std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive;
548
    drive.reset(castor::tape::tapeserver::drive::createDrive(driveInfo, m_sysWrapper));
549
    if (drive.get()) drive->config = driveConfig;
550
    return drive.release();
551
  } catch (cta::exception::Exception & e) {
552
    // We could not find this drive in the system's SCSI devices
553
    cta::log::LogContext::ScopedParam sp09(lc, cta::log::Param("devFilename", driveConfig.devFilename));
Victor Kotlyar's avatar
Victor Kotlyar committed
554
555
    cta::log::LogContext::ScopedParam sp10(lc, cta::log::Param("errorMessage", e.getMessageValue()));
    lc.log(cta::log::ERR, "Error opening tape drive");
556
    
557
558
    std::stringstream errMsg;
    errMsg << "Error opening tape drive" << lc;
559
    mount->abort();
Victor Kotlyar's avatar
Victor Kotlyar committed
560
561
562
    cta::log::LogContext::ScopedParam sp11(lc, cta::log::Param("tapebridgeTransId", mount->getMountTransactionId()));
    cta::log::LogContext::ScopedParam sp14(lc, cta::log::Param("errorMessage", errMsg.str()));
    lc.log(cta::log::ERR, "Notified client of end session with error");
563
    return NULL;
564
565
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
566
    cta::log::LogContext::ScopedParam sp09(lc, cta::log::Param("devFilename", driveConfig.devFilename));
Victor Kotlyar's avatar
Victor Kotlyar committed
567
    lc.log(cta::log::ERR, "Unexpected exception while opening drive");
568
    
569
570
    std::stringstream errMsg;
    errMsg << "Unexpected exception while opening drive" << lc;
571
    mount->abort();
Victor Kotlyar's avatar
Victor Kotlyar committed
572
573
574
    cta::log::LogContext::ScopedParam sp10(lc, cta::log::Param("tapebridgeTransId", mount->getMountTransactionId()));
    cta::log::LogContext::ScopedParam sp13(lc, cta::log::Param("errorMessage", errMsg.str()));
    lc.log(cta::log::ERR, "Notified client of end session with error");
575
    return NULL;
576
  }
Eric Cano's avatar
Eric Cano committed
577
}
578
579

//------------------------------------------------------------------------------
580
// destructor
581
//------------------------------------------------------------------------------
582
583
584
585
586
castor::tape::tapeserver::daemon::DataTransferSession::~DataTransferSession()
  throw () {
  try {
    google::protobuf::ShutdownProtobufLibrary();
  } catch(...) {
Victor Kotlyar's avatar
Victor Kotlyar committed
587
    m_log(cta::log::ERR, "google::protobuf::ShutdownProtobufLibrary() threw an"
588
      " unexpected exception");
589
  }
590
}
Steven Murray's avatar
Steven Murray committed
591
592
593
594
595

//-----------------------------------------------------------------------------
// volumeModeToString
//-----------------------------------------------------------------------------
const char *castor::tape::tapeserver::daemon::DataTransferSession::
596
  mountTypeToString(const cta::common::dataStructures::MountType mountType) const throw() {
597
  switch(mountType) {
598
  case cta::common::dataStructures::MountType::Retrieve: return "Retrieve";
599
600
  case cta::common::dataStructures::MountType::ArchiveForUser : return "ArchiveForUser";
  case cta::common::dataStructures::MountType::ArchiveForRepack : return "ArchiveForRepack";
601
  case cta::common::dataStructures::MountType::Label: return "Label";
602
  default                      : return "UNKNOWN";
Steven Murray's avatar
Steven Murray committed
603
604
  }
}