From 18e7e7c28d914ab6f75c23ea8472ea7779aea70d Mon Sep 17 00:00:00 2001
From: Steven Murray <Steven.Murray@cern.ch>
Date: Mon, 12 Feb 2018 21:37:57 +0100
Subject: [PATCH] Added Catalogue::getArchiveFileQueueCriteria()

---
 catalogue/Catalogue.hpp             | 20 +++++++++++
 catalogue/CatalogueRetryWrapper.hpp |  8 ++++-
 catalogue/DummyCatalogue.hpp        |  5 ++-
 catalogue/RdbmsCatalogue.cpp        | 52 +++++++++++++++++++++++++++++
 catalogue/RdbmsCatalogue.hpp        | 20 +++++++++++
 5 files changed, 103 insertions(+), 2 deletions(-)

diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp
index 808bf0c8c7..bb74b1b135 100644
--- a/catalogue/Catalogue.hpp
+++ b/catalogue/Catalogue.hpp
@@ -27,6 +27,7 @@
 #include "common/dataStructures/AdminHost.hpp"
 #include "common/dataStructures/AdminUser.hpp"
 #include "common/dataStructures/ArchiveFile.hpp"
+#include "common/dataStructures/ArchiveFileQueueCriteria.hpp"
 #include "common/dataStructures/ArchiveFileQueueCriteriaAndFileId.hpp"
 #include "common/dataStructures/ArchiveFileSummary.hpp"
 #include "common/dataStructures/ArchiveJob.hpp"
@@ -96,6 +97,25 @@ public:
    */
   virtual void tapeLabelled(const std::string &vid, const std::string &drive, const bool lbpIsOn) = 0;
 
