diff --git a/ReleaseNotes.md b/ReleaseNotes.md index afaa317347f00e199b8e35b8de6e9de4941d8489..69dcf505c2b9475585b0286aa46c6952d485afc1 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 3437162fd69fc44fa73c436c8e15855242274390..12792242d98308c86e51c20ca457130726a5e186 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 17bc5dd79b9447d3f20a34411dfa7e45713714f1..1a9c4553c3feaca2fa04f3a253e01b8d2797fb5d 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 d741448862f0dce5218ae72992f018edc3816197..da973b59eb370a376445a95dbbf7e3891bdab2e0 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 49db6fae184fe067e5d732a052592e51367b0fb4..7be33fc2058104f0a7b1e3b9efa1889dbd601283 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 7dd571fdb743a6e5492578f6c9f1ad9acafc58a9..a8340816c9ef95cef55d52050574e4717d219410 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 c2903929753823dbc15551e188822fb80fb8dfb3..c38e933c32478c355e808092e2c74603b52ad23e 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 d7f2e56b0f1b438239daeba8e5756ac37a25cf65..a2468d3d70e5c90eb3116d1ea2db577e2102f773 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 1a37b24e73d5abc6a2a279b091b4021baad604bc..1644bba13b51bc1706a694d8dbfa6a59d346bbb1 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 3f7fc7110b4e3d3c7711f1995ccbb66ef355c974..4a6810bd51fdedc85a5ce78064311b0e355974bb 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 3c09822f2968a8c0db636e9fcbea0ac8c8831226..5bc560f3db9ff9700998bcc768d2dfe4109d3483 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 9045f01ba4e9d642a3456f84ea4a0f2831edb70e..823c3f845ffd0f7dab3979cc03c7fdd05b145344 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 d6a01f9cff2f2400f621c0ec2e752c2eafea66a4..79d69945683476abf1bf83cda7df7ac21bc632ab 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 a19e91673522f4c572f8a1c8efd826e4d1369030..e04ca64ab5c951455d64df6c68016594c40f7e91 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 fc02eccbc7827343d5179283b8463c189a7dc7a9..6c61a4ddcca9d56af9f6596346ee0c1b336be34d 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 78765e622fe09a2b4b8d4afa3f4827861c35c26b..8b9493725432b1cbfec637c720cb8661bf6e183e 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 6801ae0b4590af927997d9a3f09ed5f9c187bc96..3de7958964713e505c5c0e8594d223962aa4bacf 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 2556c04aaa584de1c5f9cb49995161064306f766..dedfb67b53459f40f1cf559b2e1c58f767296dfe 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 3f77de93acf855c339fb1929abd736f1e2142620..0e57e8f7f05a828f691e622d4712df95e6949e42 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 db76894548ca998a01a4e18a3cbb8adc69d70b05..888873bcf36a17b0e3eba3bd81a46da65697ed42 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 da65077b65d000297336ff26aff003649d9876e6..cc515be349777d0331d041b10766b9a29d34d367 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 e224e01f1eb26b416eac85ce966b426733c78d64..2ccf0ca40395c67e5fb510c75642c77f78d2712b 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 1b14dbd0fd1f8d25c97c34191aa9ee749654aabf..3539ae411104b4c42ba45f8b5df8e757c5a225d9 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 //----------------------------------------------------------------------------