DataTransferSession.cpp 24.8 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
24
/******************************************************************************
 *
 * 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
 *****************************************************************************/

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

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
    const legacymsg::RtcpJobRqstMsgBody & clientRequest, 
54
55
    castor::log::Logger & log,
    System::virtualWrapper & sysWrapper,
56
    const utils::DriveConfig & driveConfig,
57
    castor::mediachanger::MediaChangerFacade & mc,
58
    castor::messages::TapeserverProxy & initialProcess,
59
    castor::server::ProcessCap & capUtils,
60
    const DataTransferConfig & castorConf): 
61
    m_request(clientRequest),
62
    m_log(log),
63
64
65
66
    m_clientProxy(clientRequest),
    m_sysWrapper(sysWrapper),
    m_driveConfig(driveConfig),
    m_castorConf(castorConf), 
67
    m_mc(mc),
68
    m_intialProcess(initialProcess),
69
    m_capUtils(capUtils) {
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
89
90
91
92
93
94
  lc.pushOrReplace(log::Param("thread", "mainThread"));
  log::LogContext::ScopedParam sp01(lc, log::Param("clientHost", m_request.clientHost));
  log::LogContext::ScopedParam sp02(lc, log::Param("clientPort", m_request.clientPort));
  log::LogContext::ScopedParam sp03(lc, log::Param("mountTransactionId", m_request.volReqId));
  log::LogContext::ScopedParam sp04(lc, log::Param("volReqId", m_request.volReqId));
  log::LogContext::ScopedParam sp05(lc, log::Param("driveUnit", m_request.driveUnit));
  log::LogContext::ScopedParam sp06(lc, log::Param("dgn", m_request.dgn));
95
  // 2a) Get initial information from the client
96
  client::ClientProxy::RequestReport reqReport;
Eric Cano's avatar
Eric Cano committed
97
  try {
98
    m_clientProxy.fetchVolumeId(m_volInfo, reqReport);
99
  } catch(client::ClientProxy::EndOfSession & eof) {
100
    std::stringstream fullError;
101
    fullError << "Received end of session rom client when requesting Volume "
102
      << eof.getMessageValue();
103
    lc.log(LOG_ERR, fullError.str());
104
    m_clientProxy.reportEndOfSession(reqReport);
105
106
107
108
    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()));
109
    lc.log(LOG_ERR, "Notified client of end session with error");
110
    return MARK_DRIVE_AS_UP;
111
  } catch (client::ClientProxy::UnexpectedResponse & unexp) {
112
113
    std::stringstream fullError;
    fullError << "Received unexpected response from client when requesting Volume"
114
      << unexp.getMessageValue();
Eric Cano's avatar
Eric Cano committed
115
    lc.log(LOG_ERR, fullError.str());
116
    m_clientProxy.reportEndOfSession(reqReport);
117
118
119
120
    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
121
    lc.log(LOG_ERR, "Notified client of end session with error");
122
    return MARK_DRIVE_AS_UP;
123
124
125
126
127
128
129
130
131
132
  } 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 (...) {}
133
134
    log::LogContext::ScopedParam sp07(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
135
    lc.log(LOG_ERR, "Could not contact client for Volume (client notification was attempted).");
136
    return MARK_DRIVE_AS_UP;
Eric Cano's avatar
Eric Cano committed
137
  }
138
  // 2b) ... and log.
Eric Cano's avatar
Eric Cano committed
139
  // Make the TPVID parameter permanent.
140
  log::LogContext::ScopedParam sp07(lc, log::Param("TPVID", m_request.dgn));