+  /**
+   * Returns the information required to queue an archive request.
+   *
+   * @param diskInstanceName The name of the disk instance to which the
+   * storage class belongs.
+   * @param storageClassName The name of the storage class of the file to be
+   * archived.  The storage class name is only guaranteed to be unique within
+   * its disk instance.  The storage class name will be used by the Catalogue
+   * to determine the destination tape pool for each tape copy.
+   * @param user The user for whom the file is to be archived.  This will be
+   * used by the Catalogue to determine the mount policy to be used when
+   * archiving the file.
+   * @return The information required to queue an archive request.
+   */
+  virtual common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(
+    const std::string &diskInstanceName,
+    const std::string &storageClassName,
+    const common::dataStructures::UserIdentity &user) = 0;
+
   /**
    * Prepares the catalogue for a new archive file and returns the information
    * required to queue the associated archive request.
diff --git a/catalogue/CatalogueRetryWrapper.hpp b/catalogue/CatalogueRetryWrapper.hpp
index b0b753c118..2bff386595 100644
--- a/catalogue/CatalogueRetryWrapper.hpp
+++ b/catalogue/CatalogueRetryWrapper.hpp
@@ -68,7 +68,13 @@ public:
     return retryOnLostConnection(m_log, [&]{return m_catalogue->tapeLabelled(vid, drive, lbpIsOn);}, m_maxTriesToConnect);
   }
 
-  common::dataStructures::ArchiveFileQueueCriteriaAndFileId prepareForNewFile( const std::string &diskInstanceName, const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override {
+  common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName,
+    const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override {
+    return retryOnLostConnection(m_log, [&]{return m_catalogue->getArchiveFileQueueCriteria(diskInstanceName, storageClassName, user);}, m_maxTriesToConnect);
+  }
+
+  common::dataStructures::ArchiveFileQueueCriteriaAndFileId prepareForNewFile(const std::string &diskInstanceName,
+    const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override {
     return retryOnLostConnection(m_log, [&]{return m_catalogue->prepareForNewFile(diskInstanceName, storageClassName, user);}, m_maxTriesToConnect);
   }
 
diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp
index aa1f55e686..ac9c0be5e9 100644
--- a/catalogue/DummyCatalogue.hpp
+++ b/catalogue/DummyCatalogue.hpp
@@ -99,7 +99,10 @@ public:
   void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& tapePoolName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void noSpaceLeftOnTape(const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void ping() override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
-  common::dataStructures::ArchiveFileQueueCriteriaAndFileId prepareForNewFile(const std::string& diskInstanceName, const std::string& storageClassName, const common::dataStructures::UserIdentity& user) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
+  common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName,
+    const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
+  common::dataStructures::ArchiveFileQueueCriteriaAndFileId prepareForNewFile(const std::string &diskInstanceName,
+    const std::string &storageClassName, const common::dataStructures::UserIdentity &user) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string& instanceName, const uint64_t archiveFileId, const common::dataStructures::UserIdentity& user, log::LogContext &lc) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFileByDiskFileId(const std::string &diskInstanceName, const std::string &diskFileId, const common::dataStructures::UserIdentity &user, log::LogContext &lc) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
   void reclaimTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp
index e5d8cc4ee3..68c47b85ab 100644
--- a/catalogue/RdbmsCatalogue.cpp
+++ b/catalogue/RdbmsCatalogue.cpp
@@ -3913,6 +3913,58 @@ void RdbmsCatalogue::tapeLabelled(const std::string &vid, const std::string &dri
   }
 }
 
+//------------------------------------------------------------------------------
+// getArchiveFileQueueCriteria
+//------------------------------------------------------------------------------
+common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::getArchiveFileQueueCriteria(
+  const std::string &diskInstanceName,
+  const std::string &storageClassName, const common::dataStructures::UserIdentity &user) {
+  try {
+    auto conn = m_connPool.getConn();
+    const common::dataStructures::TapeCopyToPoolMap copyToPoolMap = getTapeCopyToPoolMap(conn, diskInstanceName,
+      storageClassName);
+    const uint64_t expectedNbRoutes = getExpectedNbArchiveRoutes(conn, diskInstanceName, storageClassName);
+
+    // Check that the number of archive routes is correct
+    if(copyToPoolMap.empty()) {
+      exception::UserError ue;
+      ue.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " has no archive routes";
+      throw ue;
+    }
+    if(copyToPoolMap.size() != expectedNbRoutes) {
+      exception::UserError ue;
+      ue.getMessage() << "Storage class " << diskInstanceName << ":" << storageClassName << " does not have the"
+        " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" <<
+        copyToPoolMap.size();
+      throw ue;
+    }
+
+    const RequesterAndGroupMountPolicies mountPolicies = getMountPolicies(conn, diskInstanceName, user.name,
+      user.group);
+    // Requester mount policies overrule requester group mount policies
+    common::dataStructures::MountPolicy mountPolicy;
+    if(!mountPolicies.requesterMountPolicies.empty()) {
+       mountPolicy = mountPolicies.requesterMountPolicies.front();
+    } else if(!mountPolicies.requesterGroupMountPolicies.empty()) {
+       mountPolicy = mountPolicies.requesterGroupMountPolicies.front();
+    } else {
+      exception::UserError ue;
+      ue.getMessage() << "Cannot archive file because there are no mount rules for the requester or their group:"
+        " storageClass=" << storageClassName << " requester=" << diskInstanceName << ":" << user.name << ":" <<
+        user.group;
+      throw ue;
+    }
+
+    return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, mountPolicy);
+  } catch(exception::LostDatabaseConnection &le) {
+    throw exception::LostDatabaseConnection(std::string(__FUNCTION__) + " failed: " + le.getMessage().str());
+  } catch(exception::UserError &) {
+    throw;
+  } catch(exception::Exception &ex) {
+    throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str());
+  }
+}
+
 //------------------------------------------------------------------------------
 // prepareForNewFile
 //------------------------------------------------------------------------------
diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp
index 99fb948b90..882dd9c7c2 100644
--- a/catalogue/RdbmsCatalogue.hpp
+++ b/catalogue/RdbmsCatalogue.hpp
@@ -101,6 +101,26 @@ public:
    */
   void tapeLabelled(const std::string &vid, const std::string &drive, const bool lbpIsOn) override;
 
+  /**
+   * Prepares the catalogue for a new archive file and returns the information
+   * required to queue the associated archive request.
+   *
+   * @param diskInstanceName The name of the disk instance to which the
+   * storage class belongs.
+   * @param storageClassName The name of the storage class of the file to be
+   * archived.  The storage class name is only guaranteed to be unique within
+   * its disk instance.  The storage class name will be used by the Catalogue
+   * to determine the destination tape pool for each tape copy.
+   * @param user The user for whom the file is to be archived.  This will be
+   * used by the Catalogue to determine the mount policy to be used when
+   * archiving the file.
+   * @return The information required to queue the associated archive request.
+   */
+  common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(
+    const std::string &diskInstanceName,
+    const std::string &storageClassName,
+    const common::dataStructures::UserIdentity &user) override;
+
   /**
    * Prepares the catalogue for a new archive file and returns the information
    * required to queue the associated archive request.
-- 
GitLab