diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp index ee79056d31befd1bd1f3f5df8656d693ef596e18..8ab430f75acf4641d263299cdb473aec7043159d 100644 --- a/scheduler/OStoreDB/OStoreDB.cpp +++ b/scheduler/OStoreDB/OStoreDB.cpp @@ -106,6 +106,8 @@ void OStoreDB::fetchMountInfo(SchedulerDatabase::TapeMountDecisionInfo& tmdi, Ro m.maxDrivesAllowed = aqueue.getJobsSummary().maxDrivesAllowed; m.minArchiveRequestAge = aqueue.getJobsSummary().minArchiveRequestAge; m.logicalLibrary = ""; + } else { + tmdi.queueTrimRequired = true; } } // Walk the retrieve queues for statistics @@ -129,6 +131,8 @@ void OStoreDB::fetchMountInfo(SchedulerDatabase::TapeMountDecisionInfo& tmdi, Ro m.maxDrivesAllowed = rqueue.getJobsSummary().maxDrivesAllowed; m.minArchiveRequestAge = rqueue.getJobsSummary().minArchiveRequestAge; m.logicalLibrary = ""; // The logical library is not known here, and will be determined by the caller. + } else { + tmdi.queueTrimRequired = true; } } // Collect information about the existing and next mounts @@ -202,6 +206,53 @@ std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> return ret; } +//------------------------------------------------------------------------------ +// OStoreDB::trimEmptyQueues() +//------------------------------------------------------------------------------ +void OStoreDB::trimEmptyQueues(log::LogContext& lc) { + // We will trim empty queues from the root entry. + lc.log(log::INFO, "In OStoreDB::trimEmptyQueues(): will start trimming empty queues"); + // Get an exclusive lock on the root entry, we have good chances to need it. + RootEntry re(m_objectStore); + ScopedExclusiveLock rel(re); + try { + auto archiveQueueList = re.dumpArchiveQueues(); + for (auto & a: archiveQueueList) { + ArchiveQueue aq(a.address, m_objectStore); + ScopedSharedLock aql(aq); + aq.fetch(); + if (!aq.dumpJobs().size()) { + aql.release(); + re.removeArchiveQueueAndCommit(a.tapePool); + log::ScopedParamContainer params(lc); + params.add("tapePool", a.tapePool) + .add("queueObject", a.address); + lc.log(log::INFO, "In OStoreDB::trimEmptyQueues(): deleted empty archive queue."); + } + } + auto retrieveQeueueList = re.dumpRetrieveQueues(); + for (auto & r:retrieveQeueueList) { + RetrieveQueue rq(r.address, m_objectStore); + ScopedSharedLock rql(rq); + rq.fetch(); + if (!rq.dumpJobs().size()) { + rql.release(); + re.removeRetrieveQueueAndCommit(r.vid); + log::ScopedParamContainer params(lc); + params.add("vid", r.vid) + .add("queueObject", r.address); + lc.log(log::INFO, "In OStoreDB::trimEmptyQueues(): deleted empty retrieve queue."); + } + } + } catch (cta::exception::Exception & ex) { + log::ScopedParamContainer params(lc); + params.add("exceptionMessage", ex.getMessageValue()); + lc.log(log::ERR, "In OStoreDB::trimEmptyQueues(): got an exception. Stack trace follows."); + lc.logBacktrace(log::ERR, ex.backtrace()); + } +} + + //------------------------------------------------------------------------------ // OStoreDB::getMountInfoNoLock() //------------------------------------------------------------------------------ diff --git a/scheduler/OStoreDB/OStoreDB.hpp b/scheduler/OStoreDB/OStoreDB.hpp index 32df3d41c7085423b7c8eb65594603a86a3155f3..4df089c2ea8371e421e3285c025c6e19797f542c 100644 --- a/scheduler/OStoreDB/OStoreDB.hpp +++ b/scheduler/OStoreDB/OStoreDB.hpp @@ -113,6 +113,7 @@ private: public: std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfo() override; std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> getMountInfoNoLock() override; + void trimEmptyQueues(log::LogContext& lc) override; /* === Archive Mount handling ============================================= */ class ArchiveMount: public SchedulerDatabase::ArchiveMount { diff --git a/scheduler/OStoreDB/OStoreDBFactory.hpp b/scheduler/OStoreDB/OStoreDBFactory.hpp index 24a846c3389e6f94965caefb052084dd2faa9897..072766503345ff6395b098d2099e4e3dba4aa69b 100644 --- a/scheduler/OStoreDB/OStoreDBFactory.hpp +++ b/scheduler/OStoreDB/OStoreDBFactory.hpp @@ -129,7 +129,11 @@ public: std::unique_ptr<TapeMountDecisionInfo> getMountInfo() override { return m_OStoreDB.getMountInfo(); } - + + void trimEmptyQueues(log::LogContext& lc) override { + m_OStoreDB.trimEmptyQueues(lc); + } + std::unique_ptr<TapeMountDecisionInfo> getMountInfoNoLock() override { return m_OStoreDB.getMountInfoNoLock(); } diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp index 337b605ff399b07cbc71b7beb0fe2aef3510b819..061deb1dbb7673c6c9bd7c762995ab44708e914d 100644 --- a/scheduler/Scheduler.cpp +++ b/scheduler/Scheduler.cpp @@ -405,6 +405,7 @@ std::unique_ptr<TapeMount> Scheduler::getNextMount(const std::string &logicalLib // First, get the mount-related info from the DB std::unique_ptr<SchedulerDatabase::TapeMountDecisionInfo> mountInfo; mountInfo = m_db.getMountInfo(); + if (mountInfo->queueTrimRequired) m_db.trimEmptyQueues(lc); __attribute__((unused)) SchedulerDatabase::TapeMountDecisionInfo & debugMountInfo = *mountInfo; // The library information is not know for the tapes involved in retrieves. We diff --git a/scheduler/SchedulerDatabase.hpp b/scheduler/SchedulerDatabase.hpp index 012f19cd0fab5e39b75d2c41b3528ebda857d980..6a46678a19faf7ca29801b6578e6daef3b03faf6 100644 --- a/scheduler/SchedulerDatabase.hpp +++ b/scheduler/SchedulerDatabase.hpp @@ -430,6 +430,7 @@ public: std::vector<PotentialMount> potentialMounts; /**< All the potential mounts */ std::vector<ExistingMount> existingOrNextMounts; /**< Existing mounts */ std::map<std::string, DedicationEntry> dedicationInfo; /**< Drives dedication info */ + bool queueTrimRequired = false; /**< Indicates an empty queue was encountered */ /** * Create a new archive mount. This implicitly releases the global scheduling * lock. @@ -457,6 +458,12 @@ public: */ virtual std::unique_ptr<TapeMountDecisionInfo> getMountInfo() = 0; + /** + * A function running a queue trim. This should be called if the corresponding + * bit was set in the TapeMountDecisionInfo returned by getMountInfo(). + */ + virtual void trimEmptyQueues(log::LogContext & lc) = 0; + /** * A function dumping the relevant mount information for reporting the system * status. It is identical to getMountInfo, yet does not take the global lock.