141
  {
142
143
144
145
146
147
148
149
    log::LogContext::ScopedParam sp08(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
    log::LogContext::ScopedParam sp09(lc, log::Param("connectDuration", reqReport.connectDuration));
    log::LogContext::ScopedParam sp00(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
    log::LogContext::ScopedParam sp11(lc, log::Param("TPVID", m_volInfo.vid));
    log::LogContext::ScopedParam sp12(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp13(lc, log::Param("label", m_volInfo.labelObsolete));
    log::LogContext::ScopedParam sp14(lc, log::Param("clientType", utils::volumeClientTypeToString(m_volInfo.clientType)));
    log::LogContext::ScopedParam sp15(lc, log::Param("mode", utils::volumeModeToString(m_volInfo.volumeMode)));
150
151
    lc.log(LOG_INFO, "Got volume from client");
  }
Eric Cano's avatar
Eric Cano committed
152
153
  
  // Depending on the type of session, branch into the right execution
154
155
  switch(m_volInfo.volumeMode) {
  case tapegateway::READ:
156
    return executeRead(lc);
157
  case tapegateway::WRITE:
158
    return executeWrite(lc);
159
160
  case tapegateway::DUMP:
    executeDump(lc);
161
    return MARK_DRIVE_AS_UP;
162
  default:
163
      return MARK_DRIVE_AS_UP;
164
165
  }
}
166
//------------------------------------------------------------------------------
167
//DataTransferSession::executeRead
168
//------------------------------------------------------------------------------
169
170
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
 castor::tape::tapeserver::daemon::DataTransferSession::executeRead(log::LogContext & lc) {
171
172
173
174
175
  // 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
176
  std::auto_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc));
177
  
178
  if(!drive.get()) return MARK_DRIVE_AS_DOWN;    
179
180
181
182
  // 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)
183
    RecallReportPacker rrp(m_clientProxy,
184
        m_castorConf.bulkRequestMigrationMaxFiles,
185
        lc);
186

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

203
    DiskWriteThreadPool dwtp(m_castorConf.nbDiskThreads,
204
        rrp,
205
        lc,
206
        m_castorConf.remoteFileProtocol,
207
        m_castorConf.xrootPrivateKey);
208
    RecallTaskInjector rti(mm, trst, dwtp, m_clientProxy,
209
210
            m_castorConf.bulkRequestRecallMaxFiles,
            m_castorConf.bulkRequestRecallMaxBytes,lc);
211
212
213
214
    trst.setTaskInjector(&rti);
    
    // 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)
Eric Cano's avatar
WIP    
Eric Cano committed
215
    utils::Timer timer;
216
    if (rti.synchronousInjection()) {
217
      // We got something to recall. Time to start the machinery
Eric Cano's avatar
WIP    
Eric Cano committed
218
      trst.setWaitForInstructionsTime(timer.secs());
219
      rwd.startThread();
220
221
222
223
      trst.startThreads();
      dwtp.startThreads();
      rrp.startThreads();
      rti.startThreads();
224
      tsr.startThreads();
225
226
227
228
229
230
231
232
      // 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();
233
      tsr.waitThreads();
234
      rwd.stopAndWaitThread();
235
      return trst.getHardwareStatus();
236
237
238
239
    } 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");
240
241
      log::LogContext::ScopedParam sp1(lc, log::Param("errorMessage", "Aborted: empty recall mount"));
      log::LogContext::ScopedParam sp2(lc, log::Param("errorCode", SEINTERNAL));
242
243
244
      try {
        client::ClientProxy::RequestReport reqReport;
        m_clientProxy.reportEndOfSessionWithError("Aborted: empty recall mount", SEINTERNAL, reqReport);
245
246
247
248
249
        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));
250
251
        lc.log(LOG_ERR, "Notified client of end session with error");
      } catch(castor::exception::Exception & ex) {
252
        log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
253
254
        lc.log(LOG_ERR, "Failed to notified client of end session with error");
      }
255
256
      // Empty mount, hardware is OK
      return MARK_DRIVE_AS_UP;
