CatalogueDrive.hpp 18.2 KB
Newer Older
Steven Murray's avatar
Steven Murray committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/******************************************************************************
 *
 * 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.
 *
 *
 *
21
 * @author Castor Dev team, castor-dev@cern.ch
Steven Murray's avatar
Steven Murray committed
22
23
24
25
 *****************************************************************************/

#pragma once

26
#include "castor/legacymsg/CupvProxy.hpp"
Steven Murray's avatar
Steven Murray committed
27
28
#include "castor/legacymsg/RtcpJobRqstMsgBody.hpp"
#include "castor/legacymsg/TapeLabelRqstMsgBody.hpp"
29
#include "castor/legacymsg/TapeStatDriveEntry.hpp"
30
#include "castor/legacymsg/VdqmProxy.hpp"
31
#include "castor/legacymsg/VmgrProxy.hpp"
32
#include "castor/log/Logger.hpp"
33
#include "castor/tape/tapeserver/daemon/CatalogueCleanerSession.hpp"
34
#include "castor/tape/tapeserver/daemon/CatalogueConfig.hpp"
35
#include "castor/tape/tapeserver/daemon/CatalogueDriveState.hpp"
36
37
38
#include "castor/tape/tapeserver/daemon/CatalogueLabelSession.hpp"
#include "castor/tape/tapeserver/daemon/CatalogueSession.hpp"
#include "castor/tape/tapeserver/daemon/CatalogueTransferSession.hpp"
39
#include "castor/tape/tapeserver/daemon/DriveConfig.hpp"
40
#include "castor/tape/tapeserver/daemon/ProcessForkerProxy.hpp"
41
#include "castor/tape/tapeserver/daemon/VdqmDriveSynchronizer.hpp"
42
#include "castor/tape/tapeserver/system/Wrapper.hpp"
Daniele Kruse's avatar
Daniele Kruse committed
43

44
45
#include <iostream>
#include <memory>
Steven Murray's avatar
Steven Murray committed
46
47
48
49
50
51
52
53
54
55
56
#include <string>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

namespace castor     {
namespace tape       {
namespace tapeserver {
namespace daemon     {

/**
57
 * A tape-drive entry in the tape-drive catalogue.
Steven Murray's avatar
Steven Murray committed
58
 */
59
class CatalogueDrive {
60
public:
Daniele Kruse's avatar
Daniele Kruse committed
61
  
62
63
64
65
66
  /**
   * Constructor that except for its parameters, initializes all strings to
   * the empty string, all integers to zero, all file descriptors to -1,
   * all lists to the emptylist, and the sessionType to SESSION_TYPE_NONE.
   *
67
68
   * @param netTimeout Timeout in seconds to be used when performing network
   * I/O.
69
70
   * @param log Object representing the API of the CASTOR logging system.
   * @param processForker Proxy object representing the ProcessForker.
71
   * @param cupv Proxy object representing the cupvd daemon.
72
   * @param vdqm Proxy object representing the vdqmd daemon.
73
   * @param vmgr Proxy object representing the vmgrd daemon.
74
75
   * @param hostName The name of the host on which the daemon is running.  This
   * name is needed to fill in messages to be sent to the vdqmd daemon.
76
77
   * @param config The configuration of the tape drive.
   * @param state The initial state of the tape drive.
78
79
   * @param catalogueConfig The CASTOR configuration parameters to be used by
   * the catalogue.
80
   * @param sysWrapper Object representing the operating system.
81
   */
82
  CatalogueDrive(
83
    const int netTimeout,
84
85
    log::Logger &log,
    ProcessForkerProxy &processForker,
86
    legacymsg::CupvProxy &cupv,
87
    legacymsg::VdqmProxy &vdqm,
88
    legacymsg::VmgrProxy &vmgr,
89
    const std::string &hostName,
90
    const DriveConfig &config,
91
    const CatalogueDriveState state,
92
93
    const CatalogueConfig &catalogueConfig,
    System::virtualWrapper &sysWrapper) throw();
94

95
96
97
  /**
   * Destructor
   */
98
  ~CatalogueDrive() throw();
99

100
  /**
101
102
   * Handles a tick in time.  Time driven actions such as alarms should be
   * implemented here.
103
104
105
   *
   * This method does not have to be called at any time precise interval,
   * though it should be called at least twice as fast as the quickest reaction
106
107
108
   * time imposed on the catalogue.
   *
   * @return True if the main event loop should continue, else false.
109
   */
110
  bool handleTick();
111

112
113
114
115
116
117
118
  /**
   * If there is a catalogue session associated with the tape drive then this
   * method deletes it and sets the member variable pointing to it to NULL in
   * order to prevent double deletions.
   */
  void deleteSession();

119
120
121
122
123
  /**
   * Gets the configuration of the tape-drive.
   *
   * @return The configuration of the tape-drive.
   */
124
  const DriveConfig &getConfig() const;
125
126
127
128
129
130

