diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 2cfab53283bbe976dc1a8ed9e48edb951723fab1..7bdf5c98e7a31b5df7139408362cf69d9e7f0553 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -3,6 +3,7 @@ ## Summary ### Features + - cta/CTA#1016 New options for filtering deleted files using `cta-admin rtf ls` command. ### Bug fixes diff --git a/catalogue/CatalogueTest.cpp b/catalogue/CatalogueTest.cpp index 22939e944fbe61000fc875207809b65c88f23447..8130a34a02627b8fde1bc6418013e988655bdc73 100644 --- a/catalogue/CatalogueTest.cpp +++ b/catalogue/CatalogueTest.cpp @@ -15653,7 +15653,8 @@ TEST_P(cta_catalogue_CatalogueTest, filesArePutInTheFileRecycleLogInsteadOfBeing //Check the diskFileId search criteria std::string diskFileId = "12345678"; catalogue::RecycleTapeFileSearchCriteria criteria; - criteria.diskFileId = diskFileId; + criteria.diskFileIds = std::vector<std::string>(); + criteria.diskFileIds->push_back(diskFileId); auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); ASSERT_TRUE(fileRecycleLogItor.hasMore()); auto fileRecycleLog = fileRecycleLogItor.next(); @@ -15664,10 +15665,80 @@ TEST_P(cta_catalogue_CatalogueTest, filesArePutInTheFileRecycleLogInsteadOfBeing //Check the non existing diskFileId search criteria std::string diskFileId = "DOES_NOT_EXIST"; catalogue::RecycleTapeFileSearchCriteria criteria; - criteria.diskFileId = diskFileId; + criteria.diskFileIds = std::vector<std::string>(); + criteria.diskFileIds->push_back(diskFileId); auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); ASSERT_FALSE(fileRecycleLogItor.hasMore()); } + { + //Check the archiveID search criteria + uint64_t archiveFileId = 1; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.archiveFileId = archiveFileId; + auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + auto fileRecycleLog = fileRecycleLogItor.next(); + ASSERT_EQ(archiveFileId,fileRecycleLog.archiveFileId); + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + } + { + //Check the non existing archiveFileId search criteria + uint64_t archiveFileId = -1; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.archiveFileId = archiveFileId; + auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + } + { + //Check the copynb search criteria + uint64_t copynb = 1; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.copynb = copynb; + auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); + int nbFileRecycleLogs = 0; + while(fileRecycleLogItor.hasMore()){ + nbFileRecycleLogs++; + fileRecycleLogItor.next(); + } + ASSERT_EQ(nbArchiveFiles,nbFileRecycleLogs); + } + { + //Check the disk instance search criteria + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.diskInstance = diskInstance; + auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); + int nbFileRecycleLogs = 0; + while(fileRecycleLogItor.hasMore()){ + nbFileRecycleLogs++; + fileRecycleLogItor.next(); + } + ASSERT_EQ(nbArchiveFiles,nbFileRecycleLogs); + } + { + //Check multiple search criteria together + uint64_t copynb = 1; + uint64_t archiveFileId = 1; + std::string diskFileId = "12345678"; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.diskInstance = diskInstance; + criteria.copynb = copynb; + criteria.archiveFileId = archiveFileId; + criteria.diskFileIds = std::vector<std::string>(); + criteria.diskFileIds->push_back(diskFileId); + criteria.vid = tape1.vid; + + auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria); + + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + auto fileRecycleLog = fileRecycleLogItor.next(); + ASSERT_EQ(archiveFileId, fileRecycleLog.archiveFileId); + ASSERT_EQ(diskFileId, fileRecycleLog.diskFileId); + ASSERT_EQ(copynb, fileRecycleLog.copyNb); + ASSERT_EQ(tape1.vid, fileRecycleLog.vid); + ASSERT_EQ(diskInstance, fileRecycleLog.diskInstanceName); + + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + } } TEST_P(cta_catalogue_CatalogueTest, sameFileWrittenToSameTapePutThePreviousCopyOnTheFileRecycleLog) { diff --git a/catalogue/MysqlCatalogue.cpp b/catalogue/MysqlCatalogue.cpp index 552bb129738fc641f0fd9894dec7dce33ca8d106..606b5d151a28a9189a845adeffc65050c3419d21 100644 --- a/catalogue/MysqlCatalogue.cpp +++ b/catalogue/MysqlCatalogue.cpp @@ -59,10 +59,10 @@ MysqlCatalogue::~MysqlCatalogue() { //------------------------------------------------------------------------------ // createAndPopulateTempTableFxid //------------------------------------------------------------------------------ -std::string MysqlCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const { +std::string MysqlCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const { const std::string tempTableName = "TEMP_DISK_FXIDS"; - if(tapeFileSearchCriteria.diskFileIds) { + if(diskFileIds) { try { std::string sql = "CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID VARCHAR(100))"; try { @@ -76,7 +76,7 @@ std::string MysqlCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, co sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; auto stmt = conn.createStmt(sql); - for(auto &diskFileId : tapeFileSearchCriteria.diskFileIds.value()) { + for(auto &diskFileId : diskFileIds.value()) { stmt.bindString(":DISK_FILE_ID", diskFileId); stmt.executeNonQuery(); } diff --git a/catalogue/MysqlCatalogue.hpp b/catalogue/MysqlCatalogue.hpp index 1e6b178516ffd0d820f360981e39e882f5e69b07..82d8360bff8be779fec00b01d9d88d7319250037 100644 --- a/catalogue/MysqlCatalogue.hpp +++ b/catalogue/MysqlCatalogue.hpp @@ -60,10 +60,10 @@ protected: * Creates a temporary table from the list of disk file IDs provided in the search criteria. * * @param conn The database connection. - * @param tapeFileSearchCriteria Search criteria containing a list of disk file IDs (fxid). + * @param diskFileIds List of disk file IDs (fxid). * @return Name of the temporary table */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const override; + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const override; /** * Returns a unique archive ID that can be used by a new archive file within diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp index 08e63e5afd379df8d58b4a5ee7500276b4ffb9b4..bc1a42c35413ce09523f4e140a1f300d2729a542 100644 --- a/catalogue/OracleCatalogue.cpp +++ b/catalogue/OracleCatalogue.cpp @@ -154,11 +154,11 @@ OracleCatalogue::~OracleCatalogue() { //------------------------------------------------------------------------------ // createAndPopulateTempTableFxid //------------------------------------------------------------------------------ -std::string OracleCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const { +std::string OracleCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const { const std::string tempTableName = "ORA$PTT_DISK_FXIDS"; try { - if(tapeFileSearchCriteria.diskFileIds) { + if(diskFileIds) { conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); std::string sql = "CREATE PRIVATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID VARCHAR2(100))"; @@ -166,7 +166,7 @@ std::string OracleCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, c sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; auto stmt = conn.createStmt(sql); - for(auto &diskFileId : tapeFileSearchCriteria.diskFileIds.value()) { + for(auto &diskFileId : diskFileIds.value()) { stmt.bindString(":DISK_FILE_ID", diskFileId); stmt.executeNonQuery(); } diff --git a/catalogue/OracleCatalogue.hpp b/catalogue/OracleCatalogue.hpp index 03067d1d544fea1e53e3e4ceccaaaa6bf9459a53..9dd68a65d98cdbd265c41ff005111222151d3610 100644 --- a/catalogue/OracleCatalogue.hpp +++ b/catalogue/OracleCatalogue.hpp @@ -61,10 +61,10 @@ public: * Creates a temporary table from the list of disk file IDs provided in the search criteria. * * @param conn The database connection. - * @param tapeFileSearchCriteria Search criteria containing a list of disk file IDs (fxid). + * @param diskFileIds List of disk file IDs (fxid). * @return Name of the temporary table */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const override; + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const override; /** * Returns a unique archive ID that can be used by a new archive file within diff --git a/catalogue/PostgresCatalogue.cpp b/catalogue/PostgresCatalogue.cpp index da343a4a58d41c7fbe436de4b1856f9a4ed7d32b..3073bb893597fe5b92f161d44736cb24e7547ad0 100644 --- a/catalogue/PostgresCatalogue.cpp +++ b/catalogue/PostgresCatalogue.cpp @@ -152,10 +152,10 @@ PostgresCatalogue::~PostgresCatalogue() { //------------------------------------------------------------------------------ // createAndPopulateTempTableFxid //------------------------------------------------------------------------------ -std::string PostgresCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const { +std::string PostgresCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const { const std::string tempTableName = "TEMP_DISK_FXIDS"; - if(tapeFileSearchCriteria.diskFileIds) { + if(diskFileIds) { try { std::string sql = "CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID VARCHAR(100))"; try { @@ -169,7 +169,7 @@ std::string PostgresCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; auto stmt = conn.createStmt(sql); - for(auto &diskFileId : tapeFileSearchCriteria.diskFileIds.value()) { + for(auto &diskFileId : diskFileIds.value()) { stmt.bindString(":DISK_FILE_ID", diskFileId); stmt.executeNonQuery(); } diff --git a/catalogue/PostgresCatalogue.hpp b/catalogue/PostgresCatalogue.hpp index ee2c914b851487d39cd5cc307583aacdb1a65fa7..da8d3d6bc4b7f4848b67ebf5e2aa749637640a76 100644 --- a/catalogue/PostgresCatalogue.hpp +++ b/catalogue/PostgresCatalogue.hpp @@ -88,10 +88,10 @@ public: * Creates a temporary table from the list of disk file IDs provided in the search criteria. * * @param conn The database connection. - * @param tapeFileSearchCriteria Search criteria containing a list of disk file IDs (fxid). + * @param diskFileIds List of disk file IDs (fxid). * @return Name of the temporary table */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const override; + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const override; /** * Returns a unique archive ID that can be used by a new archive file within diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp index 4db898a66bb1dcd41471ebc6cab0c07c9de163d1..262f58418aa4e506e189a64b7394464713192de5 100644 --- a/catalogue/RdbmsCatalogue.cpp +++ b/catalogue/RdbmsCatalogue.cpp @@ -6970,7 +6970,7 @@ Catalogue::ArchiveFileItor RdbmsCatalogue::getArchiveFilesItor(const TapeFileSea try { // Create a connection to populate the temporary table (specialised by database type) auto conn = m_archiveFileListingConnPool.getConn(); - const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria); + const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria.diskFileIds); // Pass ownership of the connection to the Iterator object auto impl = new RdbmsCatalogueGetArchiveFilesItor(m_log, std::move(conn), searchCriteria, tempDiskFxidsTableName); return ArchiveFileItor(impl); @@ -7002,9 +7002,8 @@ Catalogue::ArchiveFileItor RdbmsCatalogue::getTapeContentsItor(const std::string //------------------------------------------------------------------------------ // checkRecycleTapeFileSearchCriteria //------------------------------------------------------------------------------ -void RdbmsCatalogue::checkRecycleTapeFileSearchCriteria(const RecycleTapeFileSearchCriteria & searchCriteria) const { +void RdbmsCatalogue::checkRecycleTapeFileSearchCriteria(cta::rdbms::Conn &conn, const RecycleTapeFileSearchCriteria & searchCriteria) const { if(searchCriteria.vid) { - auto conn = m_connPool.getConn(); if(!tapeExists(conn, searchCriteria.vid.value())) { throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist"); } @@ -7013,8 +7012,10 @@ void RdbmsCatalogue::checkRecycleTapeFileSearchCriteria(const RecycleTapeFileSea Catalogue::FileRecycleLogItor RdbmsCatalogue::getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const { try { - checkRecycleTapeFileSearchCriteria(searchCriteria); - auto impl = new RdbmsCatalogueGetFileRecycleLogItor(m_log, m_archiveFileListingConnPool, searchCriteria); + auto conn = m_archiveFileListingConnPool.getConn(); + checkRecycleTapeFileSearchCriteria(conn, searchCriteria); + const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria.diskFileIds); + auto impl = new RdbmsCatalogueGetFileRecycleLogItor(m_log, std::move(conn), searchCriteria, tempDiskFxidsTableName); return FileRecycleLogItor(impl); } catch(exception::UserError &) { throw; @@ -7182,7 +7183,7 @@ common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary( addedAWhereConstraint = true; } if(searchCriteria.diskFileIds) { - const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria); + const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria.diskFileIds); if(addedAWhereConstraint) sql += " AND "; sql += "ARCHIVE_FILE.DISK_FILE_ID IN (SELECT DISK_FILE_ID FROM " + tempDiskFxidsTableName + ")"; diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp index 9b025b28c92c91850c314857fed9ced35f4bff3b..91189898e45ec4a3b1cd6d48da2e2f13651f54de 100644 --- a/catalogue/RdbmsCatalogue.hpp +++ b/catalogue/RdbmsCatalogue.hpp @@ -851,10 +851,10 @@ public: /** * Throws a UserError exception if the specified searchCriteria is not valid * due to a user error. - * + * @param conn The database connection. * @param searchCriteria The search criteria. */ - void checkRecycleTapeFileSearchCriteria(const RecycleTapeFileSearchCriteria & searchCriteria) const; + void checkRecycleTapeFileSearchCriteria(cta::rdbms::Conn &conn, const RecycleTapeFileSearchCriteria & searchCriteria) const; /** * Returns all the currently deleted files by looking at the FILE_RECYCLE_LOG table @@ -1575,10 +1575,10 @@ protected: * Creates a temporary table from the list of disk file IDs provided in the search criteria. * * @param conn The database connection. - * @param tapeFileSearchCriteria Search criteria containing a list of disk file IDs (fxid). + * @param diskFileIds List of disk file IDs (fxid). * @return Name of the temporary table */ - virtual std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const = 0; + virtual std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const = 0; /** * Returns a unique archive ID that can be used by a new archive file within diff --git a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp b/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp index ab9b81519cea0155e55f7bf0bcd6bd876141e2eb..71f66cb27fb918d9b66512e0eb22cffddc4c8a85 100644 --- a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp +++ b/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp @@ -27,10 +27,11 @@ namespace catalogue { //------------------------------------------------------------------------------ RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor( log::Logger &log, - rdbms::ConnPool &connPool, - const RecycleTapeFileSearchCriteria & searchCriteria): + rdbms::Conn &&conn, + const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &tempDiskFxidsTableName): m_log(log), - m_connPool(connPool), + m_conn(std::move(conn)), m_searchCriteria(searchCriteria), m_rsetIsEmpty(true), m_hasMoreHasBeenCalled(false) { @@ -65,7 +66,10 @@ RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor( const bool thereIsAtLeastOneSearchCriteria = searchCriteria.vid || - searchCriteria.diskFileId; + searchCriteria.diskFileIds || + searchCriteria.archiveFileId || + searchCriteria.copynb || + searchCriteria.diskInstance; if(thereIsAtLeastOneSearchCriteria) { sql += " WHERE "; @@ -77,12 +81,29 @@ RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor( sql += "FILE_RECYCLE_LOG.VID = :VID"; addedAWhereConstraint = true; } + + if (searchCriteria.archiveFileId) { + if(addedAWhereConstraint) sql += " AND "; + sql += "FILE_RECYCLE_LOG.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + addedAWhereConstraint = true; + } - if(searchCriteria.diskFileId){ + if(searchCriteria.diskFileIds) { if(addedAWhereConstraint) sql += " AND "; - sql += "FILE_RECYCLE_LOG.DISK_FILE_ID = :DISK_FILE_ID"; + sql += "FILE_RECYCLE_LOG.DISK_FILE_ID IN (SELECT DISK_FILE_ID FROM " + tempDiskFxidsTableName + ")"; addedAWhereConstraint = true; } + + if (searchCriteria.diskInstance) { + if(addedAWhereConstraint) sql += " AND "; + sql += "FILE_RECYCLE_LOG.DISK_INSTANCE_NAME = :DISK_INSTANCE"; + addedAWhereConstraint = true; + } + + if (searchCriteria.copynb) { + if(addedAWhereConstraint) sql += " AND "; + sql += "FILE_RECYCLE_LOG.COPY_NB = :COPY_NB"; + } // Order by FSEQ if we are listing the contents of a tape, else order by archive file ID if(searchCriteria.vid) { @@ -91,15 +112,22 @@ RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor( sql += " ORDER BY FILE_RECYCLE_LOG.ARCHIVE_FILE_ID, FILE_RECYCLE_LOG.COPY_NB"; } - m_conn = connPool.getConn(); m_stmt = m_conn.createStmt(sql); if(searchCriteria.vid){ m_stmt.bindString(":VID", searchCriteria.vid.value()); } - - if(searchCriteria.diskFileId){ - m_stmt.bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value()); + + if (searchCriteria.archiveFileId) { + m_stmt.bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value()); + } + + if (searchCriteria.diskInstance) { + m_stmt.bindString(":DISK_INSTANCE", searchCriteria.diskInstance.value()); + } + + if (searchCriteria.copynb) { + m_stmt.bindUint64(":COPY_NB", searchCriteria.copynb.value()); } m_rset = m_stmt.executeQuery(); diff --git a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp b/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp index c94cfe3949fa916190a23e0c55ca9ff4e01f993a..90e996b82ed39506e25cc28634f225bd7106d5b6 100644 --- a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp +++ b/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp @@ -29,9 +29,13 @@ public: * Constructor. * * @param log Object representing the API to the CTA logging system. - * @param connPool The database connection pool. + * @param conn A database connection. */ - RdbmsCatalogueGetFileRecycleLogItor(log::Logger &log, rdbms::ConnPool &connPool, const RecycleTapeFileSearchCriteria & searchCriteria); + RdbmsCatalogueGetFileRecycleLogItor( + log::Logger &log, + rdbms::Conn &&conn, + const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &tempDiskFxidsTableName); /** * Destructor. @@ -54,10 +58,12 @@ private: */ log::Logger &m_log; + /** - * The database connection pool. + * The database connection. */ - rdbms::ConnPool &m_connPool; + rdbms::Conn m_conn; + /** * The search criteria to be used when listing recycled tape files. @@ -79,11 +85,6 @@ private: */ bool m_hasMoreHasBeenCalled; - /** - * The database connection. - */ - rdbms::Conn m_conn; - /** * The database statement. */ diff --git a/catalogue/RecyleTapeFileSearchCriteria.hpp b/catalogue/RecyleTapeFileSearchCriteria.hpp index 8fc49830645e51f08c5c95006a235c8491ff22a3..eb4ab60cb73af6c73b9d52a7895e0082adad13ac 100644 --- a/catalogue/RecyleTapeFileSearchCriteria.hpp +++ b/catalogue/RecyleTapeFileSearchCriteria.hpp @@ -32,6 +32,15 @@ namespace catalogue { * Please note that no wild cards, for example '*' or '%', are supported. */ struct RecycleTapeFileSearchCriteria { + /** + * The unique identifier of an archive file. + */ + optional<uint64_t> archiveFileId; + + /** + * The name of a disk instance. + */ + optional<std::string> diskInstance; /** * The volume identifier of a tape. @@ -44,7 +53,12 @@ struct RecycleTapeFileSearchCriteria { * These are given as a list of strings in DECIMAL format. EOS provides the fxids in hex format. The parsing and * conversion into decimal is done in the cta-admin client, ready to be built into a SQL query string. */ - optional<std::string> diskFileId; + optional<std::vector<std::string>> diskFileIds; + + /** + * The copy number of the deleted tape file. + */ + optional<uint64_t> copynb; }; // struct TapeFileSearchCriteria diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp index c809025876f84e27a19ee67f5141488b3046009c..a48071da05e08c5d310537bb35f20d4bfd0730e9 100644 --- a/catalogue/SqliteCatalogue.cpp +++ b/catalogue/SqliteCatalogue.cpp @@ -192,7 +192,7 @@ void SqliteCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string //------------------------------------------------------------------------------ // createAndPopulateTempTableFxid //------------------------------------------------------------------------------ -std::string SqliteCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const { +std::string SqliteCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const { try { const std::string tempTableName = "TEMP.DISK_FXIDS"; @@ -200,9 +200,9 @@ std::string SqliteCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, c conn.executeNonQuery("DROP TABLE IF EXISTS " + tempTableName); conn.executeNonQuery("CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID TEXT)"); - if(tapeFileSearchCriteria.diskFileIds) { + if(diskFileIds) { auto stmt = conn.createStmt("INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"); - for(auto &diskFileId : tapeFileSearchCriteria.diskFileIds.value()) { + for(auto &diskFileId : diskFileIds.value()) { stmt.bindString(":DISK_FILE_ID", diskFileId); stmt.executeNonQuery(); } diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp index 020589f930823f08d39bd77e288d0a703a3a11a6..f42f9f14ca63c487be216d2f9d6365da1c3f3279 100644 --- a/catalogue/SqliteCatalogue.hpp +++ b/catalogue/SqliteCatalogue.hpp @@ -86,10 +86,10 @@ protected: * Creates a temporary table from the list of disk file IDs provided in the search criteria. * * @param conn The database connection. - * @param tapeFileSearchCriteria Search criteria containing a list of disk file IDs (fxid). + * @param diskFileIds List of disk file IDs (fxid). * @return Name of the temporary table */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const TapeFileSearchCriteria &tapeFileSearchCriteria) const override; + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const optional<std::vector<std::string>> &diskFileIds) const override; /** * Returns a unique archive ID that can be used by a new archive file within diff --git a/cmdline/CtaAdminCmdParse.hpp b/cmdline/CtaAdminCmdParse.hpp index 70b6123de3d2a67a453fdecac8e0321c38022608..da06f29a18b63aff72bcedd4b2c0148beffd201b 100644 --- a/cmdline/CtaAdminCmdParse.hpp +++ b/cmdline/CtaAdminCmdParse.hpp @@ -408,7 +408,7 @@ const std::map<AdminCmd::Cmd, CmdHelp> cmdHelp = { { AdminCmd::CMD_VERSION, { "version", "v", { } }}, { AdminCmd::CMD_SCHEDULINGINFOS, { "schedulinginfo", "si", { "ls" } }}, { AdminCmd::CMD_RECYCLETAPEFILE, { "recycletf", "rtf", { "ls" }, - " Tape files in the recycle log can be listed by VID or by EOS disk file ID.\n" + " Tape files in the recycle log can be listed by VID, EOS disk file ID, EOS disk instance, ArchiveFileId or copy number.\n" " Disk file IDs should be provided in hexadecimal (fxid).\n\n" }}, }; @@ -614,7 +614,8 @@ const std::map<cmd_key_t, cmd_val_t> cmdOptions = { { }}, {{ AdminCmd::CMD_VERSION, AdminCmd::SUBCMD_NONE }, { }}, {{ AdminCmd::CMD_SCHEDULINGINFOS, AdminCmd::SUBCMD_LS }, { }}, - {{ AdminCmd::CMD_RECYCLETAPEFILE, AdminCmd::SUBCMD_LS }, { opt_vid.optional(), opt_fid.optional() }}, + {{ AdminCmd::CMD_RECYCLETAPEFILE, AdminCmd::SUBCMD_LS }, + { opt_vid.optional(), opt_fid.optional(), opt_fidfile.optional(), opt_copynb.optional(), opt_archivefileid.optional(), opt_instance.optional() }}, }; diff --git a/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp b/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp index 7c18034dd8eadefad9f2c83c39860beb5237ab7b..86631b2386d39813e1ae2c644cf76feed24f8d23 100644 --- a/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp +++ b/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp @@ -66,15 +66,28 @@ RecycleTapeFileLsStream::RecycleTapeFileLsStream(const RequestMessage &requestMs searchCriteria.vid = requestMsg.getOptional(OptionString::VID, &has_any); auto diskFileId = requestMsg.getOptional(OptionString::FXID, &has_any); + + searchCriteria.diskFileIds = requestMsg.getOptional(OptionStrList::FILE_ID, &has_any); if(diskFileId){ // single option on the command line we need to do the conversion ourselves. + if(!searchCriteria.diskFileIds) searchCriteria.diskFileIds = std::vector<std::string>(); + auto fid = strtol(diskFileId->c_str(), nullptr, 16); if(fid < 1 || fid == LONG_MAX) { throw cta::exception::UserError(*diskFileId + " is not a valid file ID"); } - searchCriteria.diskFileId = std::to_string(fid); + + searchCriteria.diskFileIds->push_back(std::to_string(fid)); } + // Disk instance on its own does not give a valid set of search criteria (no &has_any) + searchCriteria.diskInstance = requestMsg.getOptional(OptionString::INSTANCE); + + searchCriteria.archiveFileId = requestMsg.getOptional(OptionUInt64::ARCHIVE_FILE_ID, &has_any); + + // Copy number on its own does not give a valid set of search criteria (no &has_any) + searchCriteria.copynb = requestMsg.getOptional(OptionUInt64::COPY_NUMBER); + if(!has_any){ throw cta::exception::UserError("Must specify at least one search option"); } diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.hpp b/xroot_plugins/XrdSsiCtaRequestMessage.hpp index 24bf193b2872f6bb74bf26c0636b7dd15cdf9de5..846024bb659c3f0ec1a6aec4d57a3f1231185759 100644 --- a/xroot_plugins/XrdSsiCtaRequestMessage.hpp +++ b/xroot_plugins/XrdSsiCtaRequestMessage.hpp @@ -207,7 +207,7 @@ private: void processVirtualOrganization_Add(cta::xrd::Response &response); void processVirtualOrganization_Ch(cta::xrd::Response &response); void processVirtualOrganization_Rm(cta::xrd::Response &response); - + /*! * Process AdminCmd events which can return a stream response *