From e49e26b759653ab80539ee17ffc4e9b532894b13 Mon Sep 17 00:00:00 2001
From: Eric Cano <Eric.Cano@cern.ch>
Date: Thu, 14 Sep 2017 09:41:41 +0200
Subject: [PATCH] Added new states for the drive: Probing and Shutdown.

The probe state is also used. It represents the time when the drive is being checked
for tapes during the down to up transition.

Shutdown is not in use yet as it requires changing the behaviour of the system (clean shutdowns).
---
 common/dataStructures/DriveState.cpp          |  6 ++
 common/dataStructures/DriveState.hpp          |  2 +
 common/dataStructures/DriveStatus.cpp         |  4 +
 common/dataStructures/DriveStatus.hpp         |  2 +
 objectstore/DriveRegister.cpp                 |  6 ++
 objectstore/cta.proto                         |  2 +
 scheduler/OStoreDB/OStoreDB.cpp               | 90 +++++++++++++++++++
 scheduler/OStoreDB/OStoreDB.hpp               |  5 ++
 .../tapeserver/daemon/DataTransferSession.cpp |  1 +
 xroot_plugins/XrdCtaFile.cpp                  |  4 +
 10 files changed, 122 insertions(+)

diff --git a/common/dataStructures/DriveState.cpp b/common/dataStructures/DriveState.cpp
index e9d013bc5e..73d83e0099 100644
--- a/common/dataStructures/DriveState.cpp
+++ b/common/dataStructures/DriveState.cpp
@@ -39,9 +39,11 @@ DriveState::DriveState():
   unmountStartTime(0),
   drainingStartTime(0),
   downOrUpStartTime(0),
+  probeStartTime(0),
   cleanupStartTime(0),
   lastUpdateTime(0),
   startStartTime(0),
+  shutdownTime(0),
   mountType(dataStructures::MountType::NoMount),
   driveStatus(dataStructures::DriveStatus::Down),
   desiredDriveState({false, false}),