  /**
   * Gets the current state of the tape drive.
   *
   * @return The current state of the tape drive.
   */
131
  CatalogueDriveState getState() const throw();
Daniele Kruse's avatar
Daniele Kruse committed
132
  
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  /**
   * Configures the tape-drive up.
   *
   * This method throws an exception if the current state of the tape drive is
   * not DRIVE_STATE_UP, DRIVE_STATE_DOWN or DRIVE_STATE_WAITDOWN.
   *
   * configureUp() is idempotent.
   */
  void configureUp();

  /**
   * Configures the tape drive down.
   *
   * This method throws an exception if the current state of the tape drive is
   * not DRIVE_STATE_UP, DRIVE_STATE_DOWN or DRIVE_STATE_RUNNING.
   *
   * configureDown() is idempotent.
   */
  void configureDown();

  /**
154
155
   * Moves the state of tape drive to DRIVE_STATE_SESSIONRUNNING and sets the 
   * current session type to SESSION_TYPE_DATATRANSFER.
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
   *
   * This method throws an exception if the current state of the tape drive is
   * not DRIVE_STATE_UP. 
   *    
   * The unit name of a tape drive is unique for a given host.  No two drives
   * on the same host can have the same unit name.
   *
   * A tape drive cannot be a member of more than one device group name (DGN).
   *
   * This method throws an exception if the DGN field of the specified vdqm job
   * does not match the value that was entered into the catalogue with the
   * populateCatalogue() method.
   *  
   * @param job The job received from the vdqmd daemon.
   */   
  void receivedVdqmJob(const legacymsg::RtcpJobRqstMsgBody &job);
      
  /**
174
175
   * Moves the state of tape drive to DRIVE_STATE_SESSIONRUNNING and sets the 
   * current session type to SESSION_TYPE_LABEL.
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
   *
   * This method throws an exception if the current state of the tape drive is
   * not DRIVE_STATE_UP.
   *
   * The unit name of a tape drive is unique for a given host.  No two drives
   * on the same host can have the same unit name.
   *
   * A tape drive cannot be a member of more than one device group name (DGN).
   *
   * This method throws an exception if the DGN field of the specified vdqm job
   * does not match the value that was entered into the catalogue with the
   * populateCatalogue() method.
   *
   * PLEASE NOTE: If this method throws an exception then it does NOT close
   * the file descriptor of the TCP/IP connection with the tape labeling
   * command-line tool castor-tape-label.  The caller of this method is left
   * to close the connection because this gives them the opportunity to send
193
   * an appropriate error message to the client.
194
195
196
197
198
199
200
   *
   * @param job The label job.
   * @param labelCmdConnection The file descriptor of the TCP/IP connection
   * with the tape labeling command-line tool castor-tape-label.
   */
  void receivedLabelJob(const legacymsg::TapeLabelRqstMsgBody &job,
    const int labelCmdConnection);
201
202
  
  /**
203
   * Informs catalogue drive that the current tape session has succeeded.
204
205
206
207
   */
  void sessionSucceeded(); 
      
  /**
208
209
   * Informs catalogue drive that the current tape session completed in a failed
   * state (tape not unloaded, usually) and the drive should be marked as down.
210
   */
211
  void sessionFailedAndRequestedDriveDown();
212
213
214
215
216
217
  
