diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp index bbbfca2fd08dfa6af4927d1c2c4fee2b7da0310a..79638dd08e4d38ba8775e170991303c8858a76c2 100644 --- a/catalogue/Catalogue.hpp +++ b/catalogue/Catalogue.hpp @@ -265,6 +265,15 @@ public: virtual void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) = 0; virtual void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) = 0; + /** + * Modifies the name of the specified tape pool. + * + * @param admin The administrator. + * @param currentName The current name of the tape pool. + * @param newName The new name of the tape pool. + */ + virtual void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) = 0; + virtual void createArchiveRoute( const common::dataStructures::SecurityIdentity &admin, const std::string &diskInstanceName, diff --git a/catalogue/CatalogueRetryWrapper.hpp b/catalogue/CatalogueRetryWrapper.hpp index 725718a1790b244f47b5faf67a4acacb7d0e47a0..a9ab40f0a991dd68e2d420bd010829d7c4350f1a 100644 --- a/catalogue/CatalogueRetryWrapper.hpp +++ b/catalogue/CatalogueRetryWrapper.hpp @@ -173,6 +173,10 @@ public: return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapePoolSupply(admin, name, supply);}, m_maxTriesToConnect); } + void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override { + return retryOnLostConnection(m_log, [&]{return m_catalogue->modifyTapePoolName(admin, currentName, newName);}, m_maxTriesToConnect); + } + void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &diskInstanceName, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override { return retryOnLostConnection(m_log, [&]{return m_catalogue->createArchiveRoute(admin, diskInstanceName, storageClassName, copyNb, tapePoolName, comment);}, m_maxTriesToConnect); } diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp index fb3af14b415e3ebc278f65e727fc26959f500b56..86bb80210846bb6ea3f8db609b8345e9b82e7ecc 100644 --- a/catalogue/CatalogueTest.cpp +++ b/catalogue/CatalogueTest.cpp @@ -1757,6 +1757,121 @@ TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute) { ASSERT_EQ(creationLog, lastModificationLog); } +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newTapePoolName = "new_tape_pool"; + m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(newTapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName_emptyStringCurrentTapePoolName) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = ""; + const std::string newTapePoolName = "new_tape_pool"; + ASSERT_THROW(m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName), + catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_CatalogueTest, modifyTapePoolName_emptyStringNewTapePoolName) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->getTapePools().empty()); + + const std::string tapePoolName = "tape_pool"; + const std::string vo = "vo"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const cta::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->createTapePool(m_admin, tapePoolName, vo, nbPartialTapes, isEncrypted, supply, comment); + + { + const auto pools = m_catalogue->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(vo, pool.vo); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(comment, pool.comment); + + const common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newTapePoolName = ""; + ASSERT_THROW(m_catalogue->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName), + catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + TEST_P(cta_catalogue_CatalogueTest, createArchiveRoute_emptyStringDiskInstanceName) { using namespace cta; diff --git a/catalogue/DropSchemaCmd.cpp b/catalogue/DropSchemaCmd.cpp index 40bf7fa116cf9703908ad7718043f1d99623cb11..bb691b6584e55c760e7cc426607192f5bf195243 100644 --- a/catalogue/DropSchemaCmd.cpp +++ b/catalogue/DropSchemaCmd.cpp @@ -145,6 +145,7 @@ void DropSchemaCmd::dropSqliteCatalogueSchema(rdbms::Conn &conn) { "STORAGE_CLASS", "STORAGE_CLASS_ID", "TAPE_POOL", + "TAPE_POOL_ID", "LOGICAL_LIBRARY", "MOUNT_POLICY", "ACTIVITIES_WEIGHTS", @@ -177,6 +178,7 @@ void DropSchemaCmd::dropMysqlCatalogueSchema(rdbms::Conn &conn) { "STORAGE_CLASS", "STORAGE_CLASS_ID", "TAPE_POOL", + "TAPE_POOL_ID", "LOGICAL_LIBRARY", "MOUNT_POLICY", "ACTIVITIES_WEIGHTS", @@ -256,7 +258,7 @@ void DropSchemaCmd::dropOracleCatalogueSchema(rdbms::Conn &conn) { dropDatabaseTables(conn, tablesToDrop); - std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ"}; + std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ", "TAPE_POOL_ID_SEQ"}; dropDatabaseSequences(conn, sequencesToDrop); } catch(exception::Exception &ex) { throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); @@ -291,7 +293,7 @@ void DropSchemaCmd::dropPostgresCatalogueSchema(rdbms::Conn &conn) { dropDatabaseTables(conn, tablesToDrop); - std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ"}; + std::list<std::string> sequencesToDrop = {"ARCHIVE_FILE_ID_SEQ", "STORAGE_CLASS_ID_SEQ", "TAPE_POOL_ID_SEQ"}; dropDatabaseSequences(conn, sequencesToDrop); } catch(exception::Exception &ex) { throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp index e311234a5b48a886a6916168636ded1697c85d6b..e9ed9537327ab5d7e9c5cd5175b3d92077467a4e 100644 --- a/catalogue/DummyCatalogue.hpp +++ b/catalogue/DummyCatalogue.hpp @@ -113,6 +113,7 @@ public: void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbPartialTapes) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& supply) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } + void modifyTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } 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"); } diff --git a/catalogue/MysqlCatalogue.cpp b/catalogue/MysqlCatalogue.cpp index 47de31109f4890f3ff6f2f52950ba267093dbe68..d888963fe0811eab8fb11b6651506e88a30eb92f 100644 --- a/catalogue/MysqlCatalogue.cpp +++ b/catalogue/MysqlCatalogue.cpp @@ -138,46 +138,58 @@ uint64_t MysqlCatalogue::getNextStorageClassId(rdbms::Conn &conn) { } //------------------------------------------------------------------------------ -// selectTapeForUpdate +// getNextTapePoolId //------------------------------------------------------------------------------ -common::dataStructures::Tape MysqlCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) { +uint64_t MysqlCatalogue::getNextTapePoolId(rdbms::Conn &conn) { + try { + rdbms::AutoRollback autoRollback(conn); + + conn.executeNonQuery("START TRANSACTION"); + + { + const char *const sql = + "UPDATE TAPE_POOL_ID SET ID = LAST_INSERT_ID(ID + 1)"; + auto stmt = conn.createStmt(sql); + stmt.executeNonQuery(); + } + + uint64_t tapePoolId = 0; + { + const char *const sql = + "SELECT LAST_INSERT_ID() AS ID "; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("TAPE_POOL_ID table is empty"); + } + tapePoolId = rset.columnUint64("ID"); + if(rset.next()) { + throw exception::Exception("Found more than one ID counter in the TAPE_POOL_ID table"); + } + } + conn.commit(); + + return tapePoolId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// selectTapeForUpdateAndGetLastFSeq +//------------------------------------------------------------------------------ +uint64_t MysqlCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) { try { const char *const sql = "SELECT " - "VID AS VID," - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL_NAME AS TAPE_POOL_NAME," - "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "DATA_IN_BYTES AS DATA_IN_BYTES," - "LAST_FSEQ AS LAST_FSEQ," - "IS_DISABLED AS IS_DISABLED," - "IS_FULL AS IS_FULL," - "IS_READ_ONLY AS IS_READ_ONLY," - "IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "LABEL_DRIVE AS LABEL_DRIVE," - "LABEL_TIME AS LABEL_TIME," - - "LAST_READ_DRIVE AS LAST_READ_DRIVE," - "LAST_READ_TIME AS LAST_READ_TIME," - - "LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "USER_COMMENT AS USER_COMMENT," - - "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "LAST_FSEQ AS LAST_FSEQ " "FROM " - "TAPE " + "TAPE " "WHERE " - "VID = :VID " + "VID = :VID " "FOR UPDATE"; auto stmt = conn.createStmt(sql); stmt.bindString(":VID", vid); @@ -186,45 +198,7 @@ common::dataStructures::Tape MysqlCatalogue::selectTapeForUpdate(rdbms::Conn &co throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); } - common::dataStructures::Tape tape; - - tape.vid = rset.columnString("VID"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.disabled = rset.columnBool("IS_DISABLED"); - tape.full = rset.columnBool("IS_FULL"); - tape.readOnly = rset.columnBool("IS_READ_ONLY"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME"); - tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME"); - tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME"); - - tape.comment = rset.columnString("USER_COMMENT"); - - // std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME"); - - common::dataStructures::EntryLog creationLog; - creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - tape.creationLog = creationLog; - - // std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME"); - - common::dataStructures::EntryLog updateLog; - updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - updateLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - tape.lastModificationLog = updateLog; - - return tape; + return rset.columnUint64("LAST_FSEQ"); } catch(exception::UserError &) { throw; } catch(exception::Exception &ex) { @@ -251,8 +225,8 @@ void MysqlCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> & conn.executeNonQuery("START TRANSACTION"); - const auto tape = selectTapeForUpdate(conn, firstEvent.vid); - uint64_t expectedFSeq = tape.lastFSeq + 1; + const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; uint64_t totalLogicalBytesWritten = 0; for(const auto &eventP: events) { diff --git a/catalogue/MysqlCatalogue.hpp b/catalogue/MysqlCatalogue.hpp index fc743a52425c80a1e64d0955f7a457152c3c9981..1724195fa35647948d3349621e19c4851cfbb3e8 100644 --- a/catalogue/MysqlCatalogue.hpp +++ b/catalogue/MysqlCatalogue.hpp @@ -85,6 +85,20 @@ protected: */ uint64_t getNextStorageClassId(rdbms::Conn &conn) override; + /** + * Returns a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + * + * This method must be implemented by the sub-classes of RdbmsCatalogue + * because different database technologies propose different solution to the + * problem of generating ever increasing numeric identifiers. + * + * @param conn The database connection. + * @return a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + */ + uint64_t getNextTapePoolId(rdbms::Conn &conn) override; + /** * Notifies the catalogue that the specified files have been written to tape. * @@ -124,12 +138,13 @@ private: void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event); /** - * Selects the specified tape within the Tape table for update. + * Selects the specified tape for update and returns its last FSeq. * * @param conn The database connection. * @param vid The volume identifier of the tape. + * @return The last FSeq of the tape. */ - common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid); + uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid); }; // class MysqlCatalogue } // namespace catalogue diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp index 4ee1c1fc2839f454e0a240adf3b5ab9474e6a8e8..00faf9c15e7ed26c9b0d274571cd65dbb797e227 100644 --- a/catalogue/OracleCatalogue.cpp +++ b/catalogue/OracleCatalogue.cpp @@ -203,42 +203,39 @@ uint64_t OracleCatalogue::getNextStorageClassId(rdbms::Conn &conn) { } //------------------------------------------------------------------------------ -// selectTapeForUpdate +// getNextTapePoolId //------------------------------------------------------------------------------ -common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) { +uint64_t OracleCatalogue::getNextTapePoolId(rdbms::Conn &conn) { try { const char *const sql = "SELECT " - "VID AS VID," - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL_NAME AS TAPE_POOL_NAME," - "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "DATA_IN_BYTES AS DATA_IN_BYTES," - "LAST_FSEQ AS LAST_FSEQ," - "IS_DISABLED AS IS_DISABLED," - "IS_FULL AS IS_FULL," - "IS_READ_ONLY AS IS_READ_ONLY," - "IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "LABEL_DRIVE AS LABEL_DRIVE," - "LABEL_TIME AS LABEL_TIME," - - "LAST_READ_DRIVE AS LAST_READ_DRIVE," - "LAST_READ_TIME AS LAST_READ_TIME," - - "LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "USER_COMMENT AS USER_COMMENT," - - "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "TAPE_POOL_ID_SEQ.NEXTVAL AS TAPE_POOL_ID " + "FROM " + "DUAL"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if (!rset.next()) { + throw exception::Exception(std::string("Result set is unexpectedly empty")); + } + + return rset.columnUint64("TAPE_POOL_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// selectTapeForUpdateAndGetLastFSeq +//------------------------------------------------------------------------------ +uint64_t OracleCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, + const std::string &vid) { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " "FROM " "TAPE " "WHERE " @@ -251,45 +248,7 @@ common::dataStructures::Tape OracleCatalogue::selectTapeForUpdate(rdbms::Conn &c throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); } - common::dataStructures::Tape tape; - - tape.vid = rset.columnString("VID"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.disabled = rset.columnBool("IS_DISABLED"); - tape.full = rset.columnBool("IS_FULL"); - tape.readOnly = rset.columnBool("IS_READ_ONLY"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME"); - tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME"); - tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME"); - - tape.comment = rset.columnString("USER_COMMENT"); - - //std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME"); - - common::dataStructures::EntryLog creationLog; - creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - tape.creationLog = creationLog; - - //std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME"); - - common::dataStructures::EntryLog updateLog; - updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - updateLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - tape.lastModificationLog = updateLog; - - return tape; + return rset.columnUint64("LAST_FSEQ"); } catch(exception::UserError &) { throw; } catch(exception::Exception &ex) { @@ -317,8 +276,8 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - const auto tape = selectTapeForUpdate(conn, firstEvent.vid); - uint64_t expectedFSeq = tape.lastFSeq + 1; + const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; uint64_t totalLogicalBytesWritten = 0; uint32_t i = 0; diff --git a/catalogue/OracleCatalogue.hpp b/catalogue/OracleCatalogue.hpp index 0542c7a1881abf6c8beb69553eb859524a4880a2..b6017617ae68bba80313119871c1eb6fda699ab7 100644 --- a/catalogue/OracleCatalogue.hpp +++ b/catalogue/OracleCatalogue.hpp @@ -85,6 +85,20 @@ public: */ uint64_t getNextStorageClassId(rdbms::Conn &conn) override; + /** + * Returns a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + * + * This method must be implemented by the sub-classes of RdbmsCatalogue + * because different database technologies propose different solution to the + * problem of generating ever increasing numeric identifiers. + * + * @param conn The database connection. + * @return a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + */ + uint64_t getNextTapePoolId(rdbms::Conn &conn) override; + /** * Notifies the catalogue that the specified files have been written to tape. * @@ -116,12 +130,13 @@ public: private: /** - * Selects the specified tape within the Tape table for update. + * Selects the specified tape for update and returns its last FSeq. * * @param conn The database connection. * @param vid The volume identifier of the tape. + * @return The last FSeq of the tape. */ - common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid); + uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid); /** * Batch inserts rows into the ARCHIVE_FILE table that correspond to the diff --git a/catalogue/PostgresCatalogue.cpp b/catalogue/PostgresCatalogue.cpp index 8feba18264d8ac31c255bd5d9062e5fd4f232755..921b2d265a577674e89d37d86aefbd9b4583b8f9 100644 --- a/catalogue/PostgresCatalogue.cpp +++ b/catalogue/PostgresCatalogue.cpp @@ -193,42 +193,34 @@ uint64_t PostgresCatalogue::getNextStorageClassId(rdbms::Conn &conn) { } //------------------------------------------------------------------------------ -// selectTapeForUpdate +// getNextTapePoolId //------------------------------------------------------------------------------ -common::dataStructures::Tape PostgresCatalogue::selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) const { +uint64_t PostgresCatalogue::getNextTapePoolId(rdbms::Conn &conn) { + try { + const char *const sql = + "select NEXTVAL('TAPE_POOL_ID_SEQ') AS TAPE_POOL_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("TAPE_POOL_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// selectTapeForUpdateAndGetNextFSeq +//------------------------------------------------------------------------------ +uint64_t PostgresCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const { try { const char *const sql = "SELECT " - "VID AS VID," - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL_NAME AS TAPE_POOL_NAME," - "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "DATA_IN_BYTES AS DATA_IN_BYTES," - "LAST_FSEQ AS LAST_FSEQ," - "IS_DISABLED AS IS_DISABLED," - "IS_FULL AS IS_FULL," - "IS_READ_ONLY AS IS_READ_ONLY," - "IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "LABEL_DRIVE AS LABEL_DRIVE," - "LABEL_TIME AS LABEL_TIME," - - "LAST_READ_DRIVE AS LAST_READ_DRIVE," - "LAST_READ_TIME AS LAST_READ_TIME," - - "LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "USER_COMMENT AS USER_COMMENT," - - "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "LAST_FSEQ AS LAST_FSEQ " "FROM " "TAPE " "WHERE " @@ -241,47 +233,7 @@ common::dataStructures::Tape PostgresCatalogue::selectTapeForUpdate(rdbms::Conn throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); } - common::dataStructures::Tape tape; - - tape.vid = rset.columnString("VID"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.disabled = rset.columnBool("IS_DISABLED"); - tape.full = rset.columnBool("IS_FULL"); - tape.readOnly = rset.columnBool("IS_READ_ONLY"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME"); - tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME"); - tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME"); - - tape.comment = rset.columnString("USER_COMMENT"); - - //std::string creatorUIname = rset.columnString("CREATION_LOG_USER_NAME"); - - common::dataStructures::EntryLog creationLog; - creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - tape.creationLog = creationLog; - - //std::string updaterUIname = rset.columnString("LAST_UPDATE_USER_NAME"); - - common::dataStructures::EntryLog updateLog; - updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - updateLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - tape.lastModificationLog = updateLog; - - return tape; - } catch(exception::UserError &) { - throw; + return rset.columnUint64("LAST_FSEQ"); } catch(exception::Exception &ex) { ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); throw; @@ -310,8 +262,8 @@ void PostgresCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer // to avoid violation in the case of concurrent inserts of a previously not existing archive file. beginCreateTemporarySetDeferred(conn); - const auto tape = selectTapeForUpdate(conn, firstEvent.vid); - uint64_t expectedFSeq = tape.lastFSeq + 1; + const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; uint64_t totalLogicalBytesWritten = 0; // We have a mix of files and items. Only files will be recorded, but items diff --git a/catalogue/PostgresCatalogue.hpp b/catalogue/PostgresCatalogue.hpp index 9fa3be58765c053de43218476cb5c43b50767646..b7320784d853861e391061a63c4afc6c5ae2c9db 100644 --- a/catalogue/PostgresCatalogue.hpp +++ b/catalogue/PostgresCatalogue.hpp @@ -111,6 +111,19 @@ public: */ uint64_t getNextStorageClassId(rdbms::Conn &conn) override; + /** + * Returns a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + * + * This method must be implemented by the sub-classes of RdbmsCatalogue + * because different database technologies propose different solution to the + * problem of generating ever increasing numeric identifiers. + * + * @param conn The database connection. + * @return a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + */ + uint64_t getNextTapePoolId(rdbms::Conn &conn) override; private: @@ -125,12 +138,13 @@ private: void beginCreateTemporarySetDeferred(rdbms::Conn &conn) const; /** - * Selects the specified tape within the Tape table for update. + * Selects the specified tape for update and returns its last FSeq. * * @param conn The database connection. * @param vid The volume identifier of the tape. + * @param The last FSeq of the tape. */ - common::dataStructures::Tape selectTapeForUpdate(rdbms::Conn &conn, const std::string &vid) const; + uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const; /** * Batch inserts rows into the ARCHIVE_FILE table that correspond to the diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp index bddf5bd7200a6fef4e0ed4fc503b1d5bb5409550..6e26769b09c9f2028fab441b09994fcf27b1736b 100644 --- a/catalogue/RdbmsCatalogue.cpp +++ b/catalogue/RdbmsCatalogue.cpp @@ -707,9 +707,11 @@ void RdbmsCatalogue::createTapePool( throw exception::UserError(std::string("Cannot create tape pool ") + name + " because a tape pool with the same name already exists"); } + const uint64_t tapePoolId = getNextTapePoolId(conn); const time_t now = time(nullptr); const char *const sql = "INSERT INTO TAPE_POOL(" + "TAPE_POOL_ID," "TAPE_POOL_NAME," "VO," "NB_PARTIAL_TAPES," @@ -726,6 +728,7 @@ void RdbmsCatalogue::createTapePool( "LAST_UPDATE_HOST_NAME," "LAST_UPDATE_TIME)" "VALUES(" + ":TAPE_POOL_ID," ":TAPE_POOL_NAME," ":VO," ":NB_PARTIAL_TAPES," @@ -743,6 +746,7 @@ void RdbmsCatalogue::createTapePool( ":LAST_UPDATE_TIME)"; auto stmt = conn.createStmt(sql); + stmt.bindUint64(":TAPE_POOL_ID", tapePoolId); stmt.bindString(":TAPE_POOL_NAME", name); stmt.bindString(":VO", vo); stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes); @@ -1034,7 +1038,7 @@ std::list<TapePool> RdbmsCatalogue::getTapePools() const { "FROM " "TAPE_POOL " "LEFT OUTER JOIN TAPE ON " - "TAPE_POOL.TAPE_POOL_NAME = TAPE.TAPE_POOL_NAME " + "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID " "GROUP BY " "TAPE_POOL.TAPE_POOL_NAME," "TAPE_POOL.VO," @@ -1294,6 +1298,50 @@ void RdbmsCatalogue::modifyTapePoolSupply(const common::dataStructures::Security } } +//------------------------------------------------------------------------------ +// modifyTapePoolName +//------------------------------------------------------------------------------ +void RdbmsCatalogue::modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + try { + if(currentName.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + if(newName.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the new name is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "TAPE_POOL_NAME = :NEW_TAPE_POOL_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "TAPE_POOL_NAME = :CURRENT_TAPE_POOL_NAME"; + auto conn = m_connPool.getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":NEW_TAPE_POOL_NAME", newName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":CURRENT_TAPE_POOL_NAME", currentName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + currentName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + //------------------------------------------------------------------------------ // createArchiveRoute //------------------------------------------------------------------------------ @@ -1350,7 +1398,7 @@ void RdbmsCatalogue::createArchiveRoute( "INSERT INTO ARCHIVE_ROUTE(" "STORAGE_CLASS_ID," "COPY_NB," - "TAPE_POOL_NAME," + "TAPE_POOL_ID," "USER_COMMENT," @@ -1364,7 +1412,7 @@ void RdbmsCatalogue::createArchiveRoute( "SELECT " "STORAGE_CLASS_ID," ":COPY_NB," - ":TAPE_POOL_NAME," + "(SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME) AS TAPE_POOL_ID," ":USER_COMMENT," @@ -1457,7 +1505,7 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes "STORAGE_CLASS.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," - "ARCHIVE_ROUTE.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT," @@ -1472,6 +1520,8 @@ std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes "ARCHIVE_ROUTE " "INNER JOIN STORAGE_CLASS ON " "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_POOL ON " + "ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " "ORDER BY " "DISK_INSTANCE_NAME, STORAGE_CLASS_NAME, COPY_NB"; auto conn = m_connPool.getConn(); @@ -1514,7 +1564,7 @@ void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures const time_t now = time(nullptr); const char *const sql = "UPDATE ARCHIVE_ROUTE SET " - "TAPE_POOL_NAME = :TAPE_POOL_NAME," + "TAPE_POOL_ID = (SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME)," "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " @@ -1542,7 +1592,7 @@ void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures if(0 == stmt.getNbAffectedRows()) { exception::UserError ue; ue.getMessage() << "Cannot modify archive route for storage-class " << instanceName + ":" + storageClassName + - " and copy number " << copyNb << " because it does not exist"; + " and copy number " << copyNb << " because either it or tape pool " + tapePoolName + " does not exist"; throw ue; } } catch(exception::UserError &) { @@ -1912,59 +1962,62 @@ void RdbmsCatalogue::createTape( } const time_t now = time(nullptr); const char *const sql = - "INSERT INTO TAPE(" - "VID," - "MEDIA_TYPE," - "VENDOR," - "LOGICAL_LIBRARY_NAME," - "TAPE_POOL_NAME," - "CAPACITY_IN_BYTES," - "DATA_IN_BYTES," - "LAST_FSEQ," - "IS_DISABLED," - "IS_FULL," - "IS_READ_ONLY," - "IS_FROM_CASTOR," - - "USER_COMMENT," - - "CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME)" - "VALUES(" - ":VID," - ":MEDIA_TYPE," - ":VENDOR," - ":LOGICAL_LIBRARY_NAME," - ":TAPE_POOL_NAME," - ":CAPACITY_IN_BYTES," - ":DATA_IN_BYTES," - ":LAST_FSEQ," - ":IS_DISABLED," - ":IS_FULL," - ":IS_READ_ONLY," - ":IS_FROM_CASTOR," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; + "INSERT INTO TAPE(" "\n" + "VID," "\n" + "MEDIA_TYPE," "\n" + "VENDOR," "\n" + "LOGICAL_LIBRARY_NAME," "\n" + "TAPE_POOL_ID," "\n" + "CAPACITY_IN_BYTES," "\n" + "DATA_IN_BYTES," "\n" + "LAST_FSEQ," "\n" + "IS_DISABLED," "\n" + "IS_FULL," "\n" + "IS_READ_ONLY," "\n" + "IS_FROM_CASTOR," "\n" + + "USER_COMMENT," "\n" + + "CREATION_LOG_USER_NAME," "\n" + "CREATION_LOG_HOST_NAME," "\n" + "CREATION_LOG_TIME," "\n" + + "LAST_UPDATE_USER_NAME," "\n" + "LAST_UPDATE_HOST_NAME," "\n" + "LAST_UPDATE_TIME)" "\n" + "SELECT" "\n" + ":VID," "\n" + ":MEDIA_TYPE," "\n" + ":VENDOR," "\n" + ":LOGICAL_LIBRARY_NAME," "\n" + "TAPE_POOL_ID," "\n" + ":CAPACITY_IN_BYTES," "\n" + ":DATA_IN_BYTES," "\n" + ":LAST_FSEQ," "\n" + ":IS_DISABLED," "\n" + ":IS_FULL," "\n" + ":IS_READ_ONLY," "\n" + ":IS_FROM_CASTOR," "\n" + + ":USER_COMMENT," "\n" + + ":CREATION_LOG_USER_NAME," "\n" + ":CREATION_LOG_HOST_NAME," "\n" + ":CREATION_LOG_TIME," "\n" + + ":LAST_UPDATE_USER_NAME," "\n" + ":LAST_UPDATE_HOST_NAME," "\n" + ":LAST_UPDATE_TIME" "\n" + "FROM " + "TAPE_POOL " "\n" + "WHERE " "\n" + "TAPE_POOL_NAME = :TAPE_POOL_NAME"; auto stmt = conn.createStmt(sql); stmt.bindString(":VID", vid); stmt.bindString(":MEDIA_TYPE", mediaType); stmt.bindString(":VENDOR", vendor); stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes); stmt.bindUint64(":DATA_IN_BYTES", 0); stmt.bindUint64(":LAST_FSEQ", 0); @@ -1983,6 +2036,8 @@ void RdbmsCatalogue::createTape( stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + stmt.executeNonQuery(); log::LogContext lc(m_log); @@ -2158,7 +2213,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co "TAPE.MEDIA_TYPE AS MEDIA_TYPE," "TAPE.VENDOR AS VENDOR," "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "TAPE_POOL.VO AS VO," "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," @@ -2193,7 +2248,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co "FROM " "TAPE " "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME"; + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; if(searchCriteria.vid || searchCriteria.mediaType || @@ -2231,7 +2286,7 @@ std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &co } if(searchCriteria.tapePool) { if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + sql += " TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; addedAWhereConstraint = true; } if(searchCriteria.vo) { @@ -2333,7 +2388,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se "TAPE.MEDIA_TYPE AS MEDIA_TYPE," "TAPE.VENDOR AS VENDOR," "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "TAPE_POOL.VO AS VO," "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," @@ -2368,7 +2423,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::se "FROM " "TAPE " "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME"; + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; if(!vids.empty()) { sql += " WHERE "; @@ -2459,7 +2514,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getAllTapes() const { "TAPE.MEDIA_TYPE AS MEDIA_TYPE," "TAPE.VENDOR AS VENDOR," "TAPE.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "TAPE_POOL.VO AS VO," "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," @@ -2494,7 +2549,7 @@ common::dataStructures::VidToTapeMap RdbmsCatalogue::getAllTapes() const { "FROM " "TAPE " "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME"; + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; auto conn = m_connPool.getConn(); auto stmt = conn.createStmt(sql); @@ -2860,7 +2915,8 @@ void RdbmsCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures:: stmt.executeNonQuery(); if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or logical library " + + logicalLibraryName + " does not exist"); } log::LogContext lc(m_log); @@ -2888,7 +2944,7 @@ void RdbmsCatalogue::modifyTapeTapePoolName(const common::dataStructures::Securi const time_t now = time(nullptr); const char *const sql = "UPDATE TAPE SET " - "TAPE_POOL_NAME = :TAPE_POOL_NAME," + "TAPE_POOL_ID = (SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME)," "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " @@ -5375,7 +5431,7 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," "TAPE_FILE.SUPERSEDED_BY_VID AS SSBY_VID," "TAPE_FILE.SUPERSEDED_BY_FSEQ AS SSBY_FSEQ," - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " "FROM " "ARCHIVE_FILE " "INNER JOIN STORAGE_CLASS ON " @@ -5384,10 +5440,12 @@ std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " "INNER JOIN TAPE ON " "TAPE_FILE.VID = TAPE.VID " - "WHERE " - "TAPE_FILE.VID = :VID AND " - "TAPE_FILE.FSEQ >= :START_FSEQ AND " - "TAPE_FILE.SUPERSEDED_BY_VID IS NULL " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "WHERE " + "TAPE_FILE.VID = :VID AND " + "TAPE_FILE.FSEQ >= :START_FSEQ AND " + "TAPE_FILE.SUPERSEDED_BY_VID IS NULL " "ORDER BY FSEQ"; auto conn = m_connPool.getConn(); @@ -5472,7 +5530,9 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary( "INNER JOIN TAPE_FILE ON " "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID"; + "TAPE_FILE.VID = TAPE.VID " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; if( searchCriteria.archiveFileId || @@ -5536,7 +5596,7 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary( } if(searchCriteria.tapePool) { if(addedAWhereConstraint) sql += " AND "; - sql += "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + sql += "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; } auto conn = m_connPool.getConn(); @@ -5770,11 +5830,13 @@ common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(r const char *const sql = "SELECT " "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," - "ARCHIVE_ROUTE.TAPE_POOL_NAME AS TAPE_POOL_NAME " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " "FROM " "ARCHIVE_ROUTE " "INNER JOIN STORAGE_CLASS ON " "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_POOL ON " + "ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " "WHERE " "STORAGE_CLASS.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; @@ -6125,7 +6187,7 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string & "TAPE.VID AS VID," "TAPE.MEDIA_TYPE AS MEDIA_TYPE," "TAPE.VENDOR AS VENDOR," - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "TAPE_POOL.VO AS VO," "TAPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," @@ -6133,7 +6195,7 @@ std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string & "FROM " "TAPE " "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_NAME = TAPE_POOL.TAPE_POOL_NAME " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " "WHERE " // "LABEL_DRIVE IS NOT NULL AND " // Set when the tape has been labelled // "LABEL_TIME IS NOT NULL AND " // Set when the tape has been labelled @@ -6819,8 +6881,10 @@ uint64_t RdbmsCatalogue::getNbTapesInPool(rdbms::Conn &conn, const std::string & "COUNT(*) AS NB_TAPES " "FROM " "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " "WHERE " - "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; auto stmt = conn.createStmt(sql); stmt.bindString(":TAPE_POOL_NAME", name); auto rset = stmt.executeQuery(); diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp index 7afcd87fc06ac31599608ad39b62bb252932a14f..8b9e43720557db5fc946e1deafce1501ec3a9912 100644 --- a/catalogue/RdbmsCatalogue.hpp +++ b/catalogue/RdbmsCatalogue.hpp @@ -255,6 +255,15 @@ public: void setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool encryptionValue) override; void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &supply) override; + /** + * Modifies the name of the specified tape pool. + * + * @param admin The administrator. + * @param currentName The current name of the tape pool. + * @param newName The new name of the tape pool. + */ + void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; + void createArchiveRoute( const common::dataStructures::SecurityIdentity &admin, const std::string &diskInstanceName, @@ -1340,6 +1349,20 @@ protected: */ virtual uint64_t getNextStorageClassId(rdbms::Conn &conn) = 0; + /** + * Returns a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + * + * This method must be implemented by the sub-classes of RdbmsCatalogue + * because different database technologies propose different solution to the + * problem of generating ever increasing numeric identifiers. + * + * @param conn The database connection. + * @return a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + */ + virtual uint64_t getNextTapePoolId(rdbms::Conn &conn) = 0; + /** * Returns a cached version of the mapping from tape copy to tape pool for the * specified storage class. diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp b/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp index 5857695308921701d8d93b6ab39a5e7382573176..2a0d38ea120313f6693024101187d5589d3bd159 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp +++ b/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp @@ -113,7 +113,7 @@ RdbmsCatalogueGetArchiveFilesForRepackItor::RdbmsCatalogueGetArchiveFilesForRepa "TAPE_COPY.CREATION_TIME AS TAPE_FILE_CREATION_TIME, " "TAPE_COPY.SUPERSEDED_BY_VID AS SUPERSEDED_BY_VID, " "TAPE_COPY.SUPERSEDED_BY_FSEQ AS SUPERSEDED_BY_FSEQ, " - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " "FROM " "TAPE_FILE REPACK_TAPE " "INNER JOIN TAPE_FILE TAPE_COPY ON " @@ -124,6 +124,8 @@ RdbmsCatalogueGetArchiveFilesForRepackItor::RdbmsCatalogueGetArchiveFilesForRepa "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " "INNER JOIN TAPE ON " "TAPE_COPY.VID = TAPE.VID " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " "WHERE " "REPACK_TAPE.VID = :VID " "AND " diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp b/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp index acaa6c8023ed19f6f1ac213e6224eec15b99ae63..b988534b78aa41ccf69e3fe2ad7ade1703fe405c 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp +++ b/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp @@ -109,7 +109,7 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor( "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME, " "TAPE_FILE.SUPERSEDED_BY_VID AS SUPERSEDED_BY_VID, " "TAPE_FILE.SUPERSEDED_BY_FSEQ AS SUPERSEDED_BY_FSEQ, " - "TAPE.TAPE_POOL_NAME AS TAPE_POOL_NAME " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " "FROM " "ARCHIVE_FILE " "INNER JOIN STORAGE_CLASS ON " @@ -117,7 +117,9 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor( "LEFT OUTER JOIN TAPE_FILE ON " "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " "LEFT OUTER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID"; + "TAPE_FILE.VID = TAPE.VID " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; const bool thereIsAtLeastOneSearchCriteria = searchCriteria.archiveFileId || @@ -183,7 +185,7 @@ RdbmsCatalogueGetArchiveFilesItor::RdbmsCatalogueGetArchiveFilesItor( } if(searchCriteria.tapePool) { if(addedAWhereConstraint) sql += " AND "; - sql += "TAPE.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + sql += "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; } // Order by FSEQ if we are listing the contents of a tape, else order by diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp index 978778d18c2c995aeb8fd9250f235b83d6522025..ab9f955486b2de5c4ea3835d8ed220901413746c 100644 --- a/catalogue/SqliteCatalogue.cpp +++ b/catalogue/SqliteCatalogue.cpp @@ -241,42 +241,43 @@ uint64_t SqliteCatalogue::getNextStorageClassId(rdbms::Conn &conn) { } //------------------------------------------------------------------------------ -// selectTape +// getNextTapePoolId //------------------------------------------------------------------------------ -common::dataStructures::Tape SqliteCatalogue::selectTape(rdbms::Conn &conn, const std::string &vid) { +uint64_t SqliteCatalogue::getNextTapePoolId(rdbms::Conn &conn) { + try { + conn.executeNonQuery("INSERT INTO TAPE_POOL_ID VALUES(NULL)"); + uint64_t tapePoolId = 0; + { + const char *const sql = "SELECT LAST_INSERT_ROWID() AS ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception(std::string("Unexpected empty result set for '") + sql + "\'"); + } + tapePoolId = rset.columnUint64("ID"); + if(rset.next()) { + throw exception::Exception(std::string("Unexpectedly found more than one row in the result of '") + sql + "\'"); + } + } + conn.executeNonQuery("DELETE FROM TAPE_POOL_ID"); + + return tapePoolId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getTapeLastFSeq +//------------------------------------------------------------------------------ +uint64_t SqliteCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) { try { const char *const sql = "SELECT " - "VID AS VID," - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL_NAME AS TAPE_POOL_NAME," - "ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "DATA_IN_BYTES AS DATA_IN_BYTES," - "LAST_FSEQ AS LAST_FSEQ," - "IS_DISABLED AS IS_DISABLED," - "IS_FULL AS IS_FULL," - "IS_READ_ONLY AS IS_READ_ONLY," - "IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "LABEL_DRIVE AS LABEL_DRIVE," - "LABEL_TIME AS LABEL_TIME," - - "LAST_READ_DRIVE AS LAST_READ_DRIVE," - "LAST_READ_TIME AS LAST_READ_TIME," - - "LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "USER_COMMENT AS USER_COMMENT," - - "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "LAST_FSEQ AS LAST_FSEQ " "FROM " "TAPE " "WHERE " @@ -289,49 +290,7 @@ common::dataStructures::Tape SqliteCatalogue::selectTape(rdbms::Conn &conn, cons throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); } - common::dataStructures::Tape tape; - - tape.vid = rset.columnString("VID"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.disabled = rset.columnBool("IS_DISABLED"); - tape.full = rset.columnBool("IS_FULL"); - tape.readOnly = rset.columnBool("IS_READ_ONLY"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelLog = getTapeLogFromRset(rset, "LABEL_DRIVE", "LABEL_TIME"); - tape.lastReadLog = getTapeLogFromRset(rset, "LAST_READ_DRIVE", "LAST_READ_TIME"); - tape.lastWriteLog = getTapeLogFromRset(rset, "LAST_WRITE_DRIVE", "LAST_WRITE_TIME"); - - tape.comment = rset.columnString("USER_COMMENT"); - - common::dataStructures::RequesterIdentity creatorUI; - creatorUI.name = rset.columnString("CREATION_LOG_USER_NAME"); - - common::dataStructures::EntryLog creationLog; - creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - tape.creationLog = creationLog; - - common::dataStructures::RequesterIdentity updaterUI; - updaterUI.name = rset.columnString("LAST_UPDATE_USER_NAME"); - - common::dataStructures::EntryLog updateLog; - updateLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - updateLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - updateLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - tape.lastModificationLog = updateLog; - - return tape; - } catch(exception::UserError &) { - throw; + return rset.columnUint64("LAST_FSEQ"); } catch(exception::Exception &ex) { ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); throw; @@ -360,8 +319,8 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> threading::MutexLocker locker(m_mutex); auto conn = m_connPool.getConn(); - const auto tape = selectTape(conn, firstEvent.vid); - uint64_t expectedFSeq = tape.lastFSeq + 1; + const uint64_t lastFSeq = getTapeLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; uint64_t totalLogicalBytesWritten = 0; for(const auto &eventP: events) { diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp index 5446e0b8d6d425178c5b11fa51257e654b7176c6..65eff32c6834a53cf1215889f4c066e1a19bed50 100644 --- a/catalogue/SqliteCatalogue.hpp +++ b/catalogue/SqliteCatalogue.hpp @@ -114,6 +114,20 @@ protected: */ uint64_t getNextStorageClassId(rdbms::Conn &conn) override; + /** + * Returns a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + * + * This method must be implemented by the sub-classes of RdbmsCatalogue + * because different database technologies propose different solution to the + * problem of generating ever increasing numeric identifiers. + * + * @param conn The database connection. + * @return a unique tape pool ID that can be used by a new tape pool within + * the catalogue. + */ + uint64_t getNextTapePoolId(rdbms::Conn &conn) override; + /** * Notifies the catalogue that the specified files have been written to tape. * @@ -132,12 +146,13 @@ private: void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event); /** - * Selects the specified tape within the Tape table. + * Gets the last FSeq of the specified tape. * * @param conn The database connection. * @param vid The volume identifier of the tape. + * @return The last FSeq of the tape. */ - common::dataStructures::Tape selectTape(rdbms::Conn &conn, const std::string &vid); + uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid); }; // class SqliteCatalogue diff --git a/catalogue/common_catalogue_schema.sql b/catalogue/common_catalogue_schema.sql index 37d2d22298149102baf451424059a15fae1d6d3e..d5cdb26b921ae71326ec17be0b7f7946c36bf8f0 100644 --- a/catalogue/common_catalogue_schema.sql +++ b/catalogue/common_catalogue_schema.sql @@ -45,6 +45,7 @@ CREATE TABLE STORAGE_CLASS( CONSTRAINT STORAGE_CLASS_DIN_SCN_UN UNIQUE(DISK_INSTANCE_NAME, STORAGE_CLASS_NAME) ); CREATE TABLE TAPE_POOL( + TAPE_POOL_ID UINT64TYPE CONSTRAINT TAPE_POOL_TPI_NN NOT NULL, TAPE_POOL_NAME VARCHAR(100) CONSTRAINT TAPE_POOL_TPN_NN NOT NULL, VO VARCHAR(100) CONSTRAINT TAPE_POOL_VO_NN NOT NULL, NB_PARTIAL_TAPES UINT64TYPE CONSTRAINT TAPE_POOL_NPT_NN NOT NULL, @@ -57,13 +58,14 @@ CREATE TABLE TAPE_POOL( LAST_UPDATE_USER_NAME VARCHAR(100) CONSTRAINT TAPE_POOL_LUUN_NN NOT NULL, LAST_UPDATE_HOST_NAME VARCHAR(100) CONSTRAINT TAPE_POOL_LUHN_NN NOT NULL, LAST_UPDATE_TIME UINT64TYPE CONSTRAINT TAPE_POOL_LUT_NN NOT NULL, - CONSTRAINT TAPE_POOL_PK PRIMARY KEY(TAPE_POOL_NAME), + CONSTRAINT TAPE_POOL_PK PRIMARY KEY(TAPE_POOL_ID), + CONSTRAINT TAPE_POOL_TPN_UN UNIQUE(TAPE_POOL_NAME), CONSTRAINT TAPE_POOL_IS_ENCRYPTED_BOOL_CK CHECK(IS_ENCRYPTED IN ('0', '1')) ); CREATE TABLE ARCHIVE_ROUTE( STORAGE_CLASS_ID UINT64TYPE CONSTRAINT ARCHIVE_ROUTE_SCI_NN NOT NULL, COPY_NB UINT64TYPE CONSTRAINT ARCHIVE_ROUTE_CN_NN NOT NULL, - TAPE_POOL_NAME VARCHAR(100) CONSTRAINT ARCHIVE_ROUTE_TPN_NN NOT NULL, + TAPE_POOL_ID UINT64TYPE CONSTRAINT ARCHIVE_ROUTE_TPI_NN NOT NULL, USER_COMMENT VARCHAR(1000) CONSTRAINT ARCHIVE_ROUTE_UC_NN NOT NULL, CREATION_LOG_USER_NAME VARCHAR(100) CONSTRAINT ARCHIVE_ROUTE_CLUN_NN NOT NULL, CREATION_LOG_HOST_NAME VARCHAR(100) CONSTRAINT ARCHIVE_ROUTE_CLHN_NN NOT NULL, @@ -73,8 +75,7 @@ CREATE TABLE ARCHIVE_ROUTE( LAST_UPDATE_TIME UINT64TYPE CONSTRAINT ARCHIVE_ROUTE_LUT_NN NOT NULL, CONSTRAINT ARCHIVE_ROUTE_PK PRIMARY KEY(STORAGE_CLASS_ID, COPY_NB), CONSTRAINT ARCHIVE_ROUTE_STORAGE_CLASS_FK FOREIGN KEY(STORAGE_CLASS_ID) REFERENCES STORAGE_CLASS(STORAGE_CLASS_ID), - CONSTRAINT ARCHIVE_ROUTE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_NAME) - REFERENCES TAPE_POOL(TAPE_POOL_NAME), + CONSTRAINT ARCHIVE_ROUTE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_ID) REFERENCES TAPE_POOL(TAPE_POOL_ID), CONSTRAINT ARCHIVE_ROUTE_COPY_NB_GT_ZERO CHECK(COPY_NB > 0) ); CREATE TABLE LOGICAL_LIBRARY( @@ -95,7 +96,7 @@ CREATE TABLE TAPE( MEDIA_TYPE VARCHAR(100) CONSTRAINT TAPE_MT_NN NOT NULL, VENDOR VARCHAR(100) CONSTRAINT TAPE_V2_NN NOT NULL, LOGICAL_LIBRARY_NAME VARCHAR(100) CONSTRAINT TAPE_LLN_NN NOT NULL, - TAPE_POOL_NAME VARCHAR(100) CONSTRAINT TAPE_TPN_NN NOT NULL, + TAPE_POOL_ID UINT64TYPE CONSTRAINT TAPE_TPI_NN NOT NULL, ENCRYPTION_KEY_NAME VARCHAR(100), CAPACITY_IN_BYTES UINT64TYPE CONSTRAINT TAPE_CIB_NN NOT NULL, DATA_IN_BYTES UINT64TYPE CONSTRAINT TAPE_DIB_NN NOT NULL, @@ -122,14 +123,13 @@ CREATE TABLE TAPE( CONSTRAINT TAPE_PK PRIMARY KEY(VID), CONSTRAINT TAPE_LOGICAL_LIBRARY_FK FOREIGN KEY(LOGICAL_LIBRARY_NAME) REFERENCES LOGICAL_LIBRARY(LOGICAL_LIBRARY_NAME), - CONSTRAINT TAPE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_NAME) - REFERENCES TAPE_POOL(TAPE_POOL_NAME), + CONSTRAINT TAPE_TAPE_POOL_FK FOREIGN KEY(TAPE_POOL_ID) REFERENCES TAPE_POOL(TAPE_POOL_ID), CONSTRAINT TAPE_IS_DISABLED_BOOL_CK CHECK(IS_DISABLED IN ('0', '1')), CONSTRAINT TAPE_IS_FULL_BOOL_CK CHECK(IS_FULL IN ('0', '1')), CONSTRAINT TAPE_IS_READ_ONLY_BOOL_CK CHECK(IS_READ_ONLY IN ('0', '1')), CONSTRAINT TAPE_IS_FROM_CASTOR_BOOL_CK CHECK(IS_FROM_CASTOR IN ('0', '1')) ); -CREATE INDEX TAPE_TAPE_POOL_NAME_IDX ON TAPE(TAPE_POOL_NAME); +CREATE INDEX TAPE_TAPE_POOL_ID_IDX ON TAPE(TAPE_POOL_ID); CREATE TABLE MOUNT_POLICY( MOUNT_POLICY_NAME VARCHAR(100) CONSTRAINT MOUNT_POLICY_MPN_NN NOT NULL, ARCHIVE_PRIORITY UINT64TYPE CONSTRAINT MOUNT_POLICY_AP_NN NOT NULL, diff --git a/catalogue/mysql_catalogue_schema_header.sql b/catalogue/mysql_catalogue_schema_header.sql index fc069549a2e0980ba50e9536ea5183c3e40380f9..70a7cb314e9c7205fcc387aec79a0bb60266894d 100644 --- a/catalogue/mysql_catalogue_schema_header.sql +++ b/catalogue/mysql_catalogue_schema_header.sql @@ -8,3 +8,9 @@ CREATE TABLE STORAGE_CLASS_ID( CONSTRAINT STORAGE_CLASS_ID_PK PRIMARY KEY(ID) ); INSERT INTO STORAGE_CLASS_ID(ID) VALUES(1); +CREATE TABLE TAPE_POOL_ID( + ID UINT64TYPE, + CONSTRAINT TAPE_POOL_ID_PK PRIMARY KEY(ID) +); +INSERT INTO TAPE_POOL_ID(ID) VALUES(1); + diff --git a/catalogue/oracle_catalogue_schema_header.sql b/catalogue/oracle_catalogue_schema_header.sql index b4038762e069b499409813110459e9da2b521f6c..f3345ec826663234eadbfa4c9a9bc5d3edb049a0 100644 --- a/catalogue/oracle_catalogue_schema_header.sql +++ b/catalogue/oracle_catalogue_schema_header.sql @@ -14,6 +14,14 @@ CREATE SEQUENCE STORAGE_CLASS_ID_SEQ NOCYCLE CACHE 20 NOORDER; +CREATE SEQUENCE TAPE_POOL_ID_SEQ + INCREMENT BY 1 + START WITH 4294967296 + NOMAXVALUE + MINVALUE 1 + NOCYCLE + CACHE 20 + NOORDER; CREATE GLOBAL TEMPORARY TABLE TEMP_TAPE_FILE_INSERTION_BATCH( VID VARCHAR(100), FSEQ UINT64TYPE , diff --git a/catalogue/postgres_catalogue_schema_header.sql b/catalogue/postgres_catalogue_schema_header.sql index c46162e86fb2108df0c916183eb1c6978848c868..1ec5a948cfe57393783a9658eb1a2f6c981f2ca6 100644 --- a/catalogue/postgres_catalogue_schema_header.sql +++ b/catalogue/postgres_catalogue_schema_header.sql @@ -12,3 +12,10 @@ CREATE SEQUENCE STORAGE_CLASS_ID_SEQ MINVALUE 1 NO CYCLE CACHE 20; +CREATE SEQUENCE TAPE_POOL_ID_SEQ + INCREMENT BY 1 + START WITH 1 + NO MAXVALUE + MINVALUE 1 + NO CYCLE + CACHE 20; diff --git a/catalogue/sqlite_catalogue_schema_header.sql b/catalogue/sqlite_catalogue_schema_header.sql index 58e697395870faa928cfb2c1894f0365d935980d..d8135792875d81d5ac864d7a7b6860b06ab815f6 100644 --- a/catalogue/sqlite_catalogue_schema_header.sql +++ b/catalogue/sqlite_catalogue_schema_header.sql @@ -4,3 +4,6 @@ CREATE TABLE ARCHIVE_FILE_ID( CREATE TABLE STORAGE_CLASS_ID( ID INTEGER PRIMARY KEY AUTOINCREMENT ); +CREATE TABLE TAPE_POOL_ID( + ID INTEGER PRIMARY KEY AUTOINCREMENT +);