257
258
259
    }
  }
}
260
//------------------------------------------------------------------------------
261
//DataTransferSession::executeWrite
262
//------------------------------------------------------------------------------
263
264
265
castor::tape::tapeserver::daemon::Session::EndOfSessionAction
  castor::tape::tapeserver::daemon::DataTransferSession::executeWrite(
  log::LogContext & lc) {
266
267
268
269
  // 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
270
  std::auto_ptr<castor::tape::tapeserver::drive::DriveInterface> drive(findDrive(m_driveConfig,lc));
271
  if (!drive.get()) return MARK_DRIVE_AS_UP;
272
273
  // Once we got hold of the drive, we can run the session
  {
274
    
275
    //dereferencing configLine is safe, because if configLine were not valid, 
276
    //then findDrive would have return NULL and we would have not end up there
277
    TapeServerReporter tsr(m_intialProcess, m_driveConfig, m_hostname,m_volInfo,lc);
278
    
279
280
    MigrationMemoryManager mm(m_castorConf.nbBufs,
        m_castorConf.bufsz,lc);
281
282
    MigrationReportPacker mrp(m_clientProxy,
        lc);
283
    MigrationWatchDog mwd(2,60*10,m_intialProcess,m_driveConfig.unitName,lc);
284
    TapeWriteSingleThread twst(*drive.get(),
285
        m_mc,
286
        tsr,
287
        mwd,
288
        m_volInfo,
289
290
        lc,
        mrp,
291
        m_capUtils,    
292
293
294
295
296
        m_castorConf.maxFilesBeforeFlush,
        m_castorConf.maxBytesBeforeFlush/m_castorConf.bufsz);
    DiskReadThreadPool drtp(m_castorConf.nbDiskThreads,
        m_castorConf.bulkRequestMigrationMaxFiles,
        m_castorConf.bulkRequestMigrationMaxBytes,
297
        lc,
298
        m_castorConf.remoteFileProtocol,
299
        m_castorConf.xrootPrivateKey);
300
    MigrationTaskInjector mti(mm, drtp, twst, m_clientProxy, 
301
302
            m_castorConf.bulkRequestMigrationMaxBytes,
            m_castorConf.bulkRequestMigrationMaxFiles,lc);
303
    drtp.setTaskInjector(&mti);
Eric Cano's avatar
WIP    
Eric Cano committed
304
    utils::Timer timer;
305
    if (mti.synchronousInjection()) {
306
      const uint64_t firstFseqFromClient = mti.firstFseqToWrite();
307
308
      
      //the last fseq written on the tape is the first file's fseq minus one
309
      twst.setlastFseq(firstFseqFromClient-1);
310
      
311
312
      //we retrieved the detail from the client in execute, so at this point 
      //we can report. We get in exchange the number of files on the tape
313
      const uint64_t nbOfFileOnTape = tsr.gotWriteMountDetailsFromClient();
314
315

      //theses 2 numbers should match. Otherwise, it means the stager went mad 
316
317
318
      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");
319
       //no mount at all, drive to be kept up = return 0
320
        return MARK_DRIVE_AS_UP;
321
      }
322
323
324
325
      // We have something to do: start the session by starting all the 
      // threads.
      mm.startThreads();
      drtp.startThreads();
326
      mwd.startThread();
Eric Cano's avatar
WIP    
Eric Cano committed
327
      twst.setWaitForInstructionsTime(timer.secs());
328
329
330
      twst.startThreads();
      mrp.startThreads();
      mti.startThreads();
331
      tsr.startThreads();
332
      
333
334
335
336
      // Synchronise with end of threads
      mti.waitThreads();
      mrp.waitThread();
      twst.waitThreads();
337
      mwd.stopAndWaitThread();
338
339
      drtp.waitThreads();
      mm.waitThreads();
340
      tsr.waitThreads();
341
342
      
      return twst.getHardwareStatus();
343
344
345
346
    } 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");
347
348
      log::LogContext::ScopedParam sp1(lc, log::Param("errorMessage", "Aborted: empty recall mount"));
      log::LogContext::ScopedParam sp2(lc, log::Param("errorCode", SEINTERNAL));
349
350
351
      try {
        client::ClientProxy::RequestReport reqReport;
        m_clientProxy.reportEndOfSessionWithError("Aborted: empty migration mount", SEINTERNAL, reqReport);
352
353
354
        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));
355
356
        lc.log(LOG_ERR, "Notified client of end session with error");
      } catch(castor::exception::Exception & ex) {
357
        log::LogContext::ScopedParam sp1(lc, log::Param("notificationError", ex.getMessageValue()));
358
359
        lc.log(LOG_ERR, "Failed to notified client of end session with error");
      }
360
361
      // Empty mount, hardware safe
      return MARK_DRIVE_AS_UP;
362
    }
363
364
  }
}
365
//------------------------------------------------------------------------------
366
//DataTransferSession::executeDump
367
//------------------------------------------------------------------------------
368
void castor::tape::tapeserver::daemon::DataTransferSession::executeDump(log::LogContext & lc) {
369
370
371
  // 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.
372
373
  
}
374
375

//------------------------------------------------------------------------------
376
//DataTransferSession::findDrive
377
//------------------------------------------------------------------------------
378
379
380
381
382
383
384
385
/*
 * 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
 */
386
387
388
389
390
/**
 * 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
 */
