DataTransferSession.cpp 27.1 KB
Newer Older
Eric Cano's avatar
Eric Cano committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/******************************************************************************
 *
 * 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
 *****************************************************************************/

Steven Murray's avatar
Steven Murray committed
24
25
#include "castor/common/CastorConfiguration.hpp"
#include "castor/exception/Exception.hpp"
Eric Cano's avatar
Eric Cano committed
26
#include "castor/log/LogContext.hpp"
27
#include "castor/System.hpp"
28
29
#include "castor/tape/tapeserver/client/ClientProxy.hpp"
#include "castor/tape/tapeserver/daemon/DataTransferSession.hpp"
30
#include "castor/tape/tapeserver/daemon/DiskReadThreadPool.hpp"
31
#include "castor/tape/tapeserver/daemon/DiskWriteThreadPool.hpp"
32
33
34
35
#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"
36
#include "castor/tape/tapeserver/daemon/TapeReadSingleThread.hpp"
37
#include "castor/tape/tapeserver/daemon/TapeServerReporter.hpp"
38
#include "castor/tape/tapeserver/drive/DriveInterface.hpp"
39
#include "castor/tape/tapeserver/SCSI/Device.hpp"
40
#include "log.h"
41
#include "scheduler/TapeMount.hpp"
42
43
#include "serrno.h"
#include "stager_client_commandline.h"
44

45
#include <google/protobuf/stubs/common.h>
46
#include <memory>
47

48
49
50
//------------------------------------------------------------------------------
//Constructor
//------------------------------------------------------------------------------
51
castor::tape::tapeserver::daemon::DataTransferSession::DataTransferSession(
52
    const std::string & hostname,
53
54
    castor::log::Logger & log,
    System::virtualWrapper & sysWrapper,
55
    const DriveConfig & driveConfig,
56
    castor::mediachanger::MediaChangerFacade & mc,
57
    castor::messages::TapeserverProxy & initialProcess,
58
    castor::server::ProcessCap & capUtils,
59
60
    const DataTransferConfig & castorConf,
    cta::Scheduler & scheduler): 
61
    m_log(log),
62
63
64
    m_sysWrapper(sysWrapper),
    m_driveConfig(driveConfig),
    m_castorConf(castorConf), 
65
    m_mc(mc),
66
    m_intialProcess(initialProcess),
67
68
69
    m_capUtils(capUtils),
    m_scheduler(scheduler)
    {
70
}
Eric Cano's avatar
Eric Cano committed
71

72
//------------------------------------------------------------------------------
73
//DataTransferSession::execute
74
//------------------------------------------------------------------------------
75
/**
76
 * Function's synopsis 
77
78
79
80
81
82
 * 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
 */