@@ -65,9 +67,11 @@ bool DriveState::operator==(const DriveState &rhs) const {
       && unmountStartTime==rhs.unmountStartTime
       && drainingStartTime==rhs.drainingStartTime
       && downOrUpStartTime==rhs.downOrUpStartTime
+      && probeStartTime==rhs.probeStartTime
       && cleanupStartTime==rhs.cleanupStartTime
       && lastUpdateTime==rhs.lastUpdateTime
       && startStartTime==rhs.startStartTime
+      && shutdownTime==rhs.shutdownTime
       && mountType==rhs.mountType
       && driveStatus==rhs.driveStatus
       && desiredDriveState==rhs.desiredDriveState
@@ -104,9 +108,11 @@ std::ostream &operator<<(std::ostream &os, const DriveState &obj) {
      << " unmountStartTime="  << obj.unmountStartTime
      << " drainingStartTime="  << obj.drainingStartTime
      << " downOrUpStartTime="  << obj.downOrUpStartTime
+     << " probeStartTime=" << obj.probeStartTime
      << " cleanupStartTime="  << obj.cleanupStartTime
      << " lastUpdateTime="  << obj.lastUpdateTime
      << " startStartTime="  << obj.startStartTime
+     << " shutdownTime=" << obj.shutdownTime
      << " mountType=" << obj.mountType
      << " status=" << obj.driveStatus
      << " desiredState=" << obj.desiredDriveState
diff --git a/common/dataStructures/DriveState.hpp b/common/dataStructures/DriveState.hpp
index c320473f7b..b4568c450f 100644
--- a/common/dataStructures/DriveState.hpp
+++ b/common/dataStructures/DriveState.hpp
@@ -55,9 +55,11 @@ struct DriveState {
   time_t unmountStartTime;
   time_t drainingStartTime;
   time_t downOrUpStartTime;
+  time_t probeStartTime;
   time_t cleanupStartTime;
   time_t lastUpdateTime;
   time_t startStartTime;
+  time_t shutdownTime;
   MountType mountType;
   DriveStatus driveStatus;
   DesiredDriveState desiredDriveState;
diff --git a/common/dataStructures/DriveStatus.cpp b/common/dataStructures/DriveStatus.cpp
index c28f5465b9..6d0eac20e6 100644
--- a/common/dataStructures/DriveStatus.cpp
+++ b/common/dataStructures/DriveStatus.cpp
@@ -26,6 +26,8 @@ std::string cta::common::dataStructures::toString(cta::common::dataStructures::D
       return "Down";
     case cta::common::dataStructures::DriveStatus::Up:
       return "Free";
+    case cta::common::dataStructures::DriveStatus::Probing:
+      return "Probe";
     case cta::common::dataStructures::DriveStatus::Starting:
       return "Start";
     case cta::common::dataStructures::DriveStatus::Mounting:
@@ -40,6 +42,8 @@ std::string cta::common::dataStructures::toString(cta::common::dataStructures::D
       return "DrainToDisk";
     case cta::common::dataStructures::DriveStatus::CleaningUp:
       return "CleanUp";
+    case cta::common::dataStructures::DriveStatus::Shutdown:
+      return "Shutdown";
     case cta::common::dataStructures::DriveStatus::Unknown:
       return "Unknown";
     default:
diff --git a/common/dataStructures/DriveStatus.hpp b/common/dataStructures/DriveStatus.hpp
index db213046a3..d77af306d0 100644
--- a/common/dataStructures/DriveStatus.hpp
+++ b/common/dataStructures/DriveStatus.hpp
@@ -26,6 +26,7 @@ namespace dataStructures {
 enum DriveStatus {
   Down,
   Up,
+  Probing,
   Starting,
   Mounting,
   Transferring,
@@ -33,6 +34,7 @@ enum DriveStatus {
   Unmounting,
   DrainingToDisk,
   CleaningUp,
+  Shutdown,
   Unknown
 };
 
diff --git a/objectstore/DriveRegister.cpp b/objectstore/DriveRegister.cpp
index 9816f51ece..9d086f6e77 100644
--- a/objectstore/DriveRegister.cpp
+++ b/objectstore/DriveRegister.cpp
@@ -124,9 +124,11 @@ std::list<cta::common::dataStructures::DriveState> DriveRegister::getAllDrivesSt
     ret.back().unmountStartTime            = d.unmountstarttime();
     ret.back().drainingStartTime           = d.drainingstarttime();
     ret.back().downOrUpStartTime           = d.downorupstarttime();
+    ret.back().probeStartTime              = d.probestarttime();
     ret.back().cleanupStartTime            = d.cleanupstarttime();
     ret.back().lastUpdateTime              = d.lastupdatetime();
     ret.back().startStartTime              = d.startstarttime();
+    ret.back().shutdownTime                = d.shutdowntime();
     ret.back().mountType                   = (common::dataStructures::MountType) d.mounttype();
     ret.back().driveStatus                 = (common::dataStructures::DriveStatus) d.drivestatus();
     ret.back().desiredDriveState.up        = d.desiredup();
@@ -164,9 +166,11 @@ cta::common::dataStructures::DriveState DriveRegister::getDriveState(const std::
       ret.unmountStartTime            = d.unmountstarttime();
       ret.drainingStartTime           = d.drainingstarttime();
       ret.downOrUpStartTime           = d.downorupstarttime();
+      ret.probeStartTime              = d.probestarttime();
       ret.cleanupStartTime            = d.cleanupstarttime();
       ret.lastUpdateTime              = d.lastupdatetime();
       ret.startStartTime              = d.startstarttime();
+      ret.shutdownTime                = d.shutdowntime();
       ret.mountType                   = (common::dataStructures::MountType) d.mounttype();
       ret.driveStatus                 = (common::dataStructures::DriveStatus) d.drivestatus();
       ret.desiredDriveState.up        = d.desiredup();
@@ -210,9 +214,11 @@ update:
   ds->set_unmountstarttime(driveState.unmountStartTime);
   ds->set_drainingstarttime(driveState.drainingStartTime);
   ds->set_downorupstarttime(driveState.downOrUpStartTime);
+  ds->set_probestarttime(driveState.probeStartTime);
   ds->set_cleanupstarttime(driveState.cleanupStartTime);
   ds->set_lastupdatetime(driveState.lastUpdateTime);
   ds->set_startstarttime(driveState.startStartTime);
+  ds->set_shutdowntime(driveState.shutdownTime);
   ds->set_mounttype((uint32_t)driveState.mountType);
   ds->set_drivestatus((uint32_t)driveState.driveStatus);
   ds->set_desiredup(driveState.desiredDriveState.up);
diff --git a/objectstore/cta.proto b/objectstore/cta.proto
index ea8d21ee50..5f320f729f 100644
--- a/objectstore/cta.proto
+++ b/objectstore/cta.proto
@@ -266,9 +266,11 @@ message DriveState {
   optional uint64 unmountstarttime = 5011;
   optional uint64 drainingstarttime = 5012;
   optional uint64 downorupstarttime = 5013;
+  optional uint64 probestarttime = 5026;
   optional uint64 cleanupstarttime = 5014;
   optional uint64 lastupdatetime = 5015;
   optional uint64 startstarttime = 5016;
+  optional uint64 shutdowntime = 5027;
   required uint32 mounttype = 5017;
   required uint32 drivestatus = 5018;
   required bool desiredUp = 5019;
diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp
index a49cec8c12..b40b45a5e4 100644
--- a/scheduler/OStoreDB/OStoreDB.cpp
+++ b/scheduler/OStoreDB/OStoreDB.cpp
@@ -1116,9 +1116,11 @@ void OStoreDB::updateDriveStatusInRegitry(objectstore::DriveRegister& dr,
     driveState.unmountStartTime = 0;
     driveState.drainingStartTime = 0;
     driveState.downOrUpStartTime = 0;
+    driveState.probeStartTime = 0;
     driveState.cleanupStartTime = 0;
     driveState.lastUpdateTime = 0;
     driveState.startStartTime = 0;
+    driveState.shutdownTime=0;
     driveState.desiredDriveState.up = (inputs.status==DriveStatus::Down?false:true);
     driveState.desiredDriveState.forceDown = false;
     driveState.currentTapePool = "";
@@ -1135,6 +1137,9 @@ void OStoreDB::updateDriveStatusInRegitry(objectstore::DriveRegister& dr,
     case DriveStatus::Up:
       setDriveUpOrMaybeDown(driveState, inputs);
       break;
+    case DriveStatus::Probing:
+      setDriveProbing(driveState, inputs);
+      break;
     case DriveStatus::Starting:
       setDriveStarting(driveState, inputs);
       break;
@@ -1156,6 +1161,9 @@ void OStoreDB::updateDriveStatusInRegitry(objectstore::DriveRegister& dr,
     case DriveStatus::CleaningUp:
       setDriveCleaningUp(driveState, inputs);
       break;
+    case DriveStatus::Shutdown:
+      setDriveShutdown(driveState, inputs);
+      break;
     default:
       throw exception::Exception("Unexpected status in DriveRegister::reportDriveStatus");
   }
@@ -1219,7 +1227,9 @@ void OStoreDB::setDriveDown(common::dataStructures::DriveState & driveState,
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=inputs.reportTime;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=common::dataStructures::MountType::NoMount;
   driveState.driveStatus=common::dataStructures::DriveStatus::Down;
@@ -1257,7 +1267,9 @@ void OStoreDB::setDriveUpOrMaybeDown(common::dataStructures::DriveState & driveS
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=inputs.reportTime;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=common::dataStructures::MountType::NoMount;
   driveState.driveStatus=targetStatus;
@@ -1265,6 +1277,39 @@ void OStoreDB::setDriveUpOrMaybeDown(common::dataStructures::DriveState & driveS
   driveState.currentTapePool="";
 }
 
+//------------------------------------------------------------------------------
+// OStoreDB::setDriveUp()
+//------------------------------------------------------------------------------
+void OStoreDB::setDriveProbing(common::dataStructures::DriveState & driveState,
+  const ReportDriveStatusInputs & inputs) {
+  using common::dataStructures::DriveStatus;
+  // If we were already up (or down), then we only update the last update time.
+  if (driveState.driveStatus == inputs.status) {
+    driveState.lastUpdateTime=inputs.reportTime;
+    return;
+  }
+  // If we are changing state, then all should be reset.
+  driveState.sessionId=0;
+  driveState.bytesTransferredInSession=0;
+  driveState.filesTransferredInSession=0;
+  driveState.latestBandwidth=0;
+  driveState.sessionStartTime=0;
+  driveState.mountStartTime=0;
+  driveState.transferStartTime=0;
+  driveState.unloadStartTime=0;
+  driveState.unmountStartTime=0;
+  driveState.drainingStartTime=0;
+  driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=inputs.reportTime;
+  driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
+  driveState.lastUpdateTime=inputs.reportTime;
+  driveState.mountType=common::dataStructures::MountType::NoMount;
+  driveState.driveStatus=inputs.status;
+  driveState.currentVid="";
+  driveState.currentTapePool="";
+}
+
 //------------------------------------------------------------------------------
 // OStoreDB::setDriveStarting()
 //------------------------------------------------------------------------------
@@ -1288,7 +1333,9 @@ void OStoreDB::setDriveStarting(common::dataStructures::DriveState & driveState,
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.startStartTime=inputs.reportTime;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
@@ -1320,7 +1367,9 @@ void OStoreDB::setDriveMounting(common::dataStructures::DriveState & driveState,
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::Mounting;
@@ -1352,7 +1401,9 @@ void OStoreDB::setDriveTransferring(common::dataStructures::DriveState & driveSt
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::Transferring;
@@ -1382,7 +1433,9 @@ void OStoreDB::setDriveUnloading(common::dataStructures::DriveState & driveState
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::Unloading;
@@ -1412,7 +1465,9 @@ void OStoreDB::setDriveUnmounting(common::dataStructures::DriveState & driveStat
   driveState.unmountStartTime=inputs.reportTime;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::Unmounting;
@@ -1442,7 +1497,9 @@ void OStoreDB::setDriveDrainingToDisk(common::dataStructures::DriveState & drive
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=inputs.reportTime;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=0;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::DrainingToDisk;
@@ -1472,7 +1529,9 @@ void OStoreDB::setDriveCleaningUp(common::dataStructures::DriveState & driveStat
   driveState.unmountStartTime=0;
   driveState.drainingStartTime=0;
   driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
   driveState.cleanupStartTime=inputs.reportTime;
+  driveState.shutdownTime=0;
   driveState.lastUpdateTime=inputs.reportTime;
   driveState.mountType=inputs.mountType;
   driveState.driveStatus=common::dataStructures::DriveStatus::CleaningUp;
@@ -1480,6 +1539,37 @@ void OStoreDB::setDriveCleaningUp(common::dataStructures::DriveState & driveStat
   driveState.currentTapePool=inputs.tapepool;
 }
 
+//------------------------------------------------------------------------------
+// OStoreDB::setDriveShutdown()
+//------------------------------------------------------------------------------
+void OStoreDB::setDriveShutdown(common::dataStructures::DriveState & driveState,
+  const ReportDriveStatusInputs & inputs) {
+  if (driveState.driveStatus == common::dataStructures::DriveStatus::Shutdown) {
+    driveState.lastUpdateTime=inputs.reportTime;
+    return;
+  }
+  // If we are changing state, then all should be reset. We are not supposed to
+  // know the direction yet.
+  driveState.sessionId=0;
+  driveState.bytesTransferredInSession=0;
+  driveState.filesTransferredInSession=0;
+  driveState.latestBandwidth=0;
+  driveState.sessionStartTime=0;
+  driveState.mountStartTime=0;
+  driveState.transferStartTime=0;
+  driveState.unloadStartTime=0;
+  driveState.unmountStartTime=0;
+  driveState.drainingStartTime=0;
+  driveState.downOrUpStartTime=0;
+  driveState.probeStartTime=0;
+  driveState.cleanupStartTime=0;
+  driveState.shutdownTime=inputs.reportTime;
+  driveState.lastUpdateTime=inputs.reportTime;
+  driveState.mountType=inputs.mountType;
+  driveState.driveStatus=common::dataStructures::DriveStatus::CleaningUp;
+  driveState.currentVid=inputs.vid;
+  driveState.currentTapePool=inputs.tapepool;
+}
 //------------------------------------------------------------------------------
 // OStoreDB::TapeMountDecisionInfo::createArchiveMount()
 //------------------------------------------------------------------------------
diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp
index 2d5cf775d4..46bce86c52 100644
--- a/scheduler/OStoreDB/OStoreDB.hpp
+++ b/scheduler/OStoreDB/OStoreDB.hpp
@@ -329,6 +329,9 @@ private:
   /** Helper for setting a drive state in a specific case. Going UP means drive is ready. It will be instead marked as
    * down if this is the requested state */
   static void setDriveUpOrMaybeDown(common::dataStructures::DriveState & driveState, const ReportDriveStatusInputs & inputs);
+ 
+  /** Helper for setting a drive state in a specific case */
+  static void setDriveProbing(common::dataStructures::DriveState & driveState, const ReportDriveStatusInputs & inputs);
   
   /** Helper for setting a drive state in a specific case */
   static void setDriveStarting(common::dataStructures::DriveState & driveState, const ReportDriveStatusInputs & inputs);
@@ -351,6 +354,8 @@ private:
   /** Helper for setting a drive state in a specific case */
   static void setDriveCleaningUp(common::dataStructures::DriveState & driveState, const ReportDriveStatusInputs & inputs);
   
+  /** Helper for setting a drive state in a specific case */
+  static void setDriveShutdown(common::dataStructures::DriveState & driveState, const ReportDriveStatusInputs & inputs); 
 private:
   objectstore::Backend & m_objectStore;
   catalogue::Catalogue & m_catalogue;
diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp
index 1dc8c60f22..0392653e67 100644
--- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp
+++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp
@@ -115,6 +115,7 @@ schedule:
   // down to up. In such a case, we will run an empty 
   if (downUpTransition) {
     downUpTransition = false;
+    m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Probing, lc);
     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()) {
diff --git a/xroot_plugins/XrdCtaFile.cpp b/xroot_plugins/XrdCtaFile.cpp
index b545229f99..6d225af666 100644
--- a/xroot_plugins/XrdCtaFile.cpp
+++ b/xroot_plugins/XrdCtaFile.cpp
@@ -1897,6 +1897,8 @@ std::string XrdCtaFile::xCom_drive() {
           currentRow.push_back(cta::common::dataStructures::toString(ds.driveStatus));
           // print the time spent in the current state
           switch(ds.driveStatus) {
+          case cta::common::dataStructures::DriveStatus::Probing:
+            currentRow.push_back(std::to_string((unsigned long long)(time(nullptr)-ds.probeStartTime)));
           case cta::common::dataStructures::DriveStatus::Up:
           case cta::common::dataStructures::DriveStatus::Down:
             currentRow.push_back(std::to_string((unsigned long long)(time(nullptr)-ds.downOrUpStartTime)));
@@ -1922,6 +1924,8 @@ std::string XrdCtaFile::xCom_drive() {
           case cta::common::dataStructures::DriveStatus::DrainingToDisk:
             currentRow.push_back(std::to_string((unsigned long long)(time(nullptr)-ds.drainingStartTime)));
             break;
+          case cta::common::dataStructures::DriveStatus::Shutdown:
+            currentRow.push_back(std::to_string((unsigned long long)(time(nullptr)-ds.shutdownTime)));
           case cta::common::dataStructures::DriveStatus::Unknown:
             currentRow.push_back("-");
             break;
-- 
GitLab