  /**
   * Informs catalogue drive that the current tape session was killed (either 
   * due to a hang, of for other reason, like a dissatisfied operator.)
   */
  void sessionKilled(uint32_t signal);
218

219
220
221
222
  /**
   * Informs catalogue drive that the current tape session has failed and that
   * it has requested a CleanerSession.
   */
223
  void sessionFailedAndRequestedCleaner();
224

225
226
227
228
229
230
231
  /**
   * Gets the tpstat representation of the tape drive.
   *
   * @return The tpstat representation of the tape drive.
   */
  legacymsg::TapeStatDriveEntry getTapeStatDriveEntry() const;

232
233
234
235
236
237
  /** 
   * Returns the catalogue cleaner-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * cleaner session associated with the tape drive.
   */
238
  const CatalogueCleanerSession &getCleanerSession() const;
239
240
241
242
243
244
245
    
  /**
   * Returns the catalogue cleaner-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * cleaner session associated with the tape drive.
   */ 
246
  CatalogueCleanerSession &getCleanerSession();
247
248
249
250
251
252
253

  /**
   * Returns the catalogue label-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * label session associated with the tape drive.
   */
254
  const CatalogueLabelSession &getLabelSession() const;
255
256
257
258
259
260
261

  /**
   * Returns the catalogue label-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * label session associated with the tape drive.
   */
262
  CatalogueLabelSession &getLabelSession();
263
264
265
266
267
268
269

  /**
   * Returns the catalogue transfer-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * transfer session associated with the tape drive.
   */
270
  const CatalogueTransferSession &getTransferSession() const;
271
272
273
274
275
276
277

  /**
   * Returns the catalogue transfer-session associated with the tape drive.
   *
   * This method throws a castor::exception::Exception if there is no
   * transfer session associated with the tape drive.
   */
278
  CatalogueTransferSession &getTransferSession();
279

280
281
282
283
284
285
286
287
288
289
290
291
  /**
   * Gets the session asscoiated with the tape drive.
   *
   * This method throws castor::exception::Exception if there is no session
   * currently associated with the tape drive.
   *
   * Please use either getCleanerSession(), getLabelSession() or
   * getTransferSession() instead of this method if a specific type of session
   * is required.
   * 
   * @return The session associated with the tape drive.
   */
292
  const CatalogueSession &getSession() const;
293

294
295
296
297
298
299
300
301
  /**
   * Tries to determine the assigment time associated with the tap[e drive.
   *
   * @return The assigment time associated with the tape drive or 0 if not
   * known.  The assignment time is given in seconds elapsed since the Epoch.
   */
  time_t getAssignmentTimeForCleaner() const throw();

302
303
304
305
306
307
  /**
   * If there is a running session that is not a cleaner session then this
   * method kills the session and runs a cleaner session.
   */
  void shutdown();

308
309
310
311
312
313
314
315
  /**
   * If there is a running session then this method kills it and sets the drive
   * down in the vdqm and the drive catalogue.
   *
   * If there is no running session then this method does nothing.
   */
  void killSession();

316
317
private:

Daniele Kruse's avatar
Daniele Kruse committed
318
  /**
319
   * Copy constructor declared private to prevent copies.
Daniele Kruse's avatar
Daniele Kruse committed
320
   */
321
  CatalogueDrive(const CatalogueDrive&);
Daniele Kruse's avatar
Daniele Kruse committed
322

323
  /**
324
   * Assignment operator declared private to prevent assignments.
325
   */
326
  CatalogueDrive& operator=(const CatalogueDrive&);
327

328
329
330
331
332
333
334
335
336
337
  /**
   * Transition from DRIVE_STATE_DOWN to DRIVE_STATE_UP.
   */
  void transitionFromDownToUp();

