Commit d1cf32aa authored by Steven Murray's avatar Steven Murray
Browse files

Added Catalogue::modifyTapePoolName() which works towards cta/CTA#630

parent 19a1cf0d
......@@ -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 &currentName, const std::string &newName) = 0;
virtual void createArchiveRoute(
const common::dataStructures::SecurityIdentity &admin,
const std::string &diskInstanceName,
......
......@@ -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 &currentName, 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);
}
......
......@@ -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;
......
......@@ -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());
......
......@@ -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"); }
......
......@@ -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) {
......
......@@ -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
......
......@@ -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;
......
......@@ -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
......
......@@ -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,"