From dd8692d4604ccf2e565c3432b792b96e6f1e028f Mon Sep 17 00:00:00 2001 From: Joao Afonso <joao.afonso@cern.ch> Date: Wed, 25 Jan 2023 17:42:32 +0100 Subject: [PATCH] Resolve "Add a timeout to tape server global lock on the object store" --- ReleaseNotes.md | 1 + catalogue/DriveConfig.cpp | 1 + cmdline/CtaAdminCmd.cpp | 10 ++++++++++ cmdline/CtaAdminCmd.hpp | 2 +- cmdline/CtaAdminTextFormatter.cpp | 8 +++++--- cmdline/CtaAdminTextFormatter.hpp | 8 ++++++++ cmdline/cta-cli.conf.example | 3 +++ common/exception/Exception.hpp | 8 ++++++++ objectstore/BackendRados.cpp | 4 ++-- objectstore/BackendVFS.cpp | 2 +- scheduler/OStoreDB/OStoreDB.cpp | 12 ++++++++++-- scheduler/OStoreDB/OStoreDB.hpp | 1 + scheduler/PostgresSchedDB/PostgresSchedDB.cpp | 5 +++++ scheduler/PostgresSchedDB/PostgresSchedDB.hpp | 1 + scheduler/Scheduler.cpp | 2 +- scheduler/Scheduler.hpp | 4 +++- scheduler/SchedulerDatabase.hpp | 1 + scheduler/SchedulerDatabaseFactory.hpp | 4 ++++ .../tape/tapeserver/daemon/DataTransferConfig.hpp | 5 +++++ .../tape/tapeserver/daemon/DataTransferSession.cpp | 14 +++++++++++--- tapeserver/daemon/DriveHandler.cpp | 1 + tapeserver/daemon/TapedConfiguration.cpp | 2 ++ tapeserver/daemon/TapedConfiguration.hpp | 3 +++ 23 files changed, 88 insertions(+), 14 deletions(-) diff --git a/ReleaseNotes.md b/ReleaseNotes.md index afaa317347..69dcf505c2 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -20,6 +20,7 @@ - cta/CTA#234 - Replace stoi with toUint64 in standalone cli tool - cta/CTA#238 - Compilation fails when using cta::common::Configuration::getConfEntInt(...) - cta/CTA#273 - Fix tape state change command idempotency when resetting REPACKING/BROKEN/PENDING +- cta/CTA#280 - Add a timeout to tape server global lock on the object store ### Continuous Integration - cta/CTA#205 - Updating EOS4/EOS4 in versionlock for v4.8.95/v5.1.5 - cta/CTA#253 - Allow Failure for cta_valgrind tests diff --git a/catalogue/DriveConfig.cpp b/catalogue/DriveConfig.cpp index 3437162fd6..12792242d9 100644 --- a/catalogue/DriveConfig.cpp +++ b/catalogue/DriveConfig.cpp @@ -58,6 +58,7 @@ void DriveConfig::setTapedConfiguration(const cta::tape::daemon::TapedConfigurat setConfigToDB(&config->useMaintenanceProcess, catalogue, tapeDriveName); setConfigToDB(&config->externalFreeDiskSpaceScript, catalogue, tapeDriveName); setConfigToDB(&config->tapeLoadTimeout, catalogue, tapeDriveName); + setConfigToDB(&config->wdGlobalLockAcqMaxSecs, catalogue, tapeDriveName); } void DriveConfig::checkConfigInDB(catalogue::Catalogue* catalogue, const std::string& tapeDriveName, diff --git a/cmdline/CtaAdminCmd.cpp b/cmdline/CtaAdminCmd.cpp index 17bc5dd79b..1a9c4553c3 100644 --- a/cmdline/CtaAdminCmd.cpp +++ b/cmdline/CtaAdminCmd.cpp @@ -276,6 +276,16 @@ void CtaAdminCmd::send() const throw std::runtime_error("Configuration error: cta.endpoint missing from " + config_file.string()); } + // Check drive timeout value + auto [driveTimeoutConfigExists, driveTimeoutVal] = config.getOptionValueInt("drive_timeout"); + if(driveTimeoutConfigExists) { + if (driveTimeoutVal > 0) { + formattedText.setDriveTimeout(driveTimeoutVal); + } else { + throw std::runtime_error("Configuration error: cta.drive_timeout not a positive value in " + config_file.string()); + } + } + // If the server is down, we want an immediate failure. Set client retry to a single attempt. XrdSsiProviderClient->SetTimeout(XrdSsiProvider::connect_N, 1); diff --git a/cmdline/CtaAdminCmd.hpp b/cmdline/CtaAdminCmd.hpp index d741448862..da973b59eb 100644 --- a/cmdline/CtaAdminCmd.hpp +++ b/cmdline/CtaAdminCmd.hpp @@ -80,7 +80,7 @@ private: static std::atomic<bool> is_json; //!< Display results in JSON format static std::atomic<bool> is_first_record; //!< Delimiter for JSON records - std::optional<std::string> m_config; //!< User defined config file + std::optional<std::string> m_config; //!< User defined config file static constexpr const char* const LOG_SUFFIX = "CtaAdminCmd"; //!< Identifier for log messages }; diff --git a/cmdline/CtaAdminTextFormatter.cpp b/cmdline/CtaAdminTextFormatter.cpp index 49db6fae18..7be33fc205 100644 --- a/cmdline/CtaAdminTextFormatter.cpp +++ b/cmdline/CtaAdminTextFormatter.cpp @@ -31,6 +31,10 @@ namespace admin { ** Generic utility methods **/ +void TextFormatter::setDriveTimeout(unsigned int driveTimeoutSec) { + m_driveTimeoutSec = driveTimeoutSec; +} + std::string TextFormatter::doubleToStr(double value, char unit) { std::stringstream ss; ss << std::fixed << std::setprecision(1) << value; @@ -271,8 +275,6 @@ void TextFormatter::print(const DriveLsItem &drls_item) { //using namespace cta::common::dataStructures; - const int DRIVE_TIMEOUT = 14400; // Time after which a drive will be marked as STALE (4 hours) - std::string driveStatusSince; std::string filesTransferredInSession; std::string bytesTransferredInSession; @@ -301,7 +303,7 @@ void TextFormatter::print(const DriveLsItem &drls_item) } timeSinceLastUpdate = std::to_string(drls_item.time_since_last_update()) + - (drls_item.time_since_last_update() > DRIVE_TIMEOUT ? " [STALE]" : ""); + (drls_item.time_since_last_update() > m_driveTimeoutSec ? " [STALE]" : ""); std::string reportedLogicalLibrary = drls_item.logical_library(); if (drls_item.logical_library_disabled()) { diff --git a/cmdline/CtaAdminTextFormatter.hpp b/cmdline/CtaAdminTextFormatter.hpp index 7dd571fdb7..a8340816c9 100644 --- a/cmdline/CtaAdminTextFormatter.hpp +++ b/cmdline/CtaAdminTextFormatter.hpp @@ -22,6 +22,10 @@ namespace cta { namespace admin { +// Time after which a drive will be marked as STALE +// By default it's the default global lock timeout (15 mins) + 5 extra mins +const int DRIVE_TIMEOUT_S_DEFAULT = (15 + 5) * 60; + class TextFormatter { public: @@ -100,6 +104,9 @@ public: void print(const MediaTypeLsItem &mtls_item); void print(const RecycleTapeFileLsItem & rtfls_item); + // Modify drive timeout + void setDriveTimeout(unsigned int driveTimeoutSec); + private: //! Add a line to the buffer template<typename... Args> @@ -166,6 +173,7 @@ private: static constexpr const char* const TEXT_RED = "\x1b[31;1m"; //!< Terminal formatting code for red text static constexpr const char* const TEXT_NORMAL = "\x1b[0m"; //!< Terminal formatting code for normal text static constexpr const int NB_CHAR_REASON = 50; //!< Reason max length to display in tabular output (DriveLs and TapeLs) + unsigned int m_driveTimeoutSec = DRIVE_TIMEOUT_S_DEFAULT; //!< Time after which a drive will be marked as STALE }; }} diff --git a/cmdline/cta-cli.conf.example b/cmdline/cta-cli.conf.example index c290392975..c38e933c32 100644 --- a/cmdline/cta-cli.conf.example +++ b/cmdline/cta-cli.conf.example @@ -23,3 +23,6 @@ eos.requester.group it # Specify whether log timestamps should have second (false) or microsecond (true) resolution. # cta.log.hiRes false + +# STALE drive timeout (seconds) +# cta.drive_timeout 1200 diff --git a/common/exception/Exception.hpp b/common/exception/Exception.hpp index d7f2e56b0f..a2468d3d70 100644 --- a/common/exception/Exception.hpp +++ b/common/exception/Exception.hpp @@ -117,6 +117,14 @@ protected: } ; +/** + * class TimeoutException + * A simple exception used for timeout handling in cts + */ +class TimeoutException : public Exception { + using Exception::Exception; +}; + }} // namespace cta::exception #define CTA_GENERATE_EXCEPTION_CLASS(A) class A: public cta::exception::Exception { using Exception::Exception; } diff --git a/objectstore/BackendRados.cpp b/objectstore/BackendRados.cpp index 1a37b24e73..1644bba13b 100644 --- a/objectstore/BackendRados.cpp +++ b/objectstore/BackendRados.cpp @@ -562,7 +562,7 @@ void BackendRados::lockNotify(const std::string& name, uint64_t timeout_us, Lock watcher.wait(watchTimeout); TIMESTAMPEDPRINT(lockType==LockType::Shared?"Post-wait (shared)":"Post-wait (exclusive)"); if (timeout_us && (timeoutTimer.usecs() > (int64_t)timeout_us)) { - throw exception::Exception("In BackendRados::lockNotify(): timeout."); + throw exception::TimeoutException("In BackendRados::lockNotify(): timeout."); } } cta::exception::Errnum::throwOnReturnedErrno(-rc, @@ -750,7 +750,7 @@ void BackendRados::lockBackoff(const std::string& name, uint64_t timeout_us, Loc } if (-EBUSY != rc) break; if (timeout_us && (timeoutTimer.usecs() > (int64_t)timeout_us)) { - throw exception::Exception( + throw exception::TimeoutException( "In BackendRados::lockBackoff(): timeout : timeout set = " + std::to_string(timeout_us) + " usec, time to lock the object : " + std::to_string(timeoutTimer.usecs()) + " usec, number of tries to lock = " + std::to_string(nbTriesToLock) + " object: " + name); } diff --git a/objectstore/BackendVFS.cpp b/objectstore/BackendVFS.cpp index 3f7fc7110b..4a6810bd51 100644 --- a/objectstore/BackendVFS.cpp +++ b/objectstore/BackendVFS.cpp @@ -296,7 +296,7 @@ BackendVFS::ScopedLock * BackendVFS::lockHelper(const std::string& name, int typ throw ex; } if (t.usecs() > (int64_t)timeout_us) { - throw exception::Exception("In BackendVFS::lockHelper(): timeout while locking"); + throw exception::TimeoutException("In BackendVFS::lockHelper(): timeout while locking"); } } } else { diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp index 3c09822f29..5bc560f3db 100644 --- a/scheduler/OStoreDB/OStoreDB.cpp +++ b/scheduler/OStoreDB/OStoreDB.cpp @@ -696,7 +696,15 @@ std::string OStoreDB::getLowestRequestAgeRetrieveMountPolicyName(const std::list // OStoreDB::getMountInfo() //------------------------------------------------------------------------------ std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> - OStoreDB::getMountInfo(log::LogContext& logContext) { +OStoreDB::getMountInfo(log::LogContext& logContext) { + return OStoreDB::getMountInfo(logContext, 0); +} + +//------------------------------------------------------------------------------ +// OStoreDB::getMountInfo() +//------------------------------------------------------------------------------ +std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> + OStoreDB::getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) { utils::Timer t; //Allocate the getMountInfostructure to return. assertAgentAddressSet(); @@ -709,7 +717,7 @@ std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> // Take an exclusive lock on the scheduling and fetch it. tmdi.m_schedulerGlobalLock.reset( new SchedulerGlobalLock(re.getSchedulerGlobalLock(), m_objectStore)); - tmdi.m_lockOnSchedulerGlobalLock.lock(*tmdi.m_schedulerGlobalLock); + tmdi.m_lockOnSchedulerGlobalLock.lock(*tmdi.m_schedulerGlobalLock, globalLockTimeout_us); auto lockSchedGlobalTime = t.secs(utils::Timer::resetCounter); tmdi.m_lockTaken = true; tmdi.m_schedulerGlobalLock->fetch(); diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp index 9045f01ba4..823c3f845f 100644 --- a/scheduler/OStoreDB/OStoreDB.hpp +++ b/scheduler/OStoreDB/OStoreDB.hpp @@ -232,6 +232,7 @@ class OStoreDB: public SchedulerDatabase { public: std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext) override; + std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) override; std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfoNoLock(PurposeGetMountInfo purpose, log::LogContext& logContext) override; diff --git a/scheduler/PostgresSchedDB/PostgresSchedDB.cpp b/scheduler/PostgresSchedDB/PostgresSchedDB.cpp index d6a01f9cff..79d6994568 100644 --- a/scheduler/PostgresSchedDB/PostgresSchedDB.cpp +++ b/scheduler/PostgresSchedDB/PostgresSchedDB.cpp @@ -261,6 +261,11 @@ SchedulerDatabase::JobsFailedSummary PostgresSchedDB::getRetrieveJobsFailedSumma } std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> PostgresSchedDB::getMountInfo(log::LogContext& logContext) +{ + throw cta::exception::Exception("Not implemented"); +} + +std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> PostgresSchedDB::getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) { throw cta::exception::Exception("Not implemented"); } diff --git a/scheduler/PostgresSchedDB/PostgresSchedDB.hpp b/scheduler/PostgresSchedDB/PostgresSchedDB.hpp index a19e916735..e04ca64ab5 100644 --- a/scheduler/PostgresSchedDB/PostgresSchedDB.hpp +++ b/scheduler/PostgresSchedDB/PostgresSchedDB.hpp @@ -166,6 +166,7 @@ class PostgresSchedDB: public SchedulerDatabase { JobsFailedSummary getRetrieveJobsFailedSummary(log::LogContext &logContext) override; std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext) override; + std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) override; void trimEmptyQueues(log::LogContext& lc) override; diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp index fc02eccbc7..6c61a4ddcc 100644 --- a/scheduler/Scheduler.cpp +++ b/scheduler/Scheduler.cpp @@ -1435,7 +1435,7 @@ bool Scheduler::getNextMountDryRun(const std::string& logicalLibraryName, const //------------------------------------------------------------------------------ // getNextMount //------------------------------------------------------------------------------ -std::unique_ptr<TapeMount> Scheduler::getNextMount(const std::string &logicalLibraryName, const std::string &driveName, log::LogContext & lc) { +std::unique_ptr<TapeMount> Scheduler::getNextMount(const std::string &logicalLibraryName, const std::string &driveName, log::LogContext & lc, uint64_t globalLockTimeout_us) { // In order to decide the next mount to do, we have to take a global lock on // the scheduling, retrieve a list of all running mounts, queues sizes for // tapes and tape pools, order the candidates by priority diff --git a/scheduler/Scheduler.hpp b/scheduler/Scheduler.hpp index 78765e622f..8b94937254 100644 --- a/scheduler/Scheduler.hpp +++ b/scheduler/Scheduler.hpp @@ -326,12 +326,14 @@ public: bool getNextMountDryRun(const std::string &logicalLibraryName, const std::string &driveName, log::LogContext & lc); /** * Actually decide which mount to do next for a given drive. + * Throws a TimeoutException in case the timeout goes out * @param logicalLibraryName library for the drive we are scheduling * @param driveName name of the drive we are scheduling * @param lc log context + * @param globalLockTimeout_us global lock timeout * @return unique pointer to the tape mount structure. Next step for the user will be find which type of mount this is. */ - std::unique_ptr<TapeMount> getNextMount(const std::string &logicalLibraryName, const std::string &driveName, log::LogContext & lc); + std::unique_ptr<TapeMount> getNextMount(const std::string &logicalLibraryName, const std::string &driveName, log::LogContext & lc, uint64_t globalLockTimeout_us = 0); /** * A function returning diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp index 6801ae0b45..3de7958964 100644 --- a/scheduler/SchedulerDatabase.hpp +++ b/scheduler/SchedulerDatabase.hpp @@ -831,6 +831,7 @@ class SchedulerDatabase { * a global lock on for scheduling). */ virtual std::unique_ptr<TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext) = 0; + virtual std::unique_ptr<TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) = 0; /** * A function running a queue trim. This should be called if the corresponding diff --git a/scheduler/SchedulerDatabaseFactory.hpp b/scheduler/SchedulerDatabaseFactory.hpp index 2556c04aaa..dedfb67b53 100644 --- a/scheduler/SchedulerDatabaseFactory.hpp +++ b/scheduler/SchedulerDatabaseFactory.hpp @@ -197,6 +197,10 @@ public: return m_SchedDB->getMountInfo(logContext); } + std::unique_ptr<TapeMountDecisionInfo> getMountInfo(log::LogContext& logContext, uint64_t globalLockTimeout_us) override { + return m_SchedDB->getMountInfo(logContext, globalLockTimeout_us); + } + void trimEmptyQueues(log::LogContext& lc) override { m_SchedDB->trimEmptyQueues(lc); } diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp index 3f77de93ac..0e57e8f7f0 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp @@ -152,6 +152,11 @@ struct DataTransferConfig { */ time_t wdIdleSessionTimer; + /** + * The timeout after which the tape server stops trying to get the next mount + */ + time_t wdGlobalLockAcqMaxSecs; + /** * Constructor that sets all integer member-variables to 0 and all string * member-variables to the empty string. diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp index db76894548..888873bcf3 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp @@ -167,10 +167,16 @@ castor::tape::tapeserver::daemon::DataTransferSession::execute() { tapeServerReporter.reportState(cta::tape::session::SessionState::Scheduling, cta::tape::session::SessionType::Undetermined); + bool globalLockTimeout = false; try { if (m_scheduler.getNextMountDryRun(m_driveConfig.logicalLibrary, m_driveConfig.unitName, lc)) { - tapeMount = m_scheduler.getNextMount(m_driveConfig.logicalLibrary, m_driveConfig.unitName, lc); + tapeMount = m_scheduler.getNextMount(m_driveConfig.logicalLibrary, m_driveConfig.unitName, lc, + m_dataTransferConfig.wdGlobalLockAcqMaxSecs * 1000000); } + } catch (cta::exception::TimeoutException &e) { + // Print warning and try again, after refreshing the tape drive states + lc.log(cta::log::WARNING, "Timeout while scheduling new mount."); + globalLockTimeout = true; } catch (cta::exception::Exception &e) { lc.log(cta::log::ERR, "Error while scheduling new mount. Putting the drive down. Stack trace follows."); lc.logBacktrace(cta::log::INFO, e.backtrace()); @@ -180,11 +186,13 @@ castor::tape::tapeserver::daemon::DataTransferSession::execute() { // No mount to be done found, that was fast... if (!tapeMount) { - lc.log(cta::log::DEBUG, "No new mount found. (sleeping 10 seconds)"); // Refresh the status to trigger the timeout update m_scheduler.reportDriveStatus(m_driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Up, lc); - sleep(m_dataTransferConfig.wdIdleSessionTimer); + if (!globalLockTimeout) { + lc.log(cta::log::DEBUG, "No new mount found. (sleeping " + std::to_string(m_dataTransferConfig.wdIdleSessionTimer) + " seconds)"); + sleep(m_dataTransferConfig.wdIdleSessionTimer); + } continue; } break; diff --git a/tapeserver/daemon/DriveHandler.cpp b/tapeserver/daemon/DriveHandler.cpp index da65077b65..cc515be349 100644 --- a/tapeserver/daemon/DriveHandler.cpp +++ b/tapeserver/daemon/DriveHandler.cpp @@ -1010,6 +1010,7 @@ int DriveHandler::runChild() { dataTransferConfig.useEncryption = m_tapedConfig.useEncryption.value() == "yes" ? true : false; dataTransferConfig.externalEncryptionKeyScript = m_tapedConfig.externalEncryptionKeyScript.value(); dataTransferConfig.wdIdleSessionTimer = m_tapedConfig.wdIdleSessionTimer.value(); + dataTransferConfig.wdGlobalLockAcqMaxSecs = m_tapedConfig.wdGlobalLockAcqMaxSecs.value(); m_stateChangeTimeouts[session::SessionState::Checking] = std::chrono::duration_cast<Timeout>( std::chrono::minutes(m_tapedConfig.wdCheckMaxSecs.value())); m_stateChangeTimeouts[session::SessionState::Scheduling] = std::chrono::duration_cast<Timeout>( diff --git a/tapeserver/daemon/TapedConfiguration.cpp b/tapeserver/daemon/TapedConfiguration.cpp index e224e01f1e..2ccf0ca403 100644 --- a/tapeserver/daemon/TapedConfiguration.cpp +++ b/tapeserver/daemon/TapedConfiguration.cpp @@ -117,6 +117,7 @@ TapedConfiguration TapedConfiguration::createFromCtaConf( ret.wdMountMaxSecs.setFromConfigurationFile(cf, generalConfigPath); ret.wdNoBlockMoveMaxSecs.setFromConfigurationFile(cf, generalConfigPath); ret.wdScheduleMaxSecs.setFromConfigurationFile(cf, generalConfigPath); + ret.wdGlobalLockAcqMaxSecs.setFromConfigurationFile(cf, generalConfigPath); // The central storage access configuration ret.backendPath.setFromConfigurationFile(cf, generalConfigPath); ret.fileCatalogConfigFile.setFromConfigurationFile(cf, generalConfigPath); @@ -158,6 +159,7 @@ TapedConfiguration TapedConfiguration::createFromCtaConf( ret.wdMountMaxSecs.log(log); ret.wdNoBlockMoveMaxSecs.log(log); ret.wdScheduleMaxSecs.log(log); + ret.wdGlobalLockAcqMaxSecs.log(log); ret.backendPath.log(log); ret.fileCatalogConfigFile.log(log); diff --git a/tapeserver/daemon/TapedConfiguration.hpp b/tapeserver/daemon/TapedConfiguration.hpp index 1b14dbd0fd..3539ae4111 100644 --- a/tapeserver/daemon/TapedConfiguration.hpp +++ b/tapeserver/daemon/TapedConfiguration.hpp @@ -134,6 +134,9 @@ struct TapedConfiguration { /// Time to wait after scheduling came up idle cta::SourcedParameter<time_t> wdIdleSessionTimer{ "taped", "WatchdogIdleSessionTimer", 10, "Compile time default"}; + /// Time to wait after which the tape server stops trying to get the next mount + cta::SourcedParameter<time_t> wdGlobalLockAcqMaxSecs{ + "taped", "WatchdogGlobalLockAcqMaxSecs", 15 * 60, "Compile time default"}; //---------------------------------------------------------------------------- // The central storage access configuration //---------------------------------------------------------------------------- -- GitLab