  /**
   * Throws an exception if the physical tape drive is not empty.
   */
  void checkDriveIsEmpty();

338
339
340
341
342
  /**
   * Timeout in seconds to be used when performing network I/O.
   */
  const int m_netTimeout;

Steven Murray's avatar
Steven Murray committed
343
  /**
344
   * The object representing the API of the CASTOR logging system.
Steven Murray's avatar
Steven Murray committed
345
   */
346
347
  log::Logger &m_log;

Steven Murray's avatar
Steven Murray committed
348
  /**
349
   * Proxy object representing the ProcessForker.
Steven Murray's avatar
Steven Murray committed
350
   */
351
352
  ProcessForkerProxy &m_processForker;

353
354
355
356
357
  /**
   * Proxy object reprsenting the cupvd daemon.
   */
  legacymsg::CupvProxy &m_cupv;

Steven Murray's avatar
Steven Murray committed
358
  /**
359
   * Proxy object representing the vdqmd daemon.
Steven Murray's avatar
Steven Murray committed
360
   */
361
362
  legacymsg::VdqmProxy &m_vdqm;

363
364
365
366
367
  /**
   * Proxy object representing the vmgrd daemon.
   */
  legacymsg::VmgrProxy &m_vmgr;

368
369
370
371
372
373
  /**
   * The name of the host on which the daemon is running.  This name is
   * needed to fill in messages to be sent to the vdqmd daemon.
   */   
  const std::string m_hostName;

Steven Murray's avatar
Steven Murray committed
374
  /**
375
376
   * The configuration of the tape-drive.
   */
377
  DriveConfig m_config;
378

379
380
381
382
383
  /**
   * Object representing the operating system.
   */
  System::virtualWrapper &m_sysWrapper;

Steven Murray's avatar
Steven Murray committed
384
385
386
  /**
   * The current state of the tape drive.
   */
387
  CatalogueDriveState m_state;
388
389
390
391
392

  /**
   * The maximum time in seconds that the data-transfer session can take to get
   * the transfer job from the client.
   */
393
  const time_t m_waitJobTimeoutSecs;
394
395
396
397
398

  /**
   * The maximum time in seconds that the data-transfer session can take to
   * mount a tape.
   */
399
  const time_t m_mountTimeoutSecs;
400
401
402
403
404

  /**
   * The maximum time in seconds that the data-transfer session can cease to
   * move data blocks.
   */
405
  const time_t m_blockMoveTimeoutSecs;
Steven Murray's avatar
Steven Murray committed
406
  
Daniele Kruse's avatar
Daniele Kruse committed
407
408
409
  /**
   * The session metadata associated to the drive catalogue entry
   */
410
  CatalogueSession *m_session;
411

412
  /**
413
414
   * Object responsible for sychronizing the vdqmd daemon with the state of
   * this catalogue tape-drive.
415
   */
416
  VdqmDriveSynchronizer m_vdqmDriveSynchronizer;
417

418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  /**
   * Checks that there is a tape session currently associated with the
   * tape drive.
   *
   * This method throws castor::exception::Exception if there is no
   * tape session associated with the tape drive.
   */
  void checkForSession() const;

  /**
   * Checks that there is a cleaner session currently associated with the
   * tape drive.
   *
   * This method throws castor::exception::Exception if there is no
   * cleaner session associated with the tape drive.
   */
  void checkForCleanerSession() const;

  /**
   * Checks that there is a label session currently associated with the
   * tape drive.
   *
   * This method throws castor::exception::Exception if there is no
   * label session associated with the tape drive.
   */
  void checkForLabelSession() const;

  /**
   * Checks that there is a transfer session currently associated with the
   * tape drive.
   *
   * This method throws castor::exception::Exception if there is no
   * transfer session associated with the tape drive.
Daniele Kruse's avatar
Daniele Kruse committed
451
   */
452
  void checkForTransferSession() const;
Steven Murray's avatar
Steven Murray committed
453
454

  /**
455
456
   * Returns the value of the uid field of a TapeStatDriveEntry to be used
   * in a TapeStatReplyMsgBody.
Steven Murray's avatar
Steven Murray committed
457
   */
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  uint32_t getUidForTapeStatDriveEntry() const throw();

  /**
   * Returns the value of the jid field of a TapeStatDriveEntry to be used
   * in a TapeStatReplyMsgBody.
   */
  uint32_t getJidForTapeStatDriveEntry() const throw();

  /**
   * Returns the value of the up field of a TapeStatDriveEntry to be used
   * in a TapeStatReplyMsgBody.
   */
  uint16_t getUpForTapeStatDriveEntry() const throw();

  /**
   * Returns the value of the asn field of a TapeStatDriveEntry to be used
   * in a TapeStatReplyMsgBody.
   */
  uint16_t getAsnForTapeStatDriveEntry() const throw();