391
castor::tape::tapeserver::drive::DriveInterface *
392
castor::tape::tapeserver::daemon::DataTransferSession::findDrive(const utils::DriveConfig
393
  &driveConfig, log::LogContext& lc) {
394
  // Find the drive in the system's SCSI devices
395
  castor::tape::SCSI::DeviceVector dv(m_sysWrapper);
396
397
  castor::tape::SCSI::DeviceInfo driveInfo;
  try {
398
    driveInfo = dv.findBySymlink(driveConfig.devFilename);
399
400
  } catch (castor::tape::SCSI::DeviceVector::NotFound & e) {
    // We could not find this drive in the system's SCSI devices
401
402
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.devFilename));
403
404
    lc.log(LOG_ERR, "Drive not found on this path");
    
405
    client::ClientProxy::RequestReport reqReport;
406
407
    std::stringstream errMsg;
    errMsg << "Drive not found on this path" << lc;
408
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
409
410
411
412
413
    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));
414
    lc.log(LOG_ERR, "Notified client of end session with error");
415
    return NULL;
416
417
  } catch (castor::exception::Exception & e) {
    // We could not find this drive in the system's SCSI devices
418
419
420
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.devFilename));
    log::LogContext::ScopedParam sp10(lc, log::Param("errorMessage", e.getMessageValue()));
421
422
    lc.log(LOG_ERR, "Error looking to path to tape drive");
    
423
    client::ClientProxy::RequestReport reqReport;
424
425
    std::stringstream errMsg;
    errMsg << "Error looking to path to tape drive: " << lc;
426
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
427
428
429
430
431
    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));
432
    lc.log(LOG_ERR, "Notified client of end session with error");
433
    return NULL;
434
435
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
436
437
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.devFilename));
438
439
    lc.log(LOG_ERR, "Unexpected exception while looking for drive");
    
440
    client::ClientProxy::RequestReport reqReport;
441
442
    std::stringstream errMsg;
    errMsg << "Unexpected exception while looking for drive" << lc;
443
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
444
445
446
447
448
    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));
449
    lc.log(LOG_ERR, "Notified client of end session with error");
450
    return NULL;
451
452
  }
  try {
453
    std::auto_ptr<castor::tape::tapeserver::drive::DriveInterface> drive;
454
    drive.reset(castor::tape::tapeserver::drive::createDrive(driveInfo, m_sysWrapper));
455
    if (drive.get()) drive->librarySlot = driveConfig.librarySlot;
456
    return drive.release();
457
458
  } catch (castor::exception::Exception & e) {
    // We could not find this drive in the system's SCSI devices
459
460
461
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.devFilename));
    log::LogContext::ScopedParam sp10(lc, log::Param("errorMessage", e.getMessageValue()));
462
463
    lc.log(LOG_ERR, "Error opening tape drive");
    
464
    client::ClientProxy::RequestReport reqReport;
465
466
    std::stringstream errMsg;
    errMsg << "Error opening tape drive" << lc;
467
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
468
469
470
471
472
    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));
473
    lc.log(LOG_ERR, "Notified client of end session with error");
474
    return NULL;
475
476
  } catch (...) {
    // We could not find this drive in the system's SCSI devices
477
478
    log::LogContext::ScopedParam sp08(lc, log::Param("density", m_volInfo.density));
    log::LogContext::ScopedParam sp09(lc, log::Param("devFilename", driveConfig.devFilename));
479
480
    lc.log(LOG_ERR, "Unexpected exception while opening drive");
    
481
    client::ClientProxy::RequestReport reqReport;
482
483
    std::stringstream errMsg;
    errMsg << "Unexpected exception while opening drive" << lc;
484
    m_clientProxy.reportEndOfSessionWithError("Drive unit not found", SEINTERNAL, reqReport);
485
486
487
488
489
    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));
490
    lc.log(LOG_ERR, "Notified client of end session with error");
491
    return NULL;
492
  }
Eric Cano's avatar
Eric Cano committed
493
}
494
495

//------------------------------------------------------------------------------
496
// destructor
497
//------------------------------------------------------------------------------
498
499
500
501
502
503
504
castor::tape::tapeserver::daemon::DataTransferSession::~DataTransferSession()
  throw () {
  try {
    google::protobuf::ShutdownProtobufLibrary();
  } catch(...) {
    m_log(LOG_ERR, "google::protobuf::ShutdownProtobufLibrary() threw an"
      " unexpected exception");
505
  }
506
}