83
84
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::execute() {
Eric Cano's avatar
Eric Cano committed
85
  // 1) Prepare the logging environment
86
  log::LogContext lc(m_log);
87
  // Create a sticky thread name, which will be overridden by the other threads
88
  lc.pushOrReplace(log::Param("thread", "MainThread"));
89
  // 2a) Get initial information from the client
90
  client::ClientProxy::RequestReport reqReport;
Eric Cano's avatar
Eric Cano committed
91
  try {
92
    std::unique_ptr<cta::TapeMount> tapeMount(m_scheduler.getNextMount("LLname", "DriveName")); //TODO: put right values of logical library and drive name
93
    m_clientProxy.fetchVolumeId(m_volInfo, reqReport);
94
  } catch(client::ClientProxy::EndOfSessionWithError & eoswe) {
95
    std::stringstream fullError;
96
97
    fullError << "Received end of session with error from client when requesting Volume "
      << eoswe.getMessageValue();
98
    lc.log(LOG_ERR, fullError.str());
99
    m_clientProxy.reportEndOfSession(reqReport);
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
    log::ScopedParamContainer params(lc);
    params.add("tapebridgeTransId", reqReport.transactionId)
          .add("connectDuration", reqReport.connectDuration)
          .add("sendRecvDuration", reqReport.sendRecvDuration);
    lc.log(LOG_INFO, "Acknowledged client of end session with error");
    return MARK_DRIVE_AS_UP;    
  } catch(client::ClientProxy::EndOfSession & eos) {
    lc.log(LOG_INFO, "Received end of session from client when requesting Volume");
    m_clientProxy.reportEndOfSession(reqReport);
    log::ScopedParamContainer params(lc);
    params.add("tapebridgeTransId", reqReport.transactionId)
          .add("connectDuration", reqReport.connectDuration)
          .add("sendRecvDuration", reqReport.sendRecvDuration);
    lc.log(LOG_INFO, "Acknowledged client of end session");
    return MARK_DRIVE_AS_UP;  
115
  } catch (client::ClientProxy::UnexpectedResponse & unexp) {
116
117
    std::stringstream fullError;
    fullError << "Received unexpected response from client when requesting Volume"
118
      << unexp.getMessageValue();
Eric Cano's avatar
Eric Cano committed
119
    lc.log(LOG_ERR, fullError.str());
120
    m_clientProxy.reportEndOfSession(reqReport);
121
122
123
124
    log::LogContext::ScopedParam sp07(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp08(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp09(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
Eric Cano's avatar
Eric Cano committed
125
    lc.log(LOG_ERR, "Notified client of end session with error");
126
    return MARK_DRIVE_AS_UP;
127
128
129
130
131
132
133
134
135
136
  } catch (castor::exception::Exception & ex) {
    std::stringstream fullError;
    fullError << "When requesting Volume, "
      << ex.getMessageValue();
    lc.log(LOG_ERR, fullError.str());
    try {
      // Attempt to notify the client. This is so hopeless and likely to fail
      // that is does not deserve a log.
      m_clientProxy.reportEndOfSession(reqReport);
    } catch (...) {}
137
138
    log::LogContext::ScopedParam sp07(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
139
    lc.log(LOG_ERR, "Could not contact client for Volume (client notification was attempted).");
140
    return MARK_DRIVE_AS_UP;
Eric Cano's avatar
Eric Cano committed
141
  }
142
  // 2b) ... and log.
143
144
  // Make the DGN and TPVID parameter permanent.
  log::ScopedParamContainer params(lc);
145
  params.add("TPVID", m_volInfo.vid);
146
  {
147
148
149
150
151
152
    log::ScopedParamContainer localParams(lc);
    localParams.add("tapebridgeTransId", reqReport.transactionId)
               .add("connectDuration", reqReport.connectDuration)
               .add("sendRecvDuration", reqReport.sendRecvDuration)
               .add("density", m_volInfo.density)
               .add("label", m_volInfo.labelObsolete)
Steven Murray's avatar
Steven Murray committed
153
154
               .add("clientType", volumeClientTypeToString(m_volInfo.clientType))
               .add("mode", volumeModeToString(m_volInfo.volumeMode));
155
156
    lc.log(LOG_INFO, "Got volume from client");
  }
Eric Cano's avatar
Eric Cano committed
157
158
  
  // Depending on the type of session, branch into the right execution
159
160
  switch(m_volInfo.volumeMode) {
  case tapegateway::READ:
161
    return executeRead(lc);
162
  case tapegateway::WRITE:
163
    return executeWrite(lc);
164
165
  case tapegateway::DUMP:
    executeDump(lc);
166
    return MARK_DRIVE_AS_UP;
167
  default:
168
    return MARK_DRIVE_AS_UP;
169
170
  }
}
171
//------------------------------------------------------------------------------
172
//DataTransferSession::executeRead
173
//------------------------------------------------------------------------------
174
175
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
 castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogContext & lc) {
176
177
178
179
180
  // 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
181
  std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc));
182
  
183
  if(!drive.get()) return MARK_DRIVE_AS_DOWN;    
184
185
186
187
  // 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)
188
    RecallReportPacker rrp(m_clientProxy,
189
        m_castorConf.bulkRequestRecallMaxFiles,
190
        lc);
191

192
193
194
195
    // If we talk to a command line client, we do not batch report
    if (tapegateway::READ_TP == m_volInfo.clientType) {
      rrp.disableBulk();
    }
196
    RecallWatchDog rwd(15,60*10,m_intialProcess,m_driveConfig.getUnitName(),lc);
197
    
198
    RecallMemoryManager mm(m_castorConf.nbBufs, m_castorConf.bufsz,lc);
199
    TapeServerReporter tsr(m_intialProcess, m_driveConfig, 
200
            m_hostname, m_volInfo, lc);
201
202
    //we retrieved the detail from the client in execute, so at this point 
    //we can already report !
203
    tsr.gotReadMountDetailsFromClient();
204
    
205
    TapeReadSingleThread trst(*drive, m_mc, tsr, m_volInfo, 
206
        m_castorConf.bulkRequestRecallMaxFiles,m_capUtils,rwd,lc);
207

208
    DiskWriteThreadPool dwtp(m_castorConf.nbDiskThreads,
209
        rrp,
210
        rwd,
211
        lc,
212
        m_castorConf.remoteFileProtocol,
213
214
        m_castorConf.xrootPrivateKey,
        m_castorConf.moverHandlerPort);
215
    RecallTaskInjector rti(mm, trst, dwtp, m_clientProxy,
216
217
            m_castorConf.bulkRequestRecallMaxFiles,
            m_castorConf.bulkRequestRecallMaxBytes,lc);
218
219
220
221
    // 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
    rti.setClientType(m_volInfo.clientType);
222
    trst.setTaskInjector(&rti);
223
    rrp.setWatchdog(rwd);
224
225
226
    
    // 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)
227
    castor::utils::Timer timer;
228
    if (rti.synchronousInjection()) {
229
      // We got something to recall. Time to start the machinery
Eric Cano's avatar
WIP    
Eric Cano committed
230
      trst.setWaitForInstructionsTime(timer.secs());
231
      rwd.startThread();
232
233
234
235
      trst.startThreads();
      dwtp.startThreads();
      rrp.startThreads();
      rti.startThreads();
236
      tsr.startThreads();
237
238
239
240
241
242
243
244
      // 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();
      rrp.waitThread();
      dwtp.waitThreads();
      trst.waitThreads();
245
      tsr.waitThreads();
246
      rwd.stopAndWaitThread();
247
      return trst.getHardwareStatus();
248
249
250
251
    } else {
      // Just log this was an empty mount and that's it. The memory management
      // will be deallocated automatically.
      lc.log(LOG_ERR, "Aborting recall mount startup: empty mount");
252
253
      log::LogContext::ScopedParam sp1(lc, log::Param("errorMessage", "Aborted: empty recall mount"));
      log::LogContext::ScopedParam sp2(lc, log::Param("errorCode", SEINTERNAL));
254
255
256
      try {
        client::ClientProxy::RequestReport reqReport;
        m_clientProxy.reportEndOfSessionWithError("Aborted: empty recall mount", SEINTERNAL, reqReport);
257
258
259
260
261
        log::LogContext::ScopedParam sp08(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
        log::LogContext::ScopedParam sp09(lc, log::Param("connectDuration", reqReport.connectDuration));
        log::LogContext::ScopedParam sp10(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
        log::LogContext::ScopedParam sp11(lc, log::Param("errorMessage", "Aborted: empty recall mount"));
        log::LogContext::ScopedParam sp12(lc, log::Param("errorCode", SEINTERNAL));
262
263
        lc.log(LOG_ERR, "Notified client of end session with error");
      } catch(castor::exception::Exception & ex) {
264
        log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
265
266
        lc.log(LOG_ERR, "Failed to notified client of end session with error");
      }
267
268
      // Empty mount, hardware is OK
      return MARK_DRIVE_AS_UP;
269
270
271
    }
  }
}
272
//------------------------------------------------------------------------------
273
//DataTransferSession::executeWrite
274
//------------------------------------------------------------------------------
275
276
277
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(
  log::LogContext & lc) {
278
279
280
281
  // 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
282
  std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc));
283
  if (!drive.get()) return MARK_DRIVE_AS_UP;
284
285
  // Once we got hold of the drive, we can run the session
  {
286
    
287
    //dereferencing configLine is safe, because if configLine were not valid, 
288
    //then findDrive would have return NULL and we would have not end up there
289
    TapeServerReporter tsr(m_intialProcess, m_driveConfig, m_hostname,m_volInfo,lc);
290
    
291
292
    MigrationMemoryManager mm(m_castorConf.nbBufs,
        m_castorConf.bufsz,lc);
293
    MigrationReportPacker mrp(m_clientProxy, lc);
294
    MigrationWatchDog mwd(15,60*10,m_intialProcess,m_driveConfig.getUnitName(),lc);
295
    TapeWriteSingleThread twst(*drive.get(),
296
        m_mc,
297
        tsr,
298
        mwd,
299
        m_volInfo,
300
301
        lc,
        mrp,
302
        m_capUtils,    
303
        m_castorConf.maxFilesBeforeFlush,
304
        m_castorConf.maxBytesBeforeFlush);
305
306
307
    DiskReadThreadPool drtp(m_castorConf.nbDiskThreads,
        m_castorConf.bulkRequestMigrationMaxFiles,
        m_castorConf.bulkRequestMigrationMaxBytes,
308
        mwd,
309
        lc,
310
        m_castorConf.remoteFileProtocol,
311
312
        m_castorConf.xrootPrivateKey,
        m_castorConf.moverHandlerPort);
313
    MigrationTaskInjector mti(mm, drtp, twst, m_clientProxy, 
314
315
            m_castorConf.bulkRequestMigrationMaxFiles,
            m_castorConf.bulkRequestMigrationMaxBytes,lc);
316
    drtp.setTaskInjector(&mti);
317
    twst.setTaskInjector(&mti);
318
    mrp.setWatchdog(mwd);
319
    castor::utils::Timer timer;
320

321
    if (mti.synchronousInjection()) {
322
      const uint64_t firstFseqFromClient = mti.firstFseqToWrite();
323
324
      
      //the last fseq written on the tape is the first file's fseq minus one
325
      twst.setlastFseq(firstFseqFromClient-1);
326
      
327
      //we retrieved the detail from the client in execute, so at this point 
328
329
330
331
332
333
334
335
336
337
      //we can report. We get in exchange the number of files on the tape.
      // This function can throw an exception (usually for permission reasons)
      // This is not a reason to put the drive down. The error is already logged
      // upstream.
      // Letting the exception slip through would leave the drive down.
      // Initialise with something obviously wrong.
      uint64_t nbOfFileOnTape = std::numeric_limits<uint64_t>::max();
      try {
        nbOfFileOnTape = tsr.gotWriteMountDetailsFromClient();
      } catch (castor::exception::Exception & e) {
338
        log::LogContext::ScopedParam sp1(lc, log::Param("errorMessage", e.getMessage().str()));
339
340
341
342
343
344
345
346
        lc.log(LOG_INFO, "Aborting the session after problem with mount details. Notifying the client.");
        mrp.synchronousReportEndWithErrors(e.getMessageValue(), SEINTERNAL);
        return MARK_DRIVE_AS_UP;
      } catch (...) {
        lc.log(LOG_INFO, "Aborting the session after problem with mount details (unknown exception). Notifying the client.");
        mrp.synchronousReportEndWithErrors("Unknown exception while checking session parameters with VMGR", SEINTERNAL);
        return MARK_DRIVE_AS_UP;
      }
347
348

      //theses 2 numbers should match. Otherwise, it means the stager went mad 
349
350
351
      if(firstFseqFromClient != nbOfFileOnTape + 1) {
        lc.log(LOG_ERR, "First file to write's fseq  and number of files on "
        "the tape according to the VMGR dont match");
352
       //no mount at all, drive to be kept up = return 0
353
        return MARK_DRIVE_AS_UP;
354
      }
355
356
357
358
      // We have something to do: start the session by starting all the 
      // threads.
      mm.startThreads();
      drtp.startThreads();
359
      mwd.startThread();
Eric Cano's avatar
WIP    
Eric Cano committed
360
      twst.setWaitForInstructionsTime(timer.secs());
361
362
363
      twst.startThreads();
      mrp.startThreads();
      mti.startThreads();
364
      tsr.startThreads();
365
      
366
367
368
369
370
371
      // Synchronise with end of threads
      mti.waitThreads();
      mrp.waitThread();
      twst.waitThreads();
      drtp.waitThreads();
      mm.waitThreads();
372
      tsr.waitThreads();
373
      mwd.stopAndWaitThread();
374
375
      
      return twst.getHardwareStatus();
376
377
378
379
    } else {
      // Just log this was an empty mount and that's it. The memory management
      // will be deallocated automatically.
      lc.log(LOG_ERR, "Aborting migration mount startup: empty mount");
380
      log::LogContext::ScopedParam sp1(lc, log::Param("errorMessage", "Aborted: empty migration mount"));
381
      log::LogContext::ScopedParam sp2(lc, log::Param("errorCode", SEINTERNAL));
382
383
384
      try {
        client::ClientProxy::RequestReport reqReport;
        m_clientProxy.reportEndOfSessionWithError("Aborted: empty migration mount", SEINTERNAL, reqReport);
385
386
387
        log::LogContext::ScopedParam sp1(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
        log::LogContext::ScopedParam sp2(lc, log::Param("connectDuration", reqReport.connectDuration));
        log::LogContext::ScopedParam sp3(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
388
389
        lc.log(LOG_ERR, "Notified client of end session with error");
      } catch(castor::exception::Exception & ex) {
390
        log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
391
392
        lc.log(LOG_ERR, "Failed to notified client of end session with error");
      }
393
394
      // Empty mount, hardware safe
      return MARK_DRIVE_AS_UP;
395
    }
396
397
  }
}
398
//------------------------------------------------------------------------------
399
//DataTransferSession::executeDump
400
//------------------------------------------------------------------------------
401
void castor::tape::tapeserver::daemon::DataTransferSession::executeDump(log::LogContext & lc) {
402
403
404
  // We are ready to start the session. In case of read there is no interest in
  // creating the machinery before getting the tape mounted, so do it now.
  // 1) Get hold of the drive and check it.
405
406
  
}
407
408

//------------------------------------------------------------------------------
409
//DataTransferSession::findDrive
410
//------------------------------------------------------------------------------
411
412
413
414
415
416
417
418
/*
 * 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
 */
419
420
421
422
423
/**
 * Try to find the drive that is described by m_request.driveUnit and m_volInfo.density
 * @param lc For logging purpose
 * @return the drive if found, NULL otherwise
 */
424
castor::tape::tapeserver::drive::DriveInterface *
425
castor::tape::tapeserver::daemon::DataTransferSession::findDrive(const DriveConfig
426
  &driveConfig, log::LogContext& lc) {
427
  // Find the drive in the system's SCSI devices
428
  castor::tape::SCSI::DeviceVector dv(m_sysWrapper);
429
430
  castor::tape::SCSI::DeviceInfo driveInfo;
  try {
431
    driveInfo = dv.findBySymlink(driveConfig.getDevFilename());
432
433
  } catch (castor::tape::SCSI::DeviceVector::NotFound & e) {
    // We could not find this drive in the system's SCSI devices
434
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
435
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.getDevFilename()));
436
437
    lc.log(LOG_ERR, "Drive not found on this path");
    
438
    client::ClientProxy::RequestReport reqReport;
439
440
    std::stringstream errMsg;
    errMsg << "Drive not found on this path" << lc;
441
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
442
443
444
445
446
    log::LogContext::ScopedParam sp10(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp11(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp12(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp13(lc, log::Param("errorMessage", errMsg.str()));
    log::LogContext::ScopedParam sp14(lc, log::Param("errorCode", SEINTERNAL));
447
    lc.log(LOG_ERR, "Notified client of end session with error");
448
    return NULL;
449
450
  } catch (castor::exception::Exception & e) {
    // We could not find this drive in the system's SCSI devices
451
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
452
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.getDevFilename()));
453
    log::LogContext::ScopedParam sp10(lc, log::Param("errorMessage", e.getMessageValue()));
454
455
    lc.log(LOG_ERR, "Error looking to path to tape drive");
    
456
    client::ClientProxy::RequestReport reqReport;
457
458
    std::stringstream errMsg;
    errMsg << "Error looking to path to tape drive: " << lc;
459
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
460
461
462
463
464
    log::LogContext::ScopedParam sp11(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp12(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp13(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp14(lc, log::Param("errorMessage", errMsg.str()));
    log::LogContext::ScopedParam sp15(lc, log::Param("errorCode", SEINTERNAL));
465
    lc.log(LOG_ERR, "Notified client of end session with error");
466
    return NULL;
467
468
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
469
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
470
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.getDevFilename()));
471
472
    lc.log(LOG_ERR, "Unexpected exception while looking for drive");
    
473
    client::ClientProxy::RequestReport reqReport;
474
475
    std::stringstream errMsg;
    errMsg << "Unexpected exception while looking for drive" << lc;
476
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
477
478
479
480
481
    log::LogContext::ScopedParam sp10(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp11(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp12(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp13(lc, log::Param("errorMessage", errMsg.str()));
    log::LogContext::ScopedParam sp14(lc, log::Param("errorCode", SEINTERNAL));
482
    lc.log(LOG_ERR, "Notified client of end session with error");
483
    return NULL;
484
485
  }
  try {
486
    std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drive;
487
    drive.reset(castor::tape::tapeserver::drive::createDrive(driveInfo, m_sysWrapper));
488
    if (drive.get()) drive->config = driveConfig;
489
    return drive.release();
490
491
  } catch (castor::exception::Exception & e) {
    // We could not find this drive in the system's SCSI devices
492
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
493
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.getDevFilename()));
494
    log::LogContext::ScopedParam sp10(lc, log::Param("errorMessage", e.getMessageValue()));
495
496
    lc.log(LOG_ERR, "Error opening tape drive");
    
497
    client::ClientProxy::RequestReport reqReport;
498
499
    std::stringstream errMsg;
    errMsg << "Error opening tape drive" << lc;
500
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
501
502
503
504
505
    log::LogContext::ScopedParam sp11(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp12(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp13(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp14(lc, log::Param("errorMessage", errMsg.str()));
    log::LogContext::ScopedParam sp15(lc, log::Param("errorCode", SEINTERNAL));
506
    lc.log(LOG_ERR, "Notified client of end session with error");
507
    return NULL;
508
509
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
510
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
511
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.getDevFilename()));
512
513
    lc.log(LOG_ERR, "Unexpected exception while opening drive");
    
514
    client::ClientProxy::RequestReport reqReport;
515
516
    std::stringstream errMsg;
    errMsg << "Unexpected exception while opening drive" << lc;
517
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
518
519
520
521
522
    log::LogContext::ScopedParam sp10(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp11(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp12(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp13(lc, log::Param("errorMessage", errMsg.str()));
    log::LogContext::ScopedParam sp14(lc, log::Param("errorCode", SEINTERNAL));
523
    lc.log(LOG_ERR, "Notified client of end session with error");
524
    return NULL;
525
  }
Eric Cano's avatar
Eric Cano committed
526
}
527
528

//------------------------------------------------------------------------------
529
// destructor
530
//------------------------------------------------------------------------------
531
532
533
534
535
536
537
castor::tape::tapeserver::daemon::DataTransferSession::~DataTransferSession()
  throw () {
  try {
    google::protobuf::ShutdownProtobufLibrary();
  } catch(...) {
    m_log(LOG_ERR, "google::protobuf::ShutdownProtobufLibrary() threw an"
      " unexpected exception");
538
  }
539
}
Steven Murray's avatar
Steven Murray committed
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566

//-----------------------------------------------------------------------------
// volumeClientTypeToString
//-----------------------------------------------------------------------------
const char *castor::tape::tapeserver::daemon::DataTransferSession::
  volumeClientTypeToString(const tapegateway::ClientType mode) const throw() {
  switch(mode) {
  case tapegateway::TAPE_GATEWAY: return "TAPE_GATEWAY";
  case tapegateway::READ_TP     : return "READ_TP";
  case tapegateway::WRITE_TP    : return "WRITE_TP";
  case tapegateway::DUMP_TP     : return "DUMP_TP";
  default                       : return "UKNOWN";
  }
}   

//-----------------------------------------------------------------------------
// volumeModeToString
//-----------------------------------------------------------------------------
const char *castor::tape::tapeserver::daemon::DataTransferSession::
  volumeModeToString(const tapegateway::VolumeMode mode) const throw() {
  switch(mode) {
  case tapegateway::READ : return "READ";
  case tapegateway::WRITE: return "WRITE";
  case tapegateway::DUMP : return "DUMP";
  default                : return "UKNOWN";
  }
}