From abe6dbc4fd5277254a90f2a4ab9abc96d0181a5d Mon Sep 17 00:00:00 2001 From: Eric Cano <Eric.Cano@cern.ch> Date: Wed, 26 Jul 2017 15:33:07 +0200 Subject: [PATCH] Added automatic trimming of empty queues at schedule time. --- scheduler/OStoreDB/OStoreDB.cpp | 51 ++++++++++++++++++++++++++ scheduler/OStoreDB/OStoreDB.hpp | 1 + scheduler/OStoreDB/OStoreDBFactory.hpp | 6 ++- scheduler/Scheduler.cpp | 1 + scheduler/SchedulerDatabase.hpp | 7 ++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp index ee79056d31..8ab430f75a 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 32df3d41c7..4df089c2ea 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 24a846c338..0727665033 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 337b605ff3..061deb1dbb 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 012f19cd0f..6a46678a19 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. -- GitLab