  /**
479
480
   * Determines the value of the asnTime field of a TapeStatDriveEntry to be
   * used in a TapeStatReplyMsgBody.
481
482
483
484
   */
  uint32_t getAsnTimeForTapeStatDriveEntry() const throw();

  /**
485
   * Determines the value of the mode field of a TapeStatDriveEntry to be used
486
   * in a TapeStatReplyMsgBody.
487
488
   *
   * @return The value of the mode field if known else WRITE_DISABLE.
489
490
491
492
   */
  uint16_t getModeForTapeStatDriveEntry() const throw();

  /**
493
494
495
496
497
   * Determines the value of the lblCode field of a TapeStatDriveEntry to be
   * used in a TapeStatReplyMsgBody.
   *
   * @return Always "aul" because this is the only tape format supported by
   * CASTOR.
498
499
500
501
   */
  std::string getLblCodeForTapeStatDriveEntry() const throw();

  /**
502
   * Determines the value of the tobeMounted field of a TapeStatDriveEntry to be
503
   * used in a TapeStatReplyMsgBody.
504
505
   *
   * @return The value of the tobeMounted filed if known, else 0.
506
507
508
509
   */
  uint16_t getToBeMountedForTapeStatDriveEntry() const throw();

  /**
510
   * Determines the value of the vid field of a TapeStatDriveEntry to be used
511
   * in a TapeStatReplyMsgBody.
512
513
   *
   * @return The volume indenfier if known else the empty string.
514
515
516
517
518
519
520
521
   */
  std::string getVidForTapeStatDriveEntry() const throw();

  /**
   * Returns the value of the vsn field of a TapeStatDriveEntry to be used
   * in a TapeStatReplyMsgBody.
   */
  std::string getVsnForTapeStatDriveEntry() const throw();
Steven Murray's avatar
Steven Murray committed
522

523
524
525
526
527
  /**
   * Helper method for logging and changing the state of the catalogue drive.
   *
   * @param newState The state to which the catalogue drive should be changed.
   */
528
  void changeState(const CatalogueDriveState newState) throw();
529

530
531
  /**
   * Called when a running session (DRIVE_STATE_RUNNING or DRIVE_STATE_WAITDOWN)
532
533
   * has competed with an error return value and the drive should be marked as
   * down.
534
   */
535
  void runningSessionFailedAndRequestedDriveDown();
536
537
538
539
540
541
  
  /**
   * Called when a running session (DRIVE_STATE_RUNNING or DRIVE_STATE_WAITDOWN)
   * has been killed.
   */
  void runningSessionKilled(uint32_t signal);
542
543
544
545
546
547
548
549
550
551
552
553

  /**
   * Called when a running session has been intentionally killed by the shutdown
   * sequence.
   */
  void sessionKilledByShutdown();

  /**
   * Called when a CLeanerSession of the shutdown sequence has failed.
   */
  void cleanerOfShutdownFailed();

554
555
556
557
558
559
560
561
562
563
564
565
566
567
  /**
   * Called when a running session (DRIVE_STATE_RUNNING or DRIVE_STATE_WAITDOWN)
   * has failed and has requested a CleanerSession.
   */
  void runningSessionFailedAndRequestedCleaner();

  /**
   * Creates a cleaner session to eject any tape left in the tape drive.
   *
   * @param vid The volume identifier of the tape currently in the tape drive
   * or the empty string if not know.
   * @param The assignment time associated with the tape drive or 0 if not
   * known.  The assignment time is given as the number of seconds elapsed
   * since the Epoch.
568
569
570
571
   * @param waitMediaInDrive true if we want to check the presence of the media in the drive before cleaning,
   * false otherwise.
   * @param waitMediaInDriveTimeout The maximum number of seconds to wait for
   * the media to be ready for operations inside the drive.
572
573
574
   * @return The catalogue cleaner-session.
   */
  CatalogueCleanerSession *createCleaner(const std::string &vid,
575
576
    const time_t assignmentTime, const bool waitMediaInDrive,
    const uint32_t waitMediaInDriveTimeout) const;
577

578
}; // class CatalogueDrive
Steven Murray's avatar
Steven Murray committed
579
580
581
582
583

} // namespace daemon
} // namespace tapeserver
} // namespace tape
} // namespace castor