From f1e9672e26b300c88ab72c2b12c3b047c389842f Mon Sep 17 00:00:00 2001 From: Jorge Camarero Vera <jorge.camarero@cern.ch> Date: Mon, 23 Jan 2023 17:40:34 +0100 Subject: [PATCH] Refactor Catalogue and RdbmsCatalogue Classes --- catalogue/12.0/oracle_catalogue_schema.sql | 4 +- catalogue/12.0/postgres_catalogue_schema.sql | 4 +- catalogue/12.0/sqlite_catalogue_schema.sql | 4 +- catalogue/AllCatalogueSchema.hpp | 12 +- catalogue/CMakeLists.txt | 56 +- catalogue/Catalogue.hpp | 1440 +- ...alogueTest.cpp => CatalogueExceptions.hpp} | 16 +- catalogue/CatalogueTest.hpp | 143 - catalogue/CatalogueUtils.cpp | 43 + .../{Catalogue.cpp => CatalogueUtils.hpp} | 26 +- catalogue/CreateAdminUserCmd.cpp | 2 +- catalogue/DriveConfig.cpp | 16 +- catalogue/DriveConfig.hpp | 1 + catalogue/DummyCatalogue.cpp | 446 - catalogue/DummyCatalogue.hpp | 269 - catalogue/Group.hpp | 64 + catalogue/InMemoryCatalogueFactory.cpp | 8 +- catalogue/InMemoryVersionOfCatalogueTest.cpp | 48 - catalogue/OracleCatalogue.cpp | 1247 -- catalogue/OracleCatalogue.hpp | 302 - catalogue/OracleCatalogueFactory.cpp | 14 +- catalogue/OracleCatalogueFactory.hpp | 5 + catalogue/PostgresCatalogue.cpp | 1204 -- catalogue/PostgresCatalogue.hpp | 318 - catalogue/PostgresqlCatalogueFactory.cpp | 8 +- catalogue/PostgresqlCatalogueFactory.hpp | 9 + catalogue/RdbmsCatalogue.cpp | 12101 ---------------- catalogue/RdbmsCatalogue.hpp | 2460 ---- catalogue/SchemaCreatingSqliteCatalogue.cpp | 6 +- catalogue/SchemaCreatingSqliteCatalogue.hpp | 2 +- catalogue/SqliteCatalogue.cpp | 780 - catalogue/SqliteCatalogue.hpp | 269 - catalogue/TapeDrivesCatalogueState.cpp | 23 +- catalogue/User.hpp | 64 + catalogue/common_catalogue_schema.sql | 4 +- catalogue/dummy/DummyAdminUserCatalogue.cpp | 47 + catalogue/dummy/DummyAdminUserCatalogue.hpp | 43 + catalogue/dummy/DummyArchiveFileCatalogue.cpp | 93 + catalogue/dummy/DummyArchiveFileCatalogue.hpp | 69 + .../dummy/DummyArchiveRouteCatalogue.cpp | 53 + .../dummy/DummyArchiveRouteCatalogue.hpp | 48 + catalogue/dummy/DummyCatalogue.cpp | 152 + catalogue/dummy/DummyCatalogue.hpp | 86 + .../dummy/DummyDiskInstanceCatalogue.cpp | 48 + .../dummy/DummyDiskInstanceCatalogue.hpp | 51 + .../dummy/DummyDiskInstanceSpaceCatalogue.cpp | 72 + .../dummy/DummyDiskInstanceSpaceCatalogue.hpp | 70 + catalogue/dummy/DummyDiskSystemCatalogue.cpp | 82 + catalogue/dummy/DummyDiskSystemCatalogue.hpp | 67 + catalogue/dummy/DummyDriveConfig.hpp | 53 + catalogue/dummy/DummyDriveConfigCatalogue.cpp | 51 + catalogue/dummy/DummyDriveConfigCatalogue.hpp | 54 + catalogue/dummy/DummyDriveStateCatalogue.cpp | 171 + catalogue/dummy/DummyDriveStateCatalogue.hpp | 74 + .../dummy/DummyFileRecycleLogCatalogue.cpp | 41 + .../dummy/DummyFileRecycleLogCatalogue.hpp | 40 + .../dummy/DummyLogicalLibraryCatalogue.cpp | 60 + .../dummy/DummyLogicalLibraryCatalogue.hpp | 51 + catalogue/dummy/DummyMediaTypeCatalogue.cpp | 93 + catalogue/dummy/DummyMediaTypeCatalogue.hpp | 67 + catalogue/dummy/DummyMountPolicyCatalogue.cpp | 110 + catalogue/dummy/DummyMountPolicyCatalogue.hpp | 59 + ...mmyRequesterActivityMountRuleCatalogue.cpp | 58 + ...mmyRequesterActivityMountRuleCatalogue.hpp | 49 + .../DummyRequesterGroupMountRuleCatalogue.cpp | 58 + .../DummyRequesterGroupMountRuleCatalogue.hpp | 48 + .../DummyRequesterMountRuleCatalogue.cpp | 56 + .../DummyRequesterMountRuleCatalogue.hpp | 46 + catalogue/dummy/DummySchemaCatalogue.cpp | 38 + catalogue/dummy/DummySchemaCatalogue.hpp | 38 + .../dummy/DummyStorageClassCatalogue.cpp | 64 + .../dummy/DummyStorageClassCatalogue.hpp | 56 + catalogue/dummy/DummyTapeCatalogue.cpp | 206 + catalogue/dummy/DummyTapeCatalogue.hpp | 121 + catalogue/dummy/DummyTapeFileCatalogue.cpp | 48 + catalogue/dummy/DummyTapeFileCatalogue.hpp | 41 + catalogue/dummy/DummyTapePoolCatalogue.cpp | 82 + catalogue/dummy/DummyTapePoolCatalogue.hpp | 62 + .../DummyVirtualOrganizationCatalogue.cpp | 84 + .../DummyVirtualOrganizationCatalogue.hpp | 67 + catalogue/interfaces/AdminUserCatalogue.hpp | 64 + catalogue/interfaces/ArchiveFileCatalogue.hpp | 230 + .../interfaces/ArchiveRouteCatalogue.hpp | 97 + .../interfaces/DiskInstanceCatalogue.hpp | 56 + .../interfaces/DiskInstanceSpaceCatalogue.hpp | 89 + catalogue/interfaces/DiskSystemCatalogue.hpp | 106 + catalogue/interfaces/DriveConfigCatalogue.hpp | 99 + catalogue/interfaces/DriveStateCatalogue.hpp | 119 + .../interfaces/FileRecycleLogCatalogue.hpp | 80 + .../interfaces/LogicalLibraryCatalogue.hpp | 73 + catalogue/interfaces/MediaTypeCatalogue.hpp | 171 + catalogue/interfaces/MountPolicyCatalogue.hpp | 92 + .../RequesterActivityMountRuleCatalogue.hpp | 90 + .../RequesterGroupMountRuleCatalogue.hpp | 89 + .../RequesterMountRuleCatalogue.hpp | 86 + catalogue/interfaces/SchemaCatalogue.hpp | 58 + .../interfaces/StorageClassCatalogue.hpp | 88 + catalogue/interfaces/TapeCatalogue.hpp | 286 + catalogue/interfaces/TapeFileCatalogue.hpp | 96 + catalogue/interfaces/TapePoolCatalogue.hpp | 87 + .../VirtualOrganizationCatalogue.hpp | 135 + catalogue/rdbms/CommonExceptions.hpp | 31 + catalogue/rdbms/RdbmsAdminUserCatalogue.cpp | 287 + catalogue/rdbms/RdbmsAdminUserCatalogue.hpp | 90 + catalogue/rdbms/RdbmsArchiveFileCatalogue.cpp | 1209 ++ catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp | 334 + .../rdbms/RdbmsArchiveRouteCatalogue.cpp | 411 + .../rdbms/RdbmsArchiveRouteCatalogue.hpp | 77 + catalogue/rdbms/RdbmsCatalogue.cpp | 164 + catalogue/rdbms/RdbmsCatalogue.hpp | 182 + ...sCatalogueGetArchiveFilesForRepackItor.cpp | 2 +- ...sCatalogueGetArchiveFilesForRepackItor.hpp | 2 +- .../RdbmsCatalogueGetArchiveFilesItor.cpp | 2 +- .../RdbmsCatalogueGetArchiveFilesItor.hpp | 2 +- .../RdbmsCatalogueGetFileRecycleLogItor.cpp | 2 +- .../RdbmsCatalogueGetFileRecycleLogItor.hpp | 4 +- .../RdbmsCatalogueTapeContentsItor.cpp | 2 +- .../RdbmsCatalogueTapeContentsItor.hpp | 2 +- catalogue/rdbms/RdbmsCatalogueUtils.cpp | 508 + catalogue/rdbms/RdbmsCatalogueUtils.hpp | 87 + .../rdbms/RdbmsDiskInstanceCatalogue.cpp | 219 + .../rdbms/RdbmsDiskInstanceCatalogue.hpp | 57 + .../rdbms/RdbmsDiskInstanceSpaceCatalogue.cpp | 405 + .../rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp | 78 + catalogue/rdbms/RdbmsDiskSystemCatalogue.cpp | 492 + catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp | 79 + catalogue/rdbms/RdbmsDriveConfigCatalogue.cpp | 248 + catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp | 65 + catalogue/rdbms/RdbmsDriveStateCatalogue.cpp | 1057 ++ catalogue/rdbms/RdbmsDriveStateCatalogue.hpp | 92 + .../rdbms/RdbmsFileRecycleLogCatalogue.cpp | 389 + .../rdbms/RdbmsFileRecycleLogCatalogue.hpp | 178 + .../rdbms/RdbmsLogicalLibraryCatalogue.cpp | 361 + .../rdbms/RdbmsLogicalLibraryCatalogue.hpp | 93 + catalogue/rdbms/RdbmsMediaTypeCatalogue.cpp | 624 + catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp | 91 + catalogue/rdbms/RdbmsMountPolicyCatalogue.cpp | 861 ++ catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp | 153 + ...bmsRequesterActivityMountRuleCatalogue.cpp | 282 + ...bmsRequesterActivityMountRuleCatalogue.hpp | 66 + .../RdbmsRequesterGroupMountRuleCatalogue.cpp | 279 + .../RdbmsRequesterGroupMountRuleCatalogue.hpp | 65 + .../RdbmsRequesterMountRuleCatalogue.cpp | 273 + .../RdbmsRequesterMountRuleCatalogue.hpp | 63 + catalogue/rdbms/RdbmsSchemaCatalogue.cpp | 124 + catalogue/rdbms/RdbmsSchemaCatalogue.hpp | 60 + .../rdbms/RdbmsStorageClassCatalogue.cpp | 502 + .../rdbms/RdbmsStorageClassCatalogue.hpp | 145 + catalogue/rdbms/RdbmsTapeCatalogue.cpp | 1879 +++ catalogue/rdbms/RdbmsTapeCatalogue.hpp | 186 + catalogue/rdbms/RdbmsTapeFileCatalogue.cpp | 343 + catalogue/rdbms/RdbmsTapeFileCatalogue.hpp | 131 + catalogue/rdbms/RdbmsTapePoolCatalogue.cpp | 762 + catalogue/rdbms/RdbmsTapePoolCatalogue.hpp | 122 + .../RdbmsVirtualOrganizationCatalogue.cpp | 591 + .../RdbmsVirtualOrganizationCatalogue.hpp | 110 + .../oracle/OracleArchiveFileCatalogue.cpp | 344 + .../oracle/OracleArchiveFileCatalogue.hpp | 71 + catalogue/rdbms/oracle/OracleCatalogue.cpp | 85 + catalogue/rdbms/oracle/OracleCatalogue.hpp | 73 + .../oracle/OracleFileRecycleLogCatalogue.cpp | 117 + .../oracle/OracleFileRecycleLogCatalogue.hpp | 61 + .../oracle/OracleLogicalLibraryCatalogue.cpp | 54 + .../oracle/OracleLogicalLibraryCatalogue.hpp | 40 + .../rdbms/oracle/OracleMediaTypeCatalogue.cpp | 54 + .../rdbms/oracle/OracleMediaTypeCatalogue.hpp | 41 + .../oracle/OracleStorageClassCatalogue.cpp | 54 + .../oracle/OracleStorageClassCatalogue.hpp | 42 + .../rdbms/oracle/OracleTapeCatalogue.cpp | 58 + .../rdbms/oracle/OracleTapeCatalogue.hpp | 41 + .../rdbms/oracle/OracleTapeFileCatalogue.cpp | 619 + .../rdbms/oracle/OracleTapeFileCatalogue.hpp | 88 + .../rdbms/oracle/OracleTapePoolCatalogue.cpp | 55 + .../rdbms/oracle/OracleTapePoolCatalogue.hpp | 41 + .../OracleVirtualOrganizationCatalogue.cpp | 56 + .../OracleVirtualOrganizationCatalogue.hpp | 39 + .../postgres/PostgresArchiveFileCatalogue.cpp | 338 + .../postgres/PostgresArchiveFileCatalogue.hpp | 72 + .../rdbms/postgres/PostgresCatalogue.cpp | 91 + .../rdbms/postgres/PostgresCatalogue.hpp | 69 + .../PostgresFileRecycleLogCatalogue.cpp | 110 + .../PostgresFileRecycleLogCatalogue.hpp | 62 + .../PostgresLogicalLibraryCatalogue.cpp | 50 + .../PostgresLogicalLibraryCatalogue.hpp | 41 + .../postgres/PostgresMediaTypeCatalogue.cpp | 49 + .../postgres/PostgresMediaTypeCatalogue.hpp | 41 + .../PostgresStorageClassCatalogue.cpp | 51 + .../PostgresStorageClassCatalogue.hpp | 41 + .../rdbms/postgres/PostgresTapeCatalogue.cpp | 58 + .../rdbms/postgres/PostgresTapeCatalogue.hpp | 41 + .../postgres/PostgresTapeFileCatalogue.cpp | 589 + .../postgres/PostgresTapeFileCatalogue.hpp | 101 + .../postgres/PostgresTapePoolCatalogue.cpp | 51 + .../postgres/PostgresTapePoolCatalogue.hpp | 41 + .../PostgresVirtualOrganizationCatalogue.cpp | 50 + .../PostgresVirtualOrganizationCatalogue.hpp | 41 + .../sqlite/SqliteArchiveFileCatalogue.cpp | 240 + .../sqlite/SqliteArchiveFileCatalogue.hpp | 47 + catalogue/rdbms/sqlite/SqliteCatalogue.cpp | 86 + catalogue/rdbms/sqlite/SqliteCatalogue.hpp | 68 + .../sqlite/SqliteFileRecycleLogCatalogue.cpp | 118 + .../sqlite/SqliteFileRecycleLogCatalogue.hpp | 62 + .../sqlite/SqliteLogicalLibraryCatalogue.cpp | 59 + .../sqlite/SqliteLogicalLibraryCatalogue.hpp | 41 + .../rdbms/sqlite/SqliteMediaTypeCatalogue.cpp | 59 + .../rdbms/sqlite/SqliteMediaTypeCatalogue.hpp | 39 + .../sqlite/SqliteStorageClassCatalogue.cpp | 59 + .../sqlite/SqliteStorageClassCatalogue.hpp | 41 + .../rdbms/sqlite/SqliteTapeCatalogue.cpp | 56 + .../rdbms/sqlite/SqliteTapeCatalogue.hpp | 42 + .../rdbms/sqlite/SqliteTapeFileCatalogue.cpp | 202 + .../rdbms/sqlite/SqliteTapeFileCatalogue.hpp | 55 + .../rdbms/sqlite/SqliteTapePoolCatalogue.cpp | 60 + .../rdbms/sqlite/SqliteTapePoolCatalogue.hpp | 41 + .../SqliteVirtualOrganizationCatalogue.cpp | 59 + .../SqliteVirtualOrganizationCatalogue.hpp | 41 + .../AdminUserCatalogueRetryWrapper.cpp | 59 + .../AdminUserCatalogueRetryWrapper.hpp | 59 + .../ArchiveFileCatalogueRetryWrapper.cpp | 127 + .../ArchiveFileCatalogueRetryWrapper.hpp | 84 + .../ArchiveRouteCatalogueRetryWrapper.cpp | 70 + .../ArchiveRouteCatalogueRetryWrapper.hpp | 63 + .../retrywrappers/CatalogueRetryWrapper.cpp | 163 + .../retrywrappers/CatalogueRetryWrapper.hpp | 116 + .../DiskInstanceCatalogueRetryWrapper.cpp | 61 + .../DiskInstanceCatalogueRetryWrapper.hpp | 57 + ...DiskInstanceSpaceCatalogueRetryWrapper.cpp | 88 + ...DiskInstanceSpaceCatalogueRetryWrapper.hpp | 70 + .../DiskSystemCatalogueRetryWrapper.cpp | 93 + .../DiskSystemCatalogueRetryWrapper.hpp | 75 + .../DriveConfigCatalogueRetryWrapper.cpp | 71 + .../DriveConfigCatalogueRetryWrapper.hpp | 62 + .../DriveStateCatalogueRetryWrapper.cpp | 104 + .../DriveStateCatalogueRetryWrapper.hpp | 78 + .../FileRecycleLogCatalogueRetryWrapper.cpp | 54 + .../FileRecycleLogCatalogueRetryWrapper.hpp | 58 + .../LogicalLibraryCatalogueRetryWrapper.cpp | 75 + .../LogicalLibraryCatalogueRetryWrapper.hpp | 75 + .../MediaTypeCatalogueRetryWrapper.cpp | 111 + .../MediaTypeCatalogueRetryWrapper.hpp | 82 + .../MountPolicyCatalogueRetryWrapper.cpp | 96 + .../MountPolicyCatalogueRetryWrapper.hpp | 74 + ...ActivityMountRuleCatalogueRetryWrapper.cpp | 79 + ...ActivityMountRuleCatalogueRetryWrapper.hpp | 64 + ...terGroupMountRuleCatalogueRetryWrapper.cpp | 74 + ...terGroupMountRuleCatalogueRetryWrapper.hpp | 63 + ...equesterMountRuleCatalogueRetryWrapper.cpp | 73 + ...equesterMountRuleCatalogueRetryWrapper.hpp | 61 + .../SchemaCatalogueRetryWrapper.cpp | 46 + .../SchemaCatalogueRetryWrapper.hpp | 49 + .../StorageClassCatalogueRetryWrapper.cpp | 84 + .../StorageClassCatalogueRetryWrapper.hpp | 67 + .../TapeCatalogueRetryWrapper.cpp | 191 + .../TapeCatalogueRetryWrapper.hpp | 118 + .../TapeFileCatalogueRetryWrapper.cpp | 55 + .../TapeFileCatalogueRetryWrapper.hpp | 51 + .../TapePoolCatalogueRetryWrapper.hpp | 75 + .../TapePoolRetryCatalogueWrapper.cpp | 96 + ...rtualOrganizationCatalogueRetryWrapper.cpp | 98 + ...rtualOrganizationCatalogueRetryWrapper.hpp | 73 + .../retryOnLostConnection.hpp | 14 +- catalogue/tests/CatalogueTestUtils.cpp | 511 + catalogue/tests/CatalogueTestUtils.hpp | 106 + .../tests/DbConfigVersionOfCatalogueTest.cpp | 65 + catalogue/tests/DriveConfigCatalogueTest.cpp | 287 + catalogue/tests/DriveConfigCatalogueTest.hpp | 42 + catalogue/tests/DriveStateCatalogueTest.cpp | 1547 ++ catalogue/tests/DriveStateCatalogueTest.hpp | 45 + .../{ => tests}/InMemoryCatalogueTest.cpp | 3 +- .../tests/InMemoryVersionOfCatalogueTest.cpp | 88 + .../tests/modules/AdminUserCatalogueTest.cpp | 214 + .../tests/modules/AdminUserCatalogueTest.hpp | 46 + .../modules/ArchiveFileCatalogueTest.cpp | 4897 +++++++ .../modules/ArchiveFileCatalogueTest.hpp | 57 + .../modules/ArchiveRouteCatalogueTest.cpp | 483 + .../modules/ArchiveRouteCatalogueTest.hpp | 53 + .../modules/DiskInstanceCatalogueTest.cpp | 230 + .../modules/DiskInstanceCatalogueTest.hpp | 45 + .../DiskInstanceSpaceCatalogueTest.cpp | 620 + .../DiskInstanceSpaceCatalogueTest.hpp | 45 + .../tests/modules/DiskSystemCatalogueTest.cpp | 714 + .../tests/modules/DiskSystemCatalogueTest.hpp | 45 + .../modules/DriveConfigCatalogueTest.cpp | 266 + .../modules/DriveConfigCatalogueTest.hpp | 42 + .../tests/modules/DriveStateCatalogueTest.cpp | 1526 ++ .../tests/modules/DriveStateCatalogueTest.hpp | 45 + .../modules/FileRecycleLogCatalogueTest.cpp | 1122 ++ .../modules/FileRecycleLogCatalogueTest.hpp | 56 + .../modules/LogicalLibraryCatalogueTest.cpp | 751 + .../modules/LogicalLibraryCatalogueTest.hpp | 56 + .../tests/modules/MediaTypeCatalogueTest.cpp | 788 + .../tests/modules/MediaTypeCatalogueTest.hpp | 65 + .../modules/MountPolicyCatalogueTest.cpp | 318 + .../modules/MountPolicyCatalogueTest.hpp | 45 + .../RequesterActivityMountRuleTest.cpp | 282 + .../RequesterActivityMountRuleTest.hpp | 47 + .../RequesterGroupMountRuleCatalogueTest.cpp | 288 + .../RequesterGroupMountRuleCatalogueTest.hpp | 47 + .../tests/modules/RequesterMountRuleTest.cpp | 267 + .../tests/modules/RequesterMountRuleTest.hpp | 47 + .../tests/modules/SchemaCatalogueTest.cpp | 55 + .../tests/modules/SchemaCatalogueTest.hpp | 41 + .../modules/StorageClassCatalogueTest.cpp | 337 + .../modules/StorageClassCatalogueTest.hpp | 50 + catalogue/tests/modules/TapeCatalogueTest.cpp | 4185 ++++++ catalogue/tests/modules/TapeCatalogueTest.hpp | 62 + .../tests/modules/TapeFileCatalogueTest.cpp | 1614 +++ .../tests/modules/TapeFileCatalogueTest.hpp | 57 + .../tests/modules/TapePoolCatalogueTest.cpp | 1526 ++ .../tests/modules/TapePoolCatalogueTest.hpp | 56 + .../VirtualOrganizationCatalogueTest.cpp | 335 + .../VirtualOrganizationCatalogueTest.hpp | 52 + disk/DiskSystem.cpp | 3 +- disk/DiskSystemTest.cpp | 22 +- frontend-grpc/FrontendGRpcSvc.cpp | 2 +- frontend-grpc/Main.cpp | 5 +- frontend/common/FrontendService.cpp | 2 +- objectstore/AlgorithmsTest.cpp | 2 +- objectstore/GarbageCollectorTest.cpp | 9 +- objectstore/Helpers.cpp | 4 +- objectstore/QueueCleanupRunner.cpp | 13 +- .../QueueCleanupRunnerConcurrentTest.cpp | 12 +- objectstore/QueueCleanupRunnerTest.cpp | 14 +- objectstore/SorterTest.cpp | 2 +- scheduler/ArchiveMount.cpp | 6 +- scheduler/OStoreDB/OStoreDB.cpp | 24 +- scheduler/OStoreDB/OStoreDBTest.cpp | 2 +- scheduler/RetrieveMount.cpp | 2 +- scheduler/Scheduler.cpp | 69 +- scheduler/SchedulerDatabaseTest.cpp | 30 +- scheduler/SchedulerTest.cpp | 501 +- scheduler/testingMocks/MockArchiveJob.hpp | 6 +- scheduler/testingMocks/MockArchiveMount.hpp | 2 +- .../RAO/FilePositionEstimatorFactory.cpp | 2 +- .../tape/tapeserver/daemon/CleanerSession.cpp | 8 +- .../daemon/DataTransferSessionTest.cpp | 221 +- .../tapeserver/daemon/DiskWriteTaskTest.cpp | 2 +- .../daemon/DiskWriteThreadPoolTest.cpp | 2 +- .../daemon/MigrationReportPackerTest.cpp | 30 +- .../daemon/RecallReportPackerTest.cpp | 2 +- .../daemon/RecallTaskInjectorTest.cpp | 2 +- .../tape/tapeserver/file/OsmReaderTest.cpp | 20 +- tapeserver/daemon/DriveHandler.cpp | 2 +- tapeserver/readtp/ReadtpCmd.cpp | 6 +- tapeserver/tapelabel/TapeLabelCmd.cpp | 4 +- xroot_plugins/XrdCtaActivityMountRuleLs.hpp | 2 +- xroot_plugins/XrdCtaAdminLs.hpp | 2 +- xroot_plugins/XrdCtaArchiveRouteLs.hpp | 2 +- xroot_plugins/XrdCtaChangeStorageClass.hpp | 4 +- xroot_plugins/XrdCtaDiskInstanceLs.hpp | 2 +- xroot_plugins/XrdCtaDiskInstanceSpaceLs.hpp | 2 +- xroot_plugins/XrdCtaDiskSystemLs.hpp | 2 +- xroot_plugins/XrdCtaDriveLs.hpp | 15 +- xroot_plugins/XrdCtaGroupMountRuleLs.hpp | 2 +- xroot_plugins/XrdCtaLogicalLibraryLs.hpp | 2 +- xroot_plugins/XrdCtaMediaTypeLs.hpp | 2 +- xroot_plugins/XrdCtaMountPolicyLs.hpp | 2 +- xroot_plugins/XrdCtaRecycleTapeFileLs.hpp | 4 +- xroot_plugins/XrdCtaRepackLs.hpp | 2 +- xroot_plugins/XrdCtaRequesterMountRuleLs.hpp | 2 +- xroot_plugins/XrdCtaStorageClassLs.hpp | 4 +- xroot_plugins/XrdCtaTapeFileLs.hpp | 8 +- xroot_plugins/XrdCtaTapeLs.hpp | 2 +- xroot_plugins/XrdCtaTapePoolLs.hpp | 4 +- xroot_plugins/XrdCtaVersion.hpp | 4 +- xroot_plugins/XrdCtaVirtualOrganizationLs.hpp | 2 +- xroot_plugins/XrdSsiCtaRequestMessage.cpp | 211 +- 367 files changed, 54974 insertions(+), 21722 deletions(-) rename catalogue/{DbConfigVersionOfCatalogueTest.cpp => CatalogueExceptions.hpp} (75%) delete mode 100644 catalogue/CatalogueTest.hpp create mode 100644 catalogue/CatalogueUtils.cpp rename catalogue/{Catalogue.cpp => CatalogueUtils.hpp} (74%) delete mode 100644 catalogue/DummyCatalogue.cpp delete mode 100644 catalogue/DummyCatalogue.hpp create mode 100644 catalogue/Group.hpp delete mode 100644 catalogue/InMemoryVersionOfCatalogueTest.cpp delete mode 100644 catalogue/OracleCatalogue.cpp delete mode 100644 catalogue/OracleCatalogue.hpp delete mode 100644 catalogue/PostgresCatalogue.cpp delete mode 100644 catalogue/PostgresCatalogue.hpp delete mode 100644 catalogue/RdbmsCatalogue.cpp delete mode 100644 catalogue/RdbmsCatalogue.hpp delete mode 100644 catalogue/SqliteCatalogue.cpp delete mode 100644 catalogue/SqliteCatalogue.hpp create mode 100644 catalogue/User.hpp create mode 100644 catalogue/dummy/DummyAdminUserCatalogue.cpp create mode 100644 catalogue/dummy/DummyAdminUserCatalogue.hpp create mode 100644 catalogue/dummy/DummyArchiveFileCatalogue.cpp create mode 100644 catalogue/dummy/DummyArchiveFileCatalogue.hpp create mode 100644 catalogue/dummy/DummyArchiveRouteCatalogue.cpp create mode 100644 catalogue/dummy/DummyArchiveRouteCatalogue.hpp create mode 100644 catalogue/dummy/DummyCatalogue.cpp create mode 100644 catalogue/dummy/DummyCatalogue.hpp create mode 100644 catalogue/dummy/DummyDiskInstanceCatalogue.cpp create mode 100644 catalogue/dummy/DummyDiskInstanceCatalogue.hpp create mode 100644 catalogue/dummy/DummyDiskInstanceSpaceCatalogue.cpp create mode 100644 catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp create mode 100644 catalogue/dummy/DummyDiskSystemCatalogue.cpp create mode 100644 catalogue/dummy/DummyDiskSystemCatalogue.hpp create mode 100644 catalogue/dummy/DummyDriveConfig.hpp create mode 100644 catalogue/dummy/DummyDriveConfigCatalogue.cpp create mode 100644 catalogue/dummy/DummyDriveConfigCatalogue.hpp create mode 100644 catalogue/dummy/DummyDriveStateCatalogue.cpp create mode 100644 catalogue/dummy/DummyDriveStateCatalogue.hpp create mode 100644 catalogue/dummy/DummyFileRecycleLogCatalogue.cpp create mode 100644 catalogue/dummy/DummyFileRecycleLogCatalogue.hpp create mode 100644 catalogue/dummy/DummyLogicalLibraryCatalogue.cpp create mode 100644 catalogue/dummy/DummyLogicalLibraryCatalogue.hpp create mode 100644 catalogue/dummy/DummyMediaTypeCatalogue.cpp create mode 100644 catalogue/dummy/DummyMediaTypeCatalogue.hpp create mode 100644 catalogue/dummy/DummyMountPolicyCatalogue.cpp create mode 100644 catalogue/dummy/DummyMountPolicyCatalogue.hpp create mode 100644 catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.cpp create mode 100644 catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp create mode 100644 catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.cpp create mode 100644 catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp create mode 100644 catalogue/dummy/DummyRequesterMountRuleCatalogue.cpp create mode 100644 catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp create mode 100644 catalogue/dummy/DummySchemaCatalogue.cpp create mode 100644 catalogue/dummy/DummySchemaCatalogue.hpp create mode 100644 catalogue/dummy/DummyStorageClassCatalogue.cpp create mode 100644 catalogue/dummy/DummyStorageClassCatalogue.hpp create mode 100644 catalogue/dummy/DummyTapeCatalogue.cpp create mode 100644 catalogue/dummy/DummyTapeCatalogue.hpp create mode 100644 catalogue/dummy/DummyTapeFileCatalogue.cpp create mode 100644 catalogue/dummy/DummyTapeFileCatalogue.hpp create mode 100644 catalogue/dummy/DummyTapePoolCatalogue.cpp create mode 100644 catalogue/dummy/DummyTapePoolCatalogue.hpp create mode 100644 catalogue/dummy/DummyVirtualOrganizationCatalogue.cpp create mode 100644 catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp create mode 100644 catalogue/interfaces/AdminUserCatalogue.hpp create mode 100644 catalogue/interfaces/ArchiveFileCatalogue.hpp create mode 100644 catalogue/interfaces/ArchiveRouteCatalogue.hpp create mode 100644 catalogue/interfaces/DiskInstanceCatalogue.hpp create mode 100644 catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp create mode 100644 catalogue/interfaces/DiskSystemCatalogue.hpp create mode 100644 catalogue/interfaces/DriveConfigCatalogue.hpp create mode 100644 catalogue/interfaces/DriveStateCatalogue.hpp create mode 100644 catalogue/interfaces/FileRecycleLogCatalogue.hpp create mode 100644 catalogue/interfaces/LogicalLibraryCatalogue.hpp create mode 100644 catalogue/interfaces/MediaTypeCatalogue.hpp create mode 100644 catalogue/interfaces/MountPolicyCatalogue.hpp create mode 100644 catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp create mode 100644 catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp create mode 100644 catalogue/interfaces/RequesterMountRuleCatalogue.hpp create mode 100644 catalogue/interfaces/SchemaCatalogue.hpp create mode 100644 catalogue/interfaces/StorageClassCatalogue.hpp create mode 100644 catalogue/interfaces/TapeCatalogue.hpp create mode 100644 catalogue/interfaces/TapeFileCatalogue.hpp create mode 100644 catalogue/interfaces/TapePoolCatalogue.hpp create mode 100644 catalogue/interfaces/VirtualOrganizationCatalogue.hpp create mode 100644 catalogue/rdbms/CommonExceptions.hpp create mode 100644 catalogue/rdbms/RdbmsAdminUserCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsAdminUserCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsArchiveFileCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsArchiveRouteCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsCatalogue.hpp rename catalogue/{ => rdbms}/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp (99%) rename catalogue/{ => rdbms}/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp (98%) rename catalogue/{ => rdbms}/RdbmsCatalogueGetArchiveFilesItor.cpp (99%) rename catalogue/{ => rdbms}/RdbmsCatalogueGetArchiveFilesItor.hpp (98%) rename catalogue/{ => rdbms}/RdbmsCatalogueGetFileRecycleLogItor.cpp (99%) rename catalogue/{ => rdbms}/RdbmsCatalogueGetFileRecycleLogItor.hpp (96%) rename catalogue/{ => rdbms}/RdbmsCatalogueTapeContentsItor.cpp (99%) rename catalogue/{ => rdbms}/RdbmsCatalogueTapeContentsItor.hpp (97%) create mode 100644 catalogue/rdbms/RdbmsCatalogueUtils.cpp create mode 100644 catalogue/rdbms/RdbmsCatalogueUtils.hpp create mode 100644 catalogue/rdbms/RdbmsDiskInstanceCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsDiskSystemCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsDriveConfigCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsDriveStateCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsDriveStateCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsFileRecycleLogCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsLogicalLibraryCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsMediaTypeCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsMountPolicyCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsSchemaCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsSchemaCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsStorageClassCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsStorageClassCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsTapeCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsTapeCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsTapeFileCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsTapeFileCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsTapePoolCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsTapePoolCatalogue.hpp create mode 100644 catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.cpp create mode 100644 catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleArchiveFileCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleMediaTypeCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleStorageClassCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleTapeCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleTapeCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleTapeFileCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleTapePoolCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp create mode 100644 catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.cpp create mode 100644 catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresStorageClassCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresTapeCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresTapeFileCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresTapePoolCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp create mode 100644 catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.cpp create mode 100644 catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapeCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp create mode 100644 catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.cpp create mode 100644 catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp create mode 100644 catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/CatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/CatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/SchemaCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/TapeCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp create mode 100644 catalogue/retrywrappers/TapePoolRetryCatalogueWrapper.cpp create mode 100644 catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.cpp create mode 100644 catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp rename catalogue/{ => retrywrappers}/retryOnLostConnection.hpp (94%) create mode 100644 catalogue/tests/CatalogueTestUtils.cpp create mode 100644 catalogue/tests/CatalogueTestUtils.hpp create mode 100644 catalogue/tests/DbConfigVersionOfCatalogueTest.cpp create mode 100644 catalogue/tests/DriveConfigCatalogueTest.cpp create mode 100644 catalogue/tests/DriveConfigCatalogueTest.hpp create mode 100644 catalogue/tests/DriveStateCatalogueTest.cpp create mode 100644 catalogue/tests/DriveStateCatalogueTest.hpp rename catalogue/{ => tests}/InMemoryCatalogueTest.cpp (94%) create mode 100644 catalogue/tests/InMemoryVersionOfCatalogueTest.cpp create mode 100644 catalogue/tests/modules/AdminUserCatalogueTest.cpp create mode 100644 catalogue/tests/modules/AdminUserCatalogueTest.hpp create mode 100644 catalogue/tests/modules/ArchiveFileCatalogueTest.cpp create mode 100644 catalogue/tests/modules/ArchiveFileCatalogueTest.hpp create mode 100644 catalogue/tests/modules/ArchiveRouteCatalogueTest.cpp create mode 100644 catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp create mode 100644 catalogue/tests/modules/DiskInstanceCatalogueTest.cpp create mode 100644 catalogue/tests/modules/DiskInstanceCatalogueTest.hpp create mode 100644 catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.cpp create mode 100644 catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp create mode 100644 catalogue/tests/modules/DiskSystemCatalogueTest.cpp create mode 100644 catalogue/tests/modules/DiskSystemCatalogueTest.hpp create mode 100644 catalogue/tests/modules/DriveConfigCatalogueTest.cpp create mode 100644 catalogue/tests/modules/DriveConfigCatalogueTest.hpp create mode 100644 catalogue/tests/modules/DriveStateCatalogueTest.cpp create mode 100644 catalogue/tests/modules/DriveStateCatalogueTest.hpp create mode 100644 catalogue/tests/modules/FileRecycleLogCatalogueTest.cpp create mode 100644 catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp create mode 100644 catalogue/tests/modules/LogicalLibraryCatalogueTest.cpp create mode 100644 catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp create mode 100644 catalogue/tests/modules/MediaTypeCatalogueTest.cpp create mode 100644 catalogue/tests/modules/MediaTypeCatalogueTest.hpp create mode 100644 catalogue/tests/modules/MountPolicyCatalogueTest.cpp create mode 100644 catalogue/tests/modules/MountPolicyCatalogueTest.hpp create mode 100644 catalogue/tests/modules/RequesterActivityMountRuleTest.cpp create mode 100644 catalogue/tests/modules/RequesterActivityMountRuleTest.hpp create mode 100644 catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.cpp create mode 100644 catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp create mode 100644 catalogue/tests/modules/RequesterMountRuleTest.cpp create mode 100644 catalogue/tests/modules/RequesterMountRuleTest.hpp create mode 100644 catalogue/tests/modules/SchemaCatalogueTest.cpp create mode 100644 catalogue/tests/modules/SchemaCatalogueTest.hpp create mode 100644 catalogue/tests/modules/StorageClassCatalogueTest.cpp create mode 100644 catalogue/tests/modules/StorageClassCatalogueTest.hpp create mode 100644 catalogue/tests/modules/TapeCatalogueTest.cpp create mode 100644 catalogue/tests/modules/TapeCatalogueTest.hpp create mode 100644 catalogue/tests/modules/TapeFileCatalogueTest.cpp create mode 100644 catalogue/tests/modules/TapeFileCatalogueTest.hpp create mode 100644 catalogue/tests/modules/TapePoolCatalogueTest.cpp create mode 100644 catalogue/tests/modules/TapePoolCatalogueTest.hpp create mode 100644 catalogue/tests/modules/VirtualOrganizationCatalogueTest.cpp create mode 100644 catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp diff --git a/catalogue/12.0/oracle_catalogue_schema.sql b/catalogue/12.0/oracle_catalogue_schema.sql index e835a40c13..a2cbda1b88 100644 --- a/catalogue/12.0/oracle_catalogue_schema.sql +++ b/catalogue/12.0/oracle_catalogue_schema.sql @@ -120,8 +120,8 @@ CREATE UNIQUE INDEX DISK_INSTANCE_SPACE_DISN_UN_IDX ON DISK_INSTANCE_SPACE(DISK_ CREATE TABLE DISK_SYSTEM( DISK_SYSTEM_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL, - DISK_INSTANCE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, - DISK_INSTANCE_SPACE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, + DISK_INSTANCE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, + DISK_INSTANCE_SPACE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, FILE_REGEXP VARCHAR2(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL, TARGETED_FREE_SPACE NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL, SLEEP_TIME NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL, diff --git a/catalogue/12.0/postgres_catalogue_schema.sql b/catalogue/12.0/postgres_catalogue_schema.sql index 6b150277c8..d6aeaa54e9 100644 --- a/catalogue/12.0/postgres_catalogue_schema.sql +++ b/catalogue/12.0/postgres_catalogue_schema.sql @@ -102,8 +102,8 @@ CREATE UNIQUE INDEX DISK_INSTANCE_SPACE_DISN_UN_IDX ON DISK_INSTANCE_SPACE(DISK_ CREATE TABLE DISK_SYSTEM( DISK_SYSTEM_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL, - DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, - DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, + DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, + DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, FILE_REGEXP VARCHAR(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL, TARGETED_FREE_SPACE NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL, SLEEP_TIME NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL, diff --git a/catalogue/12.0/sqlite_catalogue_schema.sql b/catalogue/12.0/sqlite_catalogue_schema.sql index c0afd68d4e..2406f4f4f6 100644 --- a/catalogue/12.0/sqlite_catalogue_schema.sql +++ b/catalogue/12.0/sqlite_catalogue_schema.sql @@ -74,8 +74,8 @@ CREATE UNIQUE INDEX DISK_INSTANCE_SPACE_DISN_UN_IDX ON DISK_INSTANCE_SPACE(DISK_ CREATE TABLE DISK_SYSTEM( DISK_SYSTEM_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL, - DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, - DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, + DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, + DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, FILE_REGEXP VARCHAR(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL, TARGETED_FREE_SPACE INTEGER CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL, SLEEP_TIME INTEGER CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL, diff --git a/catalogue/AllCatalogueSchema.hpp b/catalogue/AllCatalogueSchema.hpp index f0d9a1458a..6b0aa7fb73 100644 --- a/catalogue/AllCatalogueSchema.hpp +++ b/catalogue/AllCatalogueSchema.hpp @@ -5020,8 +5020,8 @@ namespace catalogue{ "" "CREATE TABLE DISK_SYSTEM(" " DISK_SYSTEM_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL," - " DISK_INSTANCE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, " - " DISK_INSTANCE_SPACE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, " + " DISK_INSTANCE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL," + " DISK_INSTANCE_SPACE_NAME VARCHAR2(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL," " FILE_REGEXP VARCHAR2(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL," " TARGETED_FREE_SPACE NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL," " SLEEP_TIME NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL," @@ -5505,8 +5505,8 @@ namespace catalogue{ "" "CREATE TABLE DISK_SYSTEM(" " DISK_SYSTEM_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL," - " DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, " - " DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, " + " DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL," + " DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL," " FILE_REGEXP VARCHAR(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL," " TARGETED_FREE_SPACE INTEGER CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL," " SLEEP_TIME INTEGER CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL," @@ -6015,8 +6015,8 @@ namespace catalogue{ "" "CREATE TABLE DISK_SYSTEM(" " DISK_SYSTEM_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL," - " DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, " - " DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, " + " DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL," + " DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL," " FILE_REGEXP VARCHAR(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL," " TARGETED_FREE_SPACE NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL," " SLEEP_TIME NUMERIC(20, 0) CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL," diff --git a/catalogue/CMakeLists.txt b/catalogue/CMakeLists.txt index 50fb86782f..77945af0f3 100644 --- a/catalogue/CMakeLists.txt +++ b/catalogue/CMakeLists.txt @@ -33,31 +33,24 @@ include_directories(${CMAKE_BINARY_DIR}/eos_cta ${PROTOBUF3_INCLUDE_DIRS}) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow") -set (CATALOGUE_LIB_SRC_FILES +file (GLOB CATALOGUE_LIB_SRC_FILES ArchiveFileBuilder.cpp ArchiveFileRow.cpp ArchiveFileRowWithoutTimestamps.cpp - Catalogue.cpp CatalogueFactory.cpp CatalogueFactoryFactory.cpp - CatalogueRetryWrapper.cpp CatalogueSchema.cpp + CatalogueUtils.cpp CmdLineTool.cpp DriveConfig.cpp - DummyCatalogue.cpp + dummy/*.cpp InMemoryCatalogue.cpp InMemoryCatalogueFactory.cpp - PostgresCatalogue.cpp PostgresqlCatalogueFactory.cpp - RdbmsCatalogue.cpp - RdbmsCatalogueGetArchiveFilesForRepackItor.cpp - RdbmsCatalogueGetArchiveFilesItor.cpp - RdbmsCatalogueGetFileRecycleLogItor.cpp - RdbmsCatalogueTapeContentsItor.cpp - SchemaCreatingSqliteCatalogue.cpp - SchemaVersion.cpp - SqliteCatalogue.cpp - SqliteCatalogueSchema.cpp + rdbms/*.cpp + rdbms/postgres/*.cpp + rdbms/sqlite/*.cpp + retrywrappers/*.cpp TapeDrivesCatalogueState.cpp TapeFileWritten.cpp TapeForWriting.cpp @@ -66,12 +59,21 @@ set (CATALOGUE_LIB_SRC_FILES ) if (OCCI_SUPPORT) - set (CATALOGUE_LIB_SRC_FILES + file (GLOB CATALOGUE_LIB_SRC_FILES ${CATALOGUE_LIB_SRC_FILES} - OracleCatalogue.cpp - OracleCatalogueFactory.cpp) + OracleCatalogueFactory.cpp + rdbms/oracle/*.cpp + ) endif() +# It use set because it was giving linking error +set (CATALOGUE_LIB_SRC_FILES + ${CATALOGUE_LIB_SRC_FILES} + SchemaCreatingSqliteCatalogue.cpp + SchemaVersion.cpp + SqliteCatalogueSchema.cpp +) + add_library (ctacatalogue SHARED ${CATALOGUE_LIB_SRC_FILES}) @@ -145,11 +147,17 @@ add_custom_command(OUTPUT PostgresCatalogueSchema.cpp COMMAND sed -e '/CTA_SQL_SCHEMA/r postgres_catalogue_schema.cpp' ${CMAKE_CURRENT_SOURCE_DIR}/PostgresCatalogueSchema.before_SQL.cpp > PostgresCatalogueSchema.cpp DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/PostgresCatalogueSchema.before_SQL.cpp postgres_catalogue_schema.cpp) +file (GLOB CATALOGUE_MODULES_TESTS_SRC_FILES + tests/modules/*.cpp +) + set(IN_MEMORY_CATALOGUE_UNIT_TESTS_LIB_SRC_FILES - CatalogueTest.cpp - InMemoryCatalogueTest.cpp - InMemoryVersionOfCatalogueTest.cpp - TapeItemWrittenPointerTest.cpp) + ${CATALOGUE_MODULES_TESTS_SRC_FILES} + TapeItemWrittenPointerTest.cpp + tests/CatalogueTestUtils.cpp + tests/InMemoryCatalogueTest.cpp + tests/InMemoryVersionOfCatalogueTest.cpp +) add_library (ctainmemorycatalogueunittests SHARED ${IN_MEMORY_CATALOGUE_UNIT_TESTS_LIB_SRC_FILES}) @@ -165,8 +173,10 @@ target_link_libraries (ctainmemorycatalogueunittests install (TARGETS ctainmemorycatalogueunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) set (DBCONFIG_CATALOGUE_UNIT_TESTS_LIB_SRC_FILES - CatalogueTest.cpp - DbConfigVersionOfCatalogueTest.cpp) + ${CATALOGUE_MODULES_TESTS_SRC_FILES} + tests/CatalogueTestUtils.cpp + tests/DbConfigVersionOfCatalogueTest.cpp +) add_library (ctadbconfigcatalogueunittests SHARED ${DBCONFIG_CATALOGUE_UNIT_TESTS_LIB_SRC_FILES}) diff --git a/catalogue/Catalogue.hpp b/catalogue/Catalogue.hpp index 30c1cc2719..dd0e009039 100644 --- a/catalogue/Catalogue.hpp +++ b/catalogue/Catalogue.hpp @@ -17,125 +17,35 @@ #pragma once -#include <list> -#include <map> #include <memory> -#include <optional> -#include <set> -#include <string> -#include <tuple> -#include <utility> -#include "catalogue/RecyleTapeFileSearchCriteria.hpp" -#include "catalogue/TapeFileSearchCriteria.hpp" -#include "catalogue/TapePoolSearchCriteria.hpp" -#include "catalogue/TapeSearchCriteria.hpp" -#include "common/dataStructures/DiskSpaceReservationRequest.hpp" -#include "common/dataStructures/VidToTapeMap.hpp" -#include "common/exception/UserError.hpp" +#include "catalogue/interfaces/AdminUserCatalogue.hpp" +#include "catalogue/interfaces/ArchiveFileCatalogue.hpp" +#include "catalogue/interfaces/ArchiveRouteCatalogue.hpp" +#include "catalogue/interfaces/DiskInstanceCatalogue.hpp" +#include "catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp" +#include "catalogue/interfaces/DiskSystemCatalogue.hpp" +#include "catalogue/interfaces/DriveConfigCatalogue.hpp" +#include "catalogue/interfaces/DriveStateCatalogue.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/interfaces/LogicalLibraryCatalogue.hpp" +#include "catalogue/interfaces/MediaTypeCatalogue.hpp" +#include "catalogue/interfaces/MountPolicyCatalogue.hpp" +#include "catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp" +#include "catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp" +#include "catalogue/interfaces/RequesterMountRuleCatalogue.hpp" +#include "catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp" +#include "catalogue/interfaces/RequesterMountRuleCatalogue.hpp" +#include "catalogue/interfaces/SchemaCatalogue.hpp" +#include "catalogue/interfaces/StorageClassCatalogue.hpp" +#include "catalogue/interfaces/TapeCatalogue.hpp" +#include "catalogue/interfaces/TapeFileCatalogue.hpp" +#include "catalogue/interfaces/TapePoolCatalogue.hpp" +#include "catalogue/interfaces/VirtualOrganizationCatalogue.hpp" namespace cta { -namespace common { -namespace dataStructures { -struct AdminUser; -struct ArchiveFile; -struct ArchiveFileQueueCriteria; -struct ArchiveFileSummary; -struct ArchiveRoute; -struct DeleteArchiveRequest; -struct DesiredDriveState; -struct DiskInstance; -struct DiskInstanceSpace; -struct DriveState; -struct FileRecycleLog; -struct LogicalLibrary; -struct MountPolicy; -struct RequesterActivityMountRule; -struct RequesterGroupMountRule; -struct RequesterIdentity; -struct RequesterMountRule; -struct RetrieveFileQueueCriteria; -struct SecurityIdentity; -struct StorageClass; -struct Tape; -struct TapeDrive; -struct TapeDriveStatistics; -struct TapeFile; -struct VirtualOrganization; -} // namespace dataStructures -} // namespace common - -namespace disk { -class DiskSystem; -class DiskSystemList; -} - -namespace log { -class LogContext; -} - namespace catalogue { -template <typename Item> -class CatalogueItor; - -struct CreateMountPolicyAttributes; -struct CreateTapeAttributes; -struct MediaType; -struct MediaTypeWithLogs; -struct SchemaVersion; -struct TapeForWriting; -struct TapeItemWrittenPointer; -struct TapePool; - -CTA_GENERATE_EXCEPTION_CLASS(CommentOrReasonWithMoreSizeThanMaximunAllowed); -CTA_GENERATE_EXCEPTION_CLASS(NegativeDiskSpaceReservationReached); -CTA_GENERATE_EXCEPTION_CLASS(WrongSchemaVersionException); - -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringCartridge); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringComment); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskInstanceName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskInstanceSpaceName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskSystemName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringFileRegexp); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringFreeSpaceQueryURL); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringLogicalLibraryName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringMediaType); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringMediaTypeName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringStorageClassName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringTapePoolName); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringUsername); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVendor); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVid); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVo); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyTapePool); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskInstanceAfterDelete); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskInstanceSpaceAfterDelete); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskSystemAfterDelete); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyLogicalLibrary); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyTape); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentArchiveRoute); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskInstance); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskInstanceSpace); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskSystem); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentLogicalLibrary); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTape); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTapePool); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTapeState); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentVirtualOrganization); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroCapacity); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroCopyNb); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroRefreshInterval); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroSleepTime); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroTargetedFreeSpace); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedExistingDeletedFileCopy); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedMediaTypeUsedByTapes); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByArchiveFiles); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByArchiveRoutes); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByFileRecycleLogs); -CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedTapePoolUsedInAnArchiveRoute); - /** * Abstract class defining the interface to the CTA catalogue responsible for * storing critical information about archive files, tapes and tape files. @@ -145,1286 +55,30 @@ public: /** * Destructor. */ - virtual ~Catalogue() = 0; - - ////////////////////////////////////////////////////////////////// - // START OF METHODS DIRECTLY INVOLVED DATA TRANSFER AND SCHEDULING - ////////////////////////////////////////////////////////////////// - - /** - * Notifies the catalogue that the specified tape was labelled. - * - * @param vid The volume identifier of the tape. - * @param drive The name of tape drive that was used to label the tape. - */ - virtual void tapeLabelled(const std::string &vid, const std::string &drive) = 0; - - /** - * Checks the specified archival could take place and returns a new and - * unique archive file identifier that can be used by a new archive file - * within the catalogue. - * - * @param diskInstanceName The name of the disk instance to which the - * storage class belongs. - * @param storageClassName The name of the storage class of the file to be - * archived. The storage class name is only guaranteed to be unique within - * its disk instance. The storage class name will be used by the Catalogue - * to determine the destination tape pool for each tape copy. - * @param user The user for whom the file is to be archived. This will be - * used by the Catalogue to determine the mount policy to be used when - * archiving the file. - * @return The new archive file identifier. - * @throw UserErrorWithCacheInfo if there was a user error. - */ - virtual uint64_t checkAndGetNextArchiveFileId( - const std::string &diskInstanceName, - const std::string &storageClassName, - const common::dataStructures::RequesterIdentity &user) = 0; - - /** - * Returns the information required to queue an archive request. - * - * @param diskInstanceName The name of the disk instance to which the - * storage class belongs. - * @param storageClassName The name of the storage class of the file to be - * archived. The storage class name is only guaranteed to be unique within - * its disk instance. The storage class name will be used by the Catalogue - * to determine the destination tape pool for each tape copy. - * @param user The user for whom the file is to be archived. This will be - * used by the Catalogue to determine the mount policy to be used when - * archiving the file. - * @return The information required to queue an archive request. - */ - virtual common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria( - const std::string &diskInstanceName, - const std::string &storageClassName, - const common::dataStructures::RequesterIdentity &user) = 0; - - /** - * Returns the list of tapes that can be written to by a tape drive in the - * specified logical library, in other words tapes that are labelled, not - * disabled, not full, not read-only and are in the specified logical library. - * - * @param logicalLibraryName The name of the logical library. - * @return The list of tapes for writing. - */ - virtual std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const = 0; - - virtual common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const = 0; - - /** - * Notifies the catalogue that the specified files have been written to tape. - * - * @param events The tape file written events. - * @throw TapeFseqMismatch If an unexpected tape file sequence number is encountered. - * @throw FileSizeMismatch If an unexpected tape file size is encountered. - */ - virtual void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) = 0; - - /** - * Notifies the CTA catalogue that the specified tape has been mounted in - * order to archive files. - * - * The purpose of this method is to keep track of which drive mounted a given - * tape for archiving files last. - * - * @param vid The volume identifier of the tape. - * @param drive The name of the drive where the tape was mounted. - */ - virtual void tapeMountedForArchive(const std::string &vid, const std::string &drive) = 0; // internal function (noCLI) - - /** - * Prepares for a file retrieval by returning the information required to - * queue the associated retrieve request(s). - * - * @param diskInstanceName The name of the instance from where the retrieval - * request originated - * @param archiveFileId The unique identifier of the archived file that is - * to be retrieved. - * @param user The user for whom the file is to be retrieved. This will be - * used by the Catalogue to determine the mount policy to be used when - * retrieving the file. - * @param activity The activity under which the user wants to start the retrieve - * The call will fail if the activity is set and unknown. - * @param lc The log context. - * - * @return The information required to queue the associated retrieve request(s). - */ - virtual common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile( - const std::string &diskInstanceName, - const uint64_t archiveFileId, - const common::dataStructures::RequesterIdentity &user, - const std::optional<std::string> & activity, - log::LogContext &lc, - const std::optional<std::string> &mountPolicyName = std::nullopt) = 0; - - /** - * Notifies the CTA catalogue that the specified tape has been mounted in - * order to retrieve files. - * - * The purpose of this method is to keep track of which drive mounted a given - * tape for retrieving files last. - * - * @param vid The volume identifier of the tape. - * @param drive The name of the drive where the tape was mounted. - */ - virtual void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) = 0; // internal function (noCLI) - - /** - * This method notifies the CTA catalogue that there is no more free space on - * the specified tape. - * - * @param vid The volume identifier of the tape. - */ - virtual void noSpaceLeftOnTape(const std::string &vid) = 0; - - //////////////////////////////////////////////////////////////// - // END OF METHODS DIRECTLY INVOLVED DATA TRANSFER AND SCHEDULING - //////////////////////////////////////////////////////////////// - - virtual void createAdminUser(const common::dataStructures::SecurityIdentity &admin, const std::string &username, const std::string &comment) = 0; - virtual void deleteAdminUser(const std::string &username) = 0; - virtual std::list<common::dataStructures::AdminUser> getAdminUsers() const = 0; - virtual void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, const std::string &username, const std::string &comment) = 0; - - /** - * Creates the specified Virtual Organization - * @param admin The administrator. - * @param vo the Virtual Organization - */ - virtual void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo) = 0; - - /** - * Deletes the specified Virtual Organization - * @param voName the name of the VirtualOrganization to delete - */ - virtual void deleteVirtualOrganization(const std::string &voName) = 0; - - /** - * Get all the Virtual Organizations from the Catalogue - * @return the list of all the Virtual Organizations - */ - virtual std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const = 0; - - /** - * Get the virtual organization corresponding to the tapepool passed in parameter - * @param tapepoolName the name of the tapepool which we want the virtual organization - * @return the VirtualOrganization associated to the tapepool passed in parameter - */ - virtual common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool(const std::string & tapepoolName) const = 0; - - /** - * Get, from the cache, the virtual organization corresponding to the tapepool passed in parameter - * @param tapepoolName the name of the tapepool which we want the virtual organization - * @return the VirtualOrganization associated to the tapepool passed in parameter - */ - virtual common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool(const std::string & tapepoolName) const = 0; - - /** - * Modifies the name of the specified Virtual Organization. - * - * @param currentVoName The current name of the Virtual Organization. - * @param newVoName The new name of the Virtual Organization. - */ - virtual void modifyVirtualOrganizationName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, const std::string &newVoName) = 0; - - /** - * Modifies the max number of allocated drives for read for the specified Virtual Organization - * - * @param voName the VO name - * @param readMaxDrives the new max number of allocated drives for read for the specified Virtual Organization - */ - virtual void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) = 0; - - /** - * Modifies the max number of allocated drives for write for the specified Virtual Organization - * - * @param voName the VO name - * @param writeMaxDrives the new max number of allocated drives for write for the specified Virtual Organization - */ - virtual void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) = 0; - - /** - * Modifies the max size of files for the specified Virtual Organization - * - * @param voName the VO name - * @param maxFileSize the new max file size for the specified Virtual Organization - */ - virtual void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) = 0; - - /** - * Modifies the comment of the specified Virtual Organization - * - * @param voName The name of the Virtual Organization. - * @param comment The new comment of the Virtual Organization. - */ - virtual void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) = 0; - - /** - * Modifies the comment of the specified Virtual Organization - * - * @param voName The name of the Virtual Organization. - * @param diskInstance The new disk instance of the Virtual Organization. - */ - virtual void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) = 0; - - /** - * Creates the specified storage class. - * - * @param admin The administrator. - * @param storageClass The storage class. - */ - virtual void createStorageClass( - const common::dataStructures::SecurityIdentity &admin, - const common::dataStructures::StorageClass &storageClass) = 0; - - /** - * Deletes the specified storage class. - * - * @param storageClassName The name of the storage class which is only - * guaranteed to be unique within its disk instance. - */ - virtual void deleteStorageClass(const std::string &storageClassName) = 0; - - virtual std::list<common::dataStructures::StorageClass> getStorageClasses() const = 0; - virtual common::dataStructures::StorageClass getStorageClass(const std::string &name) const = 0; - - virtual void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbCopies) = 0; - virtual void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; - virtual void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) = 0; - - /** - * Modifies the name of the specified storage class. - * - * @param currentName The current name of the storage class. - * @param newName The new name of the storage class. - */ - virtual void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) = 0; - - /** - * Creates a tape media type. - * - * @param admin The administrator. - * @param mediaType The tape media type. - */ - virtual void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) = 0; - - /** - * Deletes the specified tape media type. - * - * @param name The name of the tape media type. - */ - virtual void deleteMediaType(const std::string &name) = 0; - - /** - * Returns all tape media types. - * - * @return All tape media types. - */ - virtual std::list<MediaTypeWithLogs> getMediaTypes() const = 0; - - /** - * Return the media type associated to the tape corresponding to the - * vid passed in parameter - * @param vid the vid of the tape to return its media type - * @return the media type associated to the tape corresponding to the vid passed in parameter - */ - virtual MediaType getMediaTypeByVid(const std::string & vid) const = 0; - - /** - * Modifies the name of the specified tape media type. - * - * @param admin The administrator. - * @param currentName The current name of the tape media type. - * @param newName The new name of the tape media type. - */ - virtual void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) = 0; - - /** - * Modifies the cartidge of the specified tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param cartridge The new cartidge. - */ - virtual void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &cartridge) = 0; - - /** - * Modify the capacity in bytes of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param capacityInBytes The new capacity in bytes. - */ - virtual void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) = 0; - - /** - * Modify the SCSI primary density code of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param primaryDensityCode The new SCSI primary density code. - */ - virtual void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) = 0; - - /** - * Modify the SCSI secondary density code of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param secondaryDensityCode The new SCSI secondary density code. - */ - virtual void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) = 0; - - /** - * Modify the number of tape wraps of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param nbWraps The new number of tape wraps. - */ - virtual void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint32_t> &nbWraps) = 0; - - /** - * Modify the minimum longitudinal tape position of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param minLPos The new minimum longitudinal tape position. - */ - virtual void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &minLPos) = 0; - - /** - * Modify the maximum longitudinal tape position of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param maxLPos The new maximum longitudinal tape position. - */ - virtual void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &maxLPos) = 0; - - /** - * Modify the comment of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param comment The new comment. - */ - virtual void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; - - virtual void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::optional<std::string> &supply, const std::string &comment) = 0; - - /** - * Deletes the specified tape pool. - - * @name The name of th epatpe pool. - * @throw UserSpecifiedTapePoolUsedInAnArchiveRoute If the specified tape pool - * is used in an archive route. - */ - virtual void deleteTapePool(const std::string &name) = 0; - - virtual std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria = TapePoolSearchCriteria()) const = 0; - - /** - * @return The tape pool with the specified name. - * @param tapePoolName The name of the tape pool. - */ - virtual std::optional<TapePool> getTapePool(const std::string &tapePoolName) const = 0; - - virtual void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) = 0; - virtual void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbPartialTapes) = 0; - virtual void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; - 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 &storageClassName, - const uint32_t copyNb, - const std::string &tapePoolName, - const std::string &comment) = 0; - - /** - * Deletes the specified archive route. - * - * @param storageClassName The name of the storage class. - * @param copyNb The copy number of the tape file. - */ - virtual void deleteArchiveRoute( - const std::string &storageClassName, - const uint32_t copyNb) = 0; - - virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const = 0; - - /** - * @return the archive routes of the given storage class and destination tape - * pool. - * - * Under normal circumstances this method should return either 0 or 1 route. - * For a given storage class there should be no more than one route to any - * given tape pool. - * - * @param storageClassName The name of the storage class. - * @param tapePoolName The name of the tape pool. - */ - virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes( - const std::string &storageClassName, - const std::string &tapePoolName) const = 0; - - /** - * Modifies the tape pool of the specified archive route. - * - * @param admin The administrator. - * @param storageClassName The name of the storage class. - * @param copyNb The copy number. - * @param tapePoolName The name of the tape pool. - * @throw UserSpecifiedANonExistentTapePool if the user specified a - * non-existent tape pool. - */ - virtual void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) = 0; - - virtual void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) = 0; - - virtual void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool isDisabled, const std::string &comment) = 0; - virtual void deleteLogicalLibrary(const std::string &name) = 0; - virtual std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const = 0; - - /** - * Modifies the name of the specified logical library. - * - * @param admin The administrator. - * @param currentName The current name of the logical library. - * @param newName The new name of the logical library. - */ - virtual void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) = 0; - - virtual void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; - virtual void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &disabledReason) = 0; - virtual void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) = 0; - - /** - * Creates a tape which is assumed to have isFromCastor disabled. - * - * @param admin The administrator. - * @param tape The attributes of the tape to be created. - */ - virtual void createTape( - const common::dataStructures::SecurityIdentity &admin, - const CreateTapeAttributes &tape) = 0; - - virtual void deleteTape(const std::string &vid) = 0; - - /** - * Returns the list of tapes that meet the specified search criteria. - * - * @param searchCriteria The search criteria. - * @return The list of tapes. - * @throw UserSpecifiedANonExistentTapePool if the user specified a - * non-existent tape pool. - */ - virtual std::list<common::dataStructures::Tape> getTapes( - const TapeSearchCriteria &searchCriteria = TapeSearchCriteria()) const = 0; - - /** - * Returns the tape with the specified volume identifier. - * - * This method will throw an exception if it cannot find the specified tape. - * - * @param vids The tape volume identifier (VID). - * @return Map from tape volume identifier to tape. - */ - virtual common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const = 0; - - /** - * Returns the tapes with the specified volume identifiers. - * - * This method will throw an exception if it cannot find ALL of the specified - * tapes. - * - * @param vids The tape volume identifiers (VIDs). - * @return Map from tape volume identifier to tape. - */ - virtual common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const = 0; - - /** - * Returns map from VID to logical library name for specified set of VIDs. - * - * @param vids The tape volume identifiers (VIDs). - * @return map from VID to logical library name. - */ - virtual std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const = 0; - - /** - * Reclaims the specified tape. - * - * This method will throw an exception if the specified tape does not exist. - * - * This method will throw an exception if the specified tape is not FULL. - * - * This method will throw an exception if there is still at least one tape - * file recorded in the catalogue as being on the specified tape. - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be reclaimed. - * @param lc the logContext - */ - virtual void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, cta::log::LogContext & lc) = 0; - - /** - * Checks the specified tape for the tape label command. - * - * This method checks if the tape is safe to be labeled and will throw an - * exception if the specified tape does not ready to be labeled. - * - * @param vid The volume identifier of the tape to be checked. - */ - virtual void checkTapeForLabel(const std::string &vid) = 0; - - /** - * Returns the number of any files contained in the tape identified by its vid - * @param vid the vid in which we will the number of files - * @return the number of files on the tape - */ - virtual uint64_t getNbFilesOnTape(const std::string &vid) const = 0; - - virtual void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) = 0; - virtual void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &vendor) = 0; - virtual void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &logicalLibraryName) = 0; - virtual void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &tapePoolName) = 0; - virtual void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &encryptionKeyName) = 0; - virtual void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &verificationStatus) = 0; - - /** - * Modify the state of the specified tape - * @param admin, the person or the system who modified the state of the tape - * @param vid the VID of the tape to change the state - * @param state the new state - * @param prev_state the previous state, if value is not std::nullopt then it will be used to validate that the state transition proceeds as expected - * @param stateReason the reason why the state changes, if the state is ACTIVE and the stateReason is std::nullopt, the state will be reset to null - */ - virtual void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, const common::dataStructures::Tape::State & state, const std::optional<common::dataStructures::Tape::State> & prev_state, const std::optional<std::string> & stateReason) = 0; - - /** - * Sets the full status of the specified tape. - * - * Please note that this method is to be called by the CTA front-end in - * response to a command from the CTA command-line interface (CLI). - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be marked as full. - * @param fullValue Set to true if the tape is full. - */ - virtual void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const bool fullValue) = 0; - - /** - * Sets the dirty status of the specified tape. - * - * Please note that this method is to be called by the CTA front-end in - * response to a command from the CTA command-line interface (CLI). - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be marked as full. - * @param dirty Set to true if the tape is dirty. - */ - virtual void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const bool dirty) = 0; - - /** - * This method notifies the CTA catalogue to set the specified tape is from CASTOR. - * This method only for unitTests and MUST never be called in CTA!!! - * - * @param vid The volume identifier of the tape. - */ - virtual void setTapeIsFromCastorInUnitTests(const std::string &vid) = 0; - - virtual void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string & reason) = 0; - virtual void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string & reason) = 0; - - virtual void setTapeDirty(const std::string & vid) = 0; - - /** - * Modifies the tape comment - * If the comment == std::nullopt, it will delete the comment from the tape table - * @param admin the admin who removes the comment - * @param vid the vid of the tape to remove the comment - * @param comment the new comment. If comment == std::nullopt, the comment will be deleted. - */ - virtual void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::optional<std::string> &comment) = 0; - - virtual void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) = 0; - virtual void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &comment) = 0; - virtual void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) = 0; - virtual void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &comment) = 0; - virtual void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) = 0; - virtual void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) = 0; - - virtual void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, const CreateMountPolicyAttributes & mountPolicy) = 0; - - /** - * Returns the list of all existing mount policies. - * - * @return the list of all existing mount policies. - */ - virtual std::list<common::dataStructures::MountPolicy> getMountPolicies() const = 0; - - /** - * Returns the mount policy with the specified name. - * - * @return the specified mount policy - */ - virtual std::optional<common::dataStructures::MountPolicy> getMountPolicy(const std::string &mountPolicyName) const = 0; - - - /** - * Returns the cached list of all existing mount policies. - * - * @return the list of all existing mount policies. - */ - virtual std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const = 0; - - /** - * Deletes the specified mount policy. - * - * @param name The name of the mount policy. - */ - virtual void deleteMountPolicy(const std::string &name) = 0; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester+matching activities. - * - * Please note that requester-activity mount-rules overrule requester - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstance The name of the disk instance to which the requester - * belongs. - * @param activityRegex The regex to match request activities - * @param requesterName The name of the requester which is only guarantted to - * be unique within its disk instance. - * @param comment Comment. - */ - virtual void createRequesterActivityMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstance, - const std::string &requesterName, - const std::string &activityRegex, - const std::string &comment) = 0; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester + activity. - * - * @return the rules that specify which mount policy is be used for which - * requester + activity. - */ - virtual std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const = 0; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester belongs. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - * @param activityRegex The regex to match request activities - */ - virtual void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) = 0; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester. - * - * Please note that requester mount-rules overrule requester-group - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstance The name of the disk instance to which the requester - * belongs. - * @param requesterName The name of the requester which is only guarantted to - * be unique within its disk instance. - * @param comment Comment. - */ - virtual void createRequesterMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstance, - const std::string &requesterName, - const std::string &comment) = 0; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester. - * - * @return the rules that specify which mount policy is be used for which - * requester. - */ - virtual std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const = 0; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester belongs. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - */ - virtual void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) = 0; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester group. - * - * Please note that requester mount-rules overrule requester-group - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstanceName The name of the disk instance to which the - * requester group belongs. - * @param requesterGroupName The name of the requester group which is only - * guarantted to be unique within its disk instance. - * @param comment Comment. - */ - virtual void createRequesterGroupMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstanceName, - const std::string &requesterGroupName, - const std::string &comment) = 0; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester group. - * - * @return the rules that specify which mount policy is be used for which - * requester group. - */ - virtual std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const = 0; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester group belongs. - * @param requesterGroupName The name of the requester group which is only - * guaranteed to be unique within its disk instance. - */ - virtual void deleteRequesterGroupMountRule( - const std::string &diskInstanceName, - const std::string &requesterGroupName) = 0; - - virtual void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t archivePriority) = 0; - virtual void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minArchiveRequestAge) = 0; - virtual void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t retrievePriority) = 0; - virtual void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minRetrieveRequestAge) = 0; - virtual void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) = 0; - - /** - * Returns all the disk systems within the CTA catalogue. - * - * @return The disk systems. - * requester group. - */ - virtual disk::DiskSystemList getAllDiskSystems() const = 0; - - /** - * Creates a disk system. - * - * @param admin The administrator. - * @param name The name of the disk system. - * @param fileRegexp The regular expression allowing matching destination URLs - * for this disk system. - * @param freeSpaceQueryURL The query URL that describes a method to query the - * free space from the disk system. - * @param refreshInterval The refresh interval (seconds) defining how long do - * we use a free space value. - * @param targetedFreeSpace The targeted free space (margin) based on the free - * space update latency (inherent to the file system and induced by the refresh - * interval), and the expected external bandwidth from sources external to CTA. - * @param comment Comment. - */ - virtual void createDiskSystem( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &diskInstanceName, - const std::string &diskInstanceSpaceName, - const std::string &fileRegexp, - const uint64_t targetedFreeSpace, - const time_t sleepTime, - const std::string &comment) = 0; - - /** - * Deletes a disk system. - * - * @param name The name of the disk system. - */ - virtual void deleteDiskSystem(const std::string &name) = 0; - - virtual void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &fileRegexp) = 0; - virtual void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t targetedFreeSpace) = 0; - virtual void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t sleepTime) = 0; - virtual void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) = 0; - virtual void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceName) = 0; - virtual void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceSpaceName) = 0; - - /** - * Deletes a disk instance space. - * - * @param name The name of the disk instance. - * @param diskInstance The disk instance of the disk instance space. - */ - virtual void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) = 0; - - /** - * Creates the specified Disk Instance Space - * @param admin The administrator. - * @param name the name of the new disk instance space - * @param diskInstance the disk instance associated to the disk instance space - * @param freeSpaceQueryURL the URL to query to obtain the disk instance space free space - * @param refreshInterval the period to query for disk instance space free space - * @param comment the comment of the new disk instance space - */ - virtual void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &diskInstance, - const std::string &freeSpaceQueryURL, - const uint64_t refreshInterval, - const std::string &comment) = 0; - - /** - * Returns all the disk instance spaces within the CTA catalogue. - * - * @return The disk instance spaces in the CTA catalogue. - */ - virtual std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const = 0; - - /** - * Deletes a disk instance. - * - * @param name The name of the disk instance. - */ - virtual void deleteDiskInstance(const std::string &name) = 0; - - virtual void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &comment) = 0; - virtual void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) = 0; - virtual void modifyDiskInstanceSpaceFreeSpace(const std::string &name, - const std::string &diskInstance, const uint64_t freeSpace) = 0; - virtual void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, - const std::string &freeSpaceQueryURL) = 0; - - - /** - * Changes the comment of the specified disk instance - * @param admin The administrator. - * @param name the name of the disk instance - * @param comment the new comment of the disk instance - */ - virtual void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) = 0; - - /** - * Creates the specified Disk Instance - * @param admin The administrator. - * @param name the name of the new disk instance - * @param comment the comment of the new disk instance - */ - virtual void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &comment) = 0; - - /** - * Returns all the disk instances within the CTA catalogue. - * - * @return The disk instances in the CTA catalogue. - */ - virtual std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const = 0; - - - typedef CatalogueItor<common::dataStructures::ArchiveFile> ArchiveFileItor; - - /** - * Returns the specified archive files. Please note that the list of files - * is ordered by archive file ID. - * - * @param searchCriteria The search criteria. - * @return The archive files. - */ - virtual ArchiveFileItor getArchiveFilesItor( - const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; - - /** - * Returns the specified archive file. If the search criteria result in more than one tape file being returned - * an exception is thrown. - * @param searchCriteria The search criteria. - * @return The archive file. - */ - virtual common::dataStructures::ArchiveFile getArchiveFileForDeletion(const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; - - typedef CatalogueItor<common::dataStructures::FileRecycleLog> FileRecycleLogItor; - - /** - * Returns all the currently deleted files by looking at the FILE_RECYCLE_LOG table - * - * @return The deleted archive files ordered by archive file ID. - */ - virtual FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const = 0; - - - /** - * Restores the deleted file in the Recycle log that match the criteria passed - * - * @param searchCriteria The search criteria - * @param newFid the new Fid of the archive file (if the archive file must be restored) - */ - virtual void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, const std::string &newFid) = 0; - - - /** - * Returns the specified files in tape file sequence order. - * - * @param vid The volume identifier of the tape. - * @param startFSeq The file sequence number of the first file. Please note - * that there might not be a file with this exact file sequence number. - * @param maxNbFiles The maximum number of files to be returned. - * @return The specified files in tape file sequence order. - */ - virtual std::list<common::dataStructures::ArchiveFile> getFilesForRepack( - const std::string &vid, - const uint64_t startFSeq, - const uint64_t maxNbFiles) const = 0; - - /** - * Returns all the tape copies (no matter their VIDs) of the archive files - * associated with the tape files on the specified tape in FSEQ order - * starting at the specified startFSeq. - * - * @param vid The volume identifier of the tape. - * @param startFSeq The file sequence number of the first file. Please note - * that there might not be a file with this exact file sequence number. - * @return The specified files in FSEQ order. - */ - virtual ArchiveFileItor getArchiveFilesForRepackItor( - const std::string &vid, - const uint64_t startFSeq) const = 0; - - /** - * Returns a summary of the tape files that meet the specified search - * criteria. - * - * @param searchCriteria The search criteria. - * @return The summary. - */ - virtual common::dataStructures::ArchiveFileSummary getTapeFileSummary( - const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; - - /** - * Deletes a tape file copy - * - * @param file The tape file to delete - * @param reason The reason for deleting the tape file copy - */ - virtual void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) = 0; - - /** - * Returns the archive file with the specified unique identifier. - * - * This method assumes that the archive file being requested exists and will - * therefore throw an exception if it does not. - * - * Please note that an archive file with no associated tape files is - * considered not to exist by this method. - * - * @param id The unique identifier of the archive file. - * @return The archive file. - */ - virtual common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const = 0; - - /** - * !!!!!!!!!!!!!!!!!!! THIS METHOD SHOULD NOT BE USED !!!!!!!!!!!!!!!!!!!!!!! - * Deletes the specified archive file and its associated tape copies from the - * catalogue. - * - * Please note that the name of the disk instance is specified in order to - * prevent a disk instance deleting an archive file that belongs to another - * disk instance. - * - * Please note that this method is idempotent. If the file to be deleted does - * not exist in the CTA catalogue then this method returns without error. - * - * @param instanceName The name of the instance from where the deletion request - * originated - * @param archiveFileId The unique identifier of the archive file. - * @param lc The log context. - * @return The metadata of the deleted archive file including the metadata of - * the associated and also deleted tape copies. - */ - virtual void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &instanceName, const uint64_t archiveFileId, - log::LogContext &lc) = 0; - - /** - * Returns true if the specified user running the CTA command-line tool on - * the specified host has administrator privileges. - * - * @param admin The administrator. - * @return True if the specified user running the CTA command-line tool on - * the specified host has administrator privileges. - */ - virtual bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const = 0; - - /** - * Checks that the most trivial query goes through. Throws an exception if not. - */ - virtual void ping() = 0; - - /** - * Checks that the online database schema MAJOR version number matches the schema MAJOR version number defined in version.h - */ - virtual void verifySchemaVersion() = 0; - - /** - * Returns the SchemaVersion object corresponding to the catalogue schema version: - * - SCHEMA_VERSION_MAJOR - * - SCHEMA_VERSION_MINOR - * - SCHEMA_VERSION_MAJOR_NEXT (future major version number of the schema in case of upgrade) - * - SCHEMA_VERSION_MINOR_NEXT (future minor version number of the schema in case of upgrade) - * - STATUS (UPGRADING or PRODUCTION) - * - * @return The SchemaVersion object corresponding to the catalogue schema version - */ - virtual SchemaVersion getSchemaVersion() const = 0; - - /** - * Returns true if the specified tape pool exists. - * - * @param tapePoolName The name of the tape pool. - * @return True if the tape pool exists. - */ - virtual bool tapePoolExists(const std::string &tapePoolName) const = 0; - - /** - * Returns true if the specified tape exists. - * - * @param vid The volume identifier of the tape. - * @return True if the tape exists. - */ - virtual bool tapeExists(const std::string &vid) const = 0; - - /** - * Returns true if the specified disk system exists. - * - * @param name The name identifier of the disk system. - * @return True if the tape exists. - */ - virtual bool diskSystemExists(const std::string &name) const = 0; - - /** - * Updates the disk file ID of the specified archive file. - * - * @param archiveFileId The unique identifier of the archive file. - * @param diskInstance The instance name of the source disk system. - * @param diskFileId The identifier of the source disk file which is unique - * within it's host disk system. Two files from different disk systems may - * have the same identifier. The combination of diskInstance and diskFileId - * must be globally unique, in other words unique within the CTA catalogue. - */ - virtual void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, - const std::string &diskFileId) = 0; - - /** - * Insert the ArchiveFile and all its tape files in the FILE_RECYCLE_LOG table. - * There will be one entry on the FILE_RECYCLE_LOG table per deleted tape file - * - * @param request the DeleteRequest object that holds information about the file to delete. - * @param lc the logContext - */ - virtual void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, - log::LogContext & lc) = 0; - - /** - * - * Deletes the specified archive file and its associated tape copies from the - * recycle-bin - * - * Please note that this method is idempotent. If the file to be deleted does - * not exist in the CTA catalogue then this method returns without error. - * - * @param archiveFileId The unique identifier of the archive file. - * @param lc The log context. - */ - virtual void deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc) = 0; - - /** - * Deletes all the log entries corresponding to the vid passed in parameter. - * - * Please note that this method is idempotent. If there are no recycle log - * entries associated to the vid passed in parameter, the method will return - * without any error. - * - * @param vid, the vid of the files to be deleted - * @param lc, the logContext - */ - virtual void deleteFilesFromRecycleLog(const std::string & vid, log::LogContext & lc) = 0; - - /** - * Creates the specified Tape Drive - * @param tapeDrive Parameters of the Tape Drive. - */ - virtual void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) = 0; - - /** - * Gets the names of all stored Tape Drive - * @return List of tape drive names - */ - virtual std::list<std::string> getTapeDriveNames() const = 0; - - /** - * Gets the information of all Tape Drives - * @return Parameters of all Tape Drives. - */ - virtual std::list<common::dataStructures::TapeDrive> getTapeDrives() const = 0; - - /** - * Gets the information of the specified Tape Drive - * @param tapeDriveName The name of the tape drive. - * @return Parameters of the Tape Drive. - */ - virtual std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const = 0; - - /** - * Modifies the desired state parameters off the specified Tape Drive - * @param tapeDriveName Name of the Tape Drive. - * @param desiredState Desired state parameters of the Tape Drive. - */ - virtual void setDesiredTapeDriveState(const std::string& tapeDriveName, - const common::dataStructures::DesiredDriveState &desiredState) = 0; - - virtual void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, - const std::string &comment) = 0; - - virtual void updateTapeDriveStatistics(const std::string& tapeDriveName, - const std::string& host, const std::string& logicalLibrary, - const common::dataStructures::TapeDriveStatistics& statistics) = 0; - - virtual void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) = 0; - - /** - * Deletes the entry of a Tape Drive - * @param tapeDriveName The name of the tape drive. - */ - virtual void deleteTapeDrive(const std::string &tapeDriveName) = 0; - - /* - * Struct with a drive configuration - */ - struct DriveConfig { - std::string tapeDriveName; - std::string category; - std::string keyName; - std::string value; - std::string source; - }; - - /** - * Creates a specified parameter of the configuration for a certain Tape Drive - * @param tapeDriveName The name of the tape drive. - * @param category The category of the parameter. - * @param keyName The key of the parameter. - * @param value The value of the parameter. - * @param source The source from which the parameter was gotten. - */ - virtual void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) = 0; - - /** - * Gets all Drive Configurations of all TapeDrives. - * @return Drive Configurations of all TapeDrives. - */ - virtual std::list<DriveConfig> getTapeDriveConfigs() const = 0; - - /** - * Gets the Key and Names of configurations of all TapeDrives - * @return Keys and Names of configurations. - */ - virtual std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const = 0; - - /** - * Modifies a specified parameter of the configuration for a certain Tape Drive - * @param tapeDriveName The name of the tape drive. - * @param category The category of the parameter. - * @param keyName The key of the parameter. - * @param value The value of the parameter. - * @param source The source from which the parameter was gotten. - */ - virtual void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) = 0; - - /** - * Gets a specified parameter of the configuration for a certain Tape Drive - * @param tapeDriveName The name of the tape drive. - * @param keyName The key of the parameter. - * @return Returns the category, value and source of a parameter of the configuarion - */ - virtual std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, - const std::string &keyName) const = 0; - - /** - * Deletes the entry of a Drive Configuration - * @param tapeDriveName The name of the tape drive. - */ - virtual void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) = 0; - - /** - * Gets the disk space reservations for all disk systems - */ - virtual std::map<std::string, uint64_t> getDiskSpaceReservations() const = 0; - - /** - * Adds to the current disk space reservation - */ - virtual void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) = 0; - - /** - * Subtracts from the current disk space reservation. - * - * If the amount released exceeds the current reservation, the reservation will be reduced to zero. - */ - virtual void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) = 0; - - /** - * Changes the name of hte storage class - * @param archiveFileId Id for file found in ARCHIVE_FILE - * @param newStorageClassName The name of the storage class - */ - virtual void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, const std::string& newStorageClassName) const = 0; - - /** - * Changes the fxid in for a archive file - * @param archiveId The archive file id - * @param fxId The eos fxid related to the archive file - * @param diskInstance Disk instace - */ - virtual void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, const std::string &diskInstance) const = 0; - + virtual ~Catalogue() = default; + + // Table Methods + virtual const std::unique_ptr<SchemaCatalogue>& Schema() = 0; + virtual const std::unique_ptr<AdminUserCatalogue>& AdminUser() = 0; + virtual const std::unique_ptr<DiskSystemCatalogue>& DiskSystem() = 0; + virtual const std::unique_ptr<DiskInstanceCatalogue>& DiskInstance() = 0; + virtual const std::unique_ptr<DiskInstanceSpaceCatalogue>& DiskInstanceSpace() = 0; + virtual const std::unique_ptr<VirtualOrganizationCatalogue>& VO() = 0; + virtual const std::unique_ptr<ArchiveRouteCatalogue>& ArchiveRoute() = 0; + virtual const std::unique_ptr<MediaTypeCatalogue>& MediaType() = 0; + virtual const std::unique_ptr<StorageClassCatalogue>& StorageClass() = 0; + virtual const std::unique_ptr<TapePoolCatalogue>& TapePool() = 0; + virtual const std::unique_ptr<TapeCatalogue>& Tape() = 0; + virtual const std::unique_ptr<MountPolicyCatalogue>& MountPolicy() = 0; + virtual const std::unique_ptr<RequesterActivityMountRuleCatalogue>& RequesterActivityMountRule() = 0; + virtual const std::unique_ptr<RequesterMountRuleCatalogue>& RequesterMountRule() = 0; + virtual const std::unique_ptr<RequesterGroupMountRuleCatalogue>& RequesterGroupMountRule() = 0; + virtual const std::unique_ptr<LogicalLibraryCatalogue>& LogicalLibrary() = 0; + virtual const std::unique_ptr<TapeFileCatalogue>& TapeFile() = 0; + virtual const std::unique_ptr<FileRecycleLogCatalogue>& FileRecycleLog() = 0; + virtual const std::unique_ptr<DriveConfigCatalogue>& DriveConfig() = 0; + virtual const std::unique_ptr<DriveStateCatalogue>& DriveState() = 0; + virtual const std::unique_ptr<ArchiveFileCatalogue>& ArchiveFile() = 0; }; // class Catalogue } // namespace catalogue diff --git a/catalogue/DbConfigVersionOfCatalogueTest.cpp b/catalogue/CatalogueExceptions.hpp similarity index 75% rename from catalogue/DbConfigVersionOfCatalogueTest.cpp rename to catalogue/CatalogueExceptions.hpp index 54eabde720..24b3c86f92 100644 --- a/catalogue/DbConfigVersionOfCatalogueTest.cpp +++ b/catalogue/CatalogueExceptions.hpp @@ -1,6 +1,6 @@ /* * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN + * @copyright Copyright © 2022 CERN * @license This program is free software, distributed under the terms of the GNU General Public * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your @@ -15,11 +15,13 @@ * submit itself to any jurisdiction. */ -#include "catalogue/CatalogueTest.hpp" -#include "tests/GlobalCatalogueFactoryForUnitTests.hpp" +#pragma once -namespace unitTests { +#include <common/exception/Exception.hpp> -INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_CatalogueTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); - -} // namespace unitTests +namespace cta { +namespace exception { +CTA_GENERATE_EXCEPTION_CLASS(NegativeDiskSpaceReservationReached); +CTA_GENERATE_EXCEPTION_CLASS(CommentOrReasonWithMoreSizeThanMaximunAllowed); +} +} diff --git a/catalogue/CatalogueTest.hpp b/catalogue/CatalogueTest.hpp deleted file mode 100644 index 675b367cac..0000000000 --- a/catalogue/CatalogueTest.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include <gtest/gtest.h> - -#include <list> -#include <map> -#include <memory> -#include <set> -#include <string> - -#include "catalogue/Catalogue.hpp" -#include "catalogue/CatalogueFactory.hpp" -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/CreateTapeAttributes.hpp" -#include "catalogue/MediaTypeWithLogs.hpp" -#include "catalogue/TapePool.hpp" -#include "common/dataStructures/AdminUser.hpp" -#include "common/dataStructures/ArchiveFile.hpp" -#include "common/dataStructures/DiskInstance.hpp" -#include "common/dataStructures/LogicalLibrary.hpp" -#include "common/dataStructures/SecurityIdentity.hpp" -#include "common/dataStructures/StorageClass.hpp" -#include "common/dataStructures/VirtualOrganization.hpp" -#include "common/log/DummyLogger.hpp" - -namespace unitTests { - -class cta_catalogue_CatalogueTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { -public: - cta_catalogue_CatalogueTest(); - -protected: - cta::log::DummyLogger m_dummyLog; - std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; - const cta::common::dataStructures::SecurityIdentity m_localAdmin; - const cta::common::dataStructures::SecurityIdentity m_admin; - const cta::common::dataStructures::VirtualOrganization m_vo; - const cta::common::dataStructures::VirtualOrganization m_anotherVo; - const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; - const cta::common::dataStructures::StorageClass m_anotherStorageClass; - const cta::common::dataStructures::StorageClass m_storageClassDualCopy; - const cta::common::dataStructures::StorageClass m_storageClassTripleCopy; - const cta::common::dataStructures::DiskInstance m_diskInstance; - const cta::catalogue::MediaType m_mediaType; - const cta::catalogue::CreateTapeAttributes m_tape1; - const cta::catalogue::CreateTapeAttributes m_tape2; - const cta::catalogue::CreateTapeAttributes m_tape3; - - virtual void SetUp(); - - virtual void TearDown(); - - /** - * Creates a map from logical library name to logical library given the - * specified list of logical libraries. - * - * @param listOfLibs The list of logical libraries from which the map shall - * be created. - * @return The map from logical library name to logical library. - */ - std::map<std::string, cta::common::dataStructures::LogicalLibrary> logicalLibraryListToMap( - const std::list<cta::common::dataStructures::LogicalLibrary> &listOfLibs); - - /** - * Creates a map from VID to tape given the specified list of tapes. - * - * @param listOfTapes The list of tapes from which the map shall be created. - * @return The map from VID to tape. - */ - std::map<std::string, cta::common::dataStructures::Tape> tapeListToMap( - const std::list<cta::common::dataStructures::Tape> &listOfTapes); - - /** - * Creates a map from archive file ID to archive file from the specified - * iterator. - * - * @param itor Iterator over archive files. - * @return Map from archive file ID to archive file. - */ - std::map<uint64_t, cta::common::dataStructures::ArchiveFile> archiveFileItorToMap( - cta::catalogue::Catalogue::ArchiveFileItor &itor); - - /** - * Creates a map from archive file ID to archive file from the specified - * list of archive files. - * - * @param listOfArchiveFiles The list of archive files from which the map - * shall be created. - * @return Map from archive file ID to archive file. - */ - std::map<uint64_t, cta::common::dataStructures::ArchiveFile> archiveFileListToMap( - const std::list<cta::common::dataStructures::ArchiveFile> &listOfArchiveFiles); - - /** - * Creates a map from admin username to admin user from the specified list of - * admin users. - * - * @param listOfAdminUsers The list of admin users. - * @return Map from username to admin user. - */ - std::map<std::string, cta::common::dataStructures::AdminUser> adminUserListToMap( - const std::list<cta::common::dataStructures::AdminUser> &listOfAdminUsers); - - /** - * Creates a map from tape meida type name to tape media type from the - * specified list of tape media types. - * - * @param listOfMediaTypes The list of tape media types. - * @return Map from tape media type name to tape media type. - */ - std::map<std::string, cta::catalogue::MediaTypeWithLogs> mediaTypeWithLogsListToMap( - const std::list<cta::catalogue::MediaTypeWithLogs> &listOfMediaTypes); - - /** - * Creates a map from tape pool name to tape pool from the specified list of - * tape pools. - * - * @param listOfTapePools The list of tape pools. - * @return Map from tape pool name to tape pool. - */ - std::map<std::string, cta::catalogue::TapePool> tapePoolListToMap( - const std::list<cta::catalogue::TapePool> &listOfTapePools); - -}; // cta_catalogue_CatalogueTest - -} // namespace unitTests diff --git a/catalogue/CatalogueUtils.cpp b/catalogue/CatalogueUtils.cpp new file mode 100644 index 0000000000..d9a6ee2358 --- /dev/null +++ b/catalogue/CatalogueUtils.cpp @@ -0,0 +1,43 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <optional> +#include <string> + +#include "catalogue/CatalogueExceptions.hpp" +#include "catalogue/CatalogueUtils.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { +namespace catalogue { + +void CatalogueUtils::checkCommentOrReasonMaxLength(const std::optional<std::string>& str, log::Logger &log) { + const size_t MAX_CHAR_COMMENT = 1000; + if (!str.has_value()) return; + if (str.value().length() > MAX_CHAR_COMMENT) { + log::LogContext lc(log); + log::ScopedParamContainer spc(lc); + spc.add("Large_Message: ", str.value()); + lc.log(log::ERR, "The reason or comment has more characters than the maximun allowed."); + throw exception::CommentOrReasonWithMoreSizeThanMaximunAllowed( + "The comment or reason string value has more than 1000 characters"); + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/Catalogue.cpp b/catalogue/CatalogueUtils.hpp similarity index 74% rename from catalogue/Catalogue.cpp rename to catalogue/CatalogueUtils.hpp index f660aa83de..665733cc72 100644 --- a/catalogue/Catalogue.cpp +++ b/catalogue/CatalogueUtils.hpp @@ -1,6 +1,6 @@ /* * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN + * @copyright Copyright © 2022 CERN * @license This program is free software, distributed under the terms of the GNU General Public * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your @@ -15,16 +15,24 @@ * submit itself to any jurisdiction. */ -#include "catalogue/Catalogue.hpp" +#pragma once + +#include <memory> +#include <optional> +#include <string> namespace cta { -namespace catalogue { -//------------------------------------------------------------------------------ -// destructor -//------------------------------------------------------------------------------ -Catalogue::~Catalogue() { +namespace log { +class Logger; } -} // namespace catalogue -} // namespace cta +namespace catalogue { + +class CatalogueUtils { +public: +static void checkCommentOrReasonMaxLength(const std::optional<std::string>& comment, log::Logger &log); +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/CreateAdminUserCmd.cpp b/catalogue/CreateAdminUserCmd.cpp index fa813c4f19..91da64ed2b 100644 --- a/catalogue/CreateAdminUserCmd.cpp +++ b/catalogue/CreateAdminUserCmd.cpp @@ -62,7 +62,7 @@ int CreateAdminUserCmd::exceptionThrowingMain(const int argc, char *const *const auto catalogue = catalogueFactory->create(); const common::dataStructures::SecurityIdentity adminRunningCommand(getUsername(), getHostname()); - catalogue->createAdminUser(adminRunningCommand, cmdLineArgs.adminUsername, cmdLineArgs.comment); + catalogue->AdminUser()->createAdminUser(adminRunningCommand, cmdLineArgs.adminUsername, cmdLineArgs.comment); return 0; } diff --git a/catalogue/DriveConfig.cpp b/catalogue/DriveConfig.cpp index 8ce0e03293..3437162fd6 100644 --- a/catalogue/DriveConfig.cpp +++ b/catalogue/DriveConfig.cpp @@ -62,20 +62,20 @@ void DriveConfig::setTapedConfiguration(const cta::tape::daemon::TapedConfigurat void DriveConfig::checkConfigInDB(catalogue::Catalogue* catalogue, const std::string& tapeDriveName, const std::string& key) { - auto namesAndKeys = catalogue->getTapeDriveConfigNamesAndKeys(); + auto namesAndKeys = catalogue->DriveConfig()->getTapeDriveConfigNamesAndKeys(); auto it = std::find_if(namesAndKeys.begin(), namesAndKeys.end(), [&tapeDriveName, &key](const std::pair<std::string, std::string>& element) { return element.first == tapeDriveName && element.second == key; }); if (it != namesAndKeys.end()) { - catalogue->deleteTapeDriveConfig(tapeDriveName, key); + catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, key); } } void DriveConfig::setConfigToDB(cta::SourcedParameter<std::string>* sourcedParameter, catalogue::Catalogue* catalogue, const std::string& tapeDriveName) { checkConfigInDB(catalogue, tapeDriveName, sourcedParameter->key()); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), sourcedParameter->value(), sourcedParameter->source()); } @@ -85,32 +85,32 @@ void DriveConfig::setConfigToDB(cta::SourcedParameter<cta::tape::daemon::FetchRe cta::utils::searchAndReplace(key, "Bytes", ""); cta::utils::searchAndReplace(key, "Files", ""); checkConfigInDB(catalogue, tapeDriveName, key.append("Files")); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), key, + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), key, std::to_string(sourcedParameter->value().maxFiles), sourcedParameter->source()); cta::utils::searchAndReplace(key, "Files", ""); checkConfigInDB(catalogue, tapeDriveName, key.append("Bytes")); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), key, + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), key, std::to_string(sourcedParameter->value().maxBytes), sourcedParameter->source()); } void DriveConfig::setConfigToDB(cta::SourcedParameter<uint32_t>* sourcedParameter, catalogue::Catalogue* catalogue, const std::string& tapeDriveName) { checkConfigInDB(catalogue, tapeDriveName, sourcedParameter->key()); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), std::to_string(sourcedParameter->value()), sourcedParameter->source()); } void DriveConfig::setConfigToDB(cta::SourcedParameter<uint64_t>* sourcedParameter, catalogue::Catalogue* catalogue, const std::string& tapeDriveName) { checkConfigInDB(catalogue, tapeDriveName, sourcedParameter->key()); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), std::to_string(sourcedParameter->value()), sourcedParameter->source()); } void DriveConfig::setConfigToDB(cta::SourcedParameter<time_t>* sourcedParameter, catalogue::Catalogue* catalogue, const std::string& tapeDriveName) { checkConfigInDB(catalogue, tapeDriveName, sourcedParameter->key()); - catalogue->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), + catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, sourcedParameter->category(), sourcedParameter->key(), std::to_string(sourcedParameter->value()), sourcedParameter->source()); } diff --git a/catalogue/DriveConfig.hpp b/catalogue/DriveConfig.hpp index e98c686e4e..d1966e98e0 100644 --- a/catalogue/DriveConfig.hpp +++ b/catalogue/DriveConfig.hpp @@ -17,6 +17,7 @@ #pragma once +#include <ctime> #include <memory> #include <string> diff --git a/catalogue/DummyCatalogue.cpp b/catalogue/DummyCatalogue.cpp deleted file mode 100644 index 1ff45728da..0000000000 --- a/catalogue/DummyCatalogue.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include <list> -#include <map> - -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/DummyCatalogue.hpp" -#include "catalogue/MediaType.hpp" -#include "catalogue/SchemaVersion.hpp" -#include "catalogue/TapePool.hpp" -#include "common/dataStructures/ArchiveFile.hpp" -#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" -#include "common/dataStructures/ArchiveFileSummary.hpp" -#include "common/dataStructures/DesiredDriveState.hpp" -#include "common/dataStructures/DiskInstance.hpp" -#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" -#include "common/dataStructures/StorageClass.hpp" -#include "common/dataStructures/TapeDrive.hpp" -#include "common/dataStructures/TapeDriveStatistics.hpp" -#include "common/threading/MutexLocker.hpp" - -namespace cta { -namespace catalogue { - -void DummyCatalogue::createAdminUser(const common::dataStructures::SecurityIdentity& admin, const std::string& username, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createArchiveRoute(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createLogicalLibrary(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool isDisabled, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createMountPolicy(const common::dataStructures::SecurityIdentity& admin, const CreateMountPolicyAttributes & mountPolicy) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstanceName, const std::string& requesterGroupName, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createRequesterMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstance, const std::string& requesterName, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createRequesterActivityMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstance, const std::string& requesterName, const std::string &activityRegex, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createStorageClass(const common::dataStructures::SecurityIdentity& admin, const common::dataStructures::StorageClass& storageClass) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes & tape) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteMediaType(const std::string &name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<MediaTypeWithLogs> DummyCatalogue::getMediaTypes() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -MediaType DummyCatalogue::getMediaTypeByVid(const std::string & vid) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &cartridge) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint32_t> &nbWraps) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &minLPos) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &maxLPos) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createTapePool(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string & vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::optional<std::string> &supply, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteAdminUser(const std::string& username) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string& instanceName, const uint64_t archiveFileId, log::LogContext &lc) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteArchiveRoute(const std::string& storageClassName, const uint32_t copyNb) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteLogicalLibrary(const std::string& name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteMountPolicy(const std::string& name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteRequesterGroupMountRule(const std::string& diskInstanceName, const std::string& requesterGroupName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteRequesterMountRule(const std::string& diskInstanceName, const std::string& requesterName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteRequesterActivityMountRule(const std::string& diskInstanceName, const std::string& requesterName, const std::string &activityRegex) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteStorageClass(const std::string& storageClassName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteTape(const std::string& vid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteTapePool(const std::string& name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer>& event) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteDiskSystem(const std::string &name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &fileRegexp) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t targetedFreeSpace) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t sleepTime) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceSpaceName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<common::dataStructures::DiskInstance> DummyCatalogue::getAllDiskInstances() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteDiskInstance(const std::string &name) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<common::dataStructures::DiskInstanceSpace> DummyCatalogue::getAllDiskInstanceSpaces() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<common::dataStructures::AdminUser> DummyCatalogue::getAdminUsers() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::ArchiveFile DummyCatalogue::getArchiveFileById(const uint64_t id) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -using ArchiveFileItor = CatalogueItor<common::dataStructures::ArchiveFile>; -ArchiveFileItor DummyCatalogue::getArchiveFilesItor(const TapeFileSearchCriteria& searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -using FileRecycleLogItor = CatalogueItor<common::dataStructures::FileRecycleLog>; -FileRecycleLogItor DummyCatalogue::getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, const std::string &newFid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteFilesFromRecycleLog(const std::string & vid, log::LogContext & lc) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteTapeDrive(const std::string &tapeDriveName) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, const std::string &keyName, const std::string &value, const std::string &source) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<cta::catalogue::Catalogue::DriveConfig> DummyCatalogue::getTapeDriveConfigs() const {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<std::pair<std::string, std::string>> DummyCatalogue::getTapeDriveConfigNamesAndKeys() const {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, const std::string &keyName, const std::string &value, const std::string &source) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::optional<std::tuple<std::string, std::string, std::string>> DummyCatalogue::getTapeDriveConfig( const std::string &tapeDriveName, const std::string &keyName) const {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<common::dataStructures::ArchiveFile> DummyCatalogue::getFilesForRepack(const std::string &vid, const uint64_t startFSeq, const uint64_t maxNbFiles) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -ArchiveFileItor DummyCatalogue::getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::ArchiveRoute> DummyCatalogue::getArchiveRoutes() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::ArchiveRoute> DummyCatalogue::getArchiveRoutes(const std::string &storageClassName, const std::string &tapePoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::LogicalLibrary> DummyCatalogue::getLogicalLibraries() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::RequesterGroupMountRule> DummyCatalogue::getRequesterGroupMountRules() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::RequesterMountRule> DummyCatalogue::getRequesterMountRules() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::RequesterActivityMountRule> DummyCatalogue::getRequesterActivityMountRules() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::StorageClass> DummyCatalogue::getStorageClasses() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::StorageClass DummyCatalogue::getStorageClass(const std::string &name) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::ArchiveFileSummary DummyCatalogue::getTapeFileSummary(const TapeFileSearchCriteria& searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::ArchiveFile DummyCatalogue::getArchiveFileForDeletion(const TapeFileSearchCriteria &searchCriteria) const {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -std::list<TapePool> DummyCatalogue::getTapePools(const TapePoolSearchCriteria &searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::optional<TapePool> DummyCatalogue::getTapePool(const std::string &tapePoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::optional<common::dataStructures::MountPolicy> DummyCatalogue::getMountPolicy(const std::string &mountPolicyName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::Tape> DummyCatalogue::getTapes(const TapeSearchCriteria& searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::map<std::string, std::string> DummyCatalogue::getVidToLogicalLibrary(const std::set<std::string> &vids) const { throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); } -common::dataStructures::Label::Format DummyCatalogue::getTapeLabelFormat(const std::string& vid) const { throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); } -std::list<TapeForWriting> DummyCatalogue::getTapesForWriting(const std::string& logicalLibraryName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -bool DummyCatalogue::isAdmin(const common::dataStructures::SecurityIdentity& admin) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyAdminUserComment(const common::dataStructures::SecurityIdentity& admin, const std::string& username, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::deleteVirtualOrganization(const std::string &voName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -std::list<common::dataStructures::VirtualOrganization> DummyCatalogue::getVirtualOrganizations() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::VirtualOrganization DummyCatalogue::getVirtualOrganizationOfTapepool(const std::string & tapepoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::VirtualOrganization DummyCatalogue::getCachedVirtualOrganizationOfTapepool(const std::string & tapepoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, const std::string &newVoName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& disabledReason) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t minArchiveRequestAge) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t archivePriority) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMountPolicyComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t minRetrieveRequestAge) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t retrievePriority) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string &activityRegex, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterGroupName, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterGroupName, const std::string& mountPolicy) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string& mountPolicy) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string &activityRegex, const std::string& mountPolicy) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyStorageClassComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyStorageClassName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbCopies) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::optional<std::string> &comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& encryptionKeyName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& verificationStatus) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeMediaType(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& mediaType) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeVendor(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& vendor) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& logicalLibraryName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapePoolComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbPartialTapes) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& supply) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& tapePoolName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::noSpaceLeftOnTape(const std::string& vid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::ping() { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::verifySchemaVersion() { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -SchemaVersion DummyCatalogue::getSchemaVersion() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -uint64_t DummyCatalogue::checkAndGetNextArchiveFileId(const std::string &diskInstanceName, const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::ArchiveFileQueueCriteria DummyCatalogue::getArchiveFileQueueCriteria(const std::string &diskInstanceName, - const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -common::dataStructures::RetrieveFileQueueCriteria DummyCatalogue::prepareToRetrieveFile(const std::string& diskInstanceName, const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity& user, const std::optional<std::string>& activity, log::LogContext& lc, const std::optional<std::string> &mountPolicyName) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, cta::log::LogContext & lc) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::checkTapeForLabel(const std::string& vid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -uint64_t DummyCatalogue::getNbFilesOnTape(const std::string& vid) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string & reason) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string & reason) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool fullValue) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeDirty(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool dirtyValue) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeDirty(const std::string & vid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapeIsFromCastorInUnitTests(const std::string &vid) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::setTapePoolEncryption(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool encryptionValue) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -bool DummyCatalogue::diskSystemExists(const std::string& name) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::tapeLabelled(const std::string& vid, const std::string& drive) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::tapeMountedForArchive(const std::string& vid, const std::string& drive) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::tapeMountedForRetrieve(const std::string& vid, const std::string& drive) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -bool DummyCatalogue::tapePoolExists(const std::string& tapePoolName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, const std::string &diskFileId) { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, - log::LogContext & lc) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");} -void DummyCatalogue::modifyArchiveFileStorageClassId(const uint64_t archiveFileId, const std::string &newStorageClassName) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } -void DummyCatalogue::modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, const std::string &diskInstance) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); } - - -// Special functions for unit tests. -void DummyCatalogue::addEnabledTape(const std::string & vid) { - threading::MutexLocker lm(m_tapeEnablingMutex); - m_tapeEnabling[vid]=common::dataStructures::Tape::ACTIVE; -} -void DummyCatalogue::addDisabledTape(const std::string & vid) { - threading::MutexLocker lm(m_tapeEnablingMutex); - m_tapeEnabling[vid]=common::dataStructures::Tape::DISABLED; -} -void DummyCatalogue::addRepackingTape(const std::string & vid) { - threading::MutexLocker lm(m_tapeEnablingMutex); - m_tapeEnabling[vid]=common::dataStructures::Tape::REPACKING; -} -void DummyCatalogue::modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, const common::dataStructures::Tape::State & state, const std::optional<common::dataStructures::Tape::State> & prev_state, const std::optional<std::string> & stateReason) { - threading::MutexLocker lm(m_tapeEnablingMutex); - if (prev_state.has_value() && prev_state.value() != m_tapeEnabling[vid]) { - throw exception::Exception("Previous state mismatch"); - } - m_tapeEnabling[vid]=state; -} -bool DummyCatalogue::tapeExists(const std::string& vid) const { - return m_tapeEnabling.find(vid) != m_tapeEnabling.end(); -} -common::dataStructures::Tape::State DummyCatalogue::getTapeState(const std::string & vid) const { - return m_tapeEnabling.at(vid); -} -common::dataStructures::VidToTapeMap DummyCatalogue::getTapesByVid(const std::string& vid) const { - std::set<std::string> vids = {vid}; - return getTapesByVid(vids); -} -common::dataStructures::VidToTapeMap DummyCatalogue::getTapesByVid(const std::set<std::string>& vids) const { - // Minimal implementation of VidToMap for retrieve request unit tests. We just support - // disabled status for the tapes. - // If the tape is not listed, it is listed as enabled in the return value. - threading::MutexLocker lm(m_tapeEnablingMutex); - common::dataStructures::VidToTapeMap ret; - for (const auto & v: vids) { - try { - ret[v].state = m_tapeEnabling.at(v); - } catch (std::out_of_range &) { - ret[v].state = common::dataStructures::Tape::ACTIVE; - } - } - return ret; -} -std::list<common::dataStructures::MountPolicy> DummyCatalogue::getMountPolicies() const { - std::list<common::dataStructures::MountPolicy> mountPolicies; - common::dataStructures::MountPolicy mp1; - mp1.name = "mountPolicy"; - mp1.archivePriority = 1; - mp1.archiveMinRequestAge = 0; - mp1.retrievePriority = 1; - mp1.retrieveMinRequestAge = 0; - mountPolicies.push_back(mp1); - - common::dataStructures::MountPolicy mp2; - mp2.name = "moreAdvantageous"; - mp2.archivePriority = 2; - mp2.archiveMinRequestAge = 0; - mp2.retrievePriority = 2; - mp2.retrieveMinRequestAge = 0; - mountPolicies.push_back(mp1); - return mountPolicies; -} - -std::list<common::dataStructures::MountPolicy> DummyCatalogue::getCachedMountPolicies() const { - std::list<common::dataStructures::MountPolicy> mountPolicies; - common::dataStructures::MountPolicy mp1; - mp1.name = "mountPolicy"; - mp1.archivePriority = 1; - mp1.archiveMinRequestAge = 0; - mp1.retrievePriority = 1; - mp1.retrieveMinRequestAge = 0; - mountPolicies.push_back(mp1); - - common::dataStructures::MountPolicy mp2; - mp2.name = "moreAdvantageous"; - mp2.archivePriority = 2; - mp2.archiveMinRequestAge = 0; - mp2.retrievePriority = 2; - mp2.retrieveMinRequestAge = 0; - mountPolicies.push_back(mp1); - return mountPolicies; -} - -std::list<std::string> DummyCatalogue::getTapeDriveNames() const { - return {m_tapeDriveStatus.driveName}; -} - -std::optional<common::dataStructures::TapeDrive> DummyCatalogue::getTapeDrive(const std::string &tapeDriveName) const { - if (m_tapeDriveStatus.driveName != "") return m_tapeDriveStatus; - common::dataStructures::TapeDrive tapeDriveStatus; - const time_t reportTime = time(nullptr); - - tapeDriveStatus.driveName = tapeDriveName; - tapeDriveStatus.host = "Dummy_Host"; - tapeDriveStatus.logicalLibrary = "Dummy_Library"; - - tapeDriveStatus.downOrUpStartTime = reportTime; - - tapeDriveStatus.mountType = common::dataStructures::MountType::NoMount; - tapeDriveStatus.driveStatus = common::dataStructures::DriveStatus::Down; - tapeDriveStatus.desiredUp = false; - tapeDriveStatus.desiredForceDown = false; - - tapeDriveStatus.diskSystemName = "Dummy_System"; - tapeDriveStatus.reservedBytes = 0; - tapeDriveStatus.reservationSessionId = 0; - - - return tapeDriveStatus; -} - -std::list<common::dataStructures::TapeDrive> DummyCatalogue::getTapeDrives() const { - std::list<common::dataStructures::TapeDrive> tapeDrives; - const auto tapeDrive = getTapeDrive(m_tapeDriveStatus.driveName); - if (tapeDrive.has_value()) tapeDrives.push_back(tapeDrive.value()); - return tapeDrives; -} - -void DummyCatalogue::setDesiredTapeDriveState(const std::string&, - const common::dataStructures::DesiredDriveState &desiredState) { - m_tapeDriveStatus.desiredUp = desiredState.up; - m_tapeDriveStatus.desiredForceDown = desiredState.forceDown; - m_tapeDriveStatus.reasonUpDown = desiredState.reason; -} - -void DummyCatalogue::setDesiredTapeDriveStateComment(const std::string& tapeDriveName, - const std::string &comment) { - m_tapeDriveStatus.userComment = comment; -} - -void DummyCatalogue::updateTapeDriveStatistics(const std::string& tapeDriveName, - const std::string& host, const std::string& logicalLibrary, - const common::dataStructures::TapeDriveStatistics& statistics) { - m_tapeDriveStatus.driveName = tapeDriveName; - m_tapeDriveStatus.host = host; - m_tapeDriveStatus.logicalLibrary = logicalLibrary; - m_tapeDriveStatus.bytesTransferedInSession = statistics.bytesTransferedInSession; - m_tapeDriveStatus.filesTransferedInSession = statistics.filesTransferedInSession; - m_tapeDriveStatus.lastModificationLog = statistics.lastModificationLog; -} - -void DummyCatalogue::updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) { - m_tapeDriveStatus = tapeDrive; -} - -std::map<std::string, uint64_t> DummyCatalogue::getDiskSpaceReservations() const { - std::map<std::string, uint64_t> ret; - const auto tdNames = getTapeDriveNames(); - for (const auto& driveName : tdNames) { - const auto tdStatus = getTapeDrive(driveName); - if (tdStatus.value().diskSystemName) { - // no need to check key, operator[] initializes missing values at zero for scalar types - ret[tdStatus.value().diskSystemName.value()] += tdStatus.value().reservedBytes.value(); - } - } - return ret; -} - -void DummyCatalogue::reserveDiskSpace(const std::string& driveName, const uint64_t mountId, - const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { - if (diskSpaceReservation.empty()) return; - - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::DEBUG, "In RetrieveMount::reserveDiskSpace(): reservation request."); - - auto tdStatus = getTapeDrive(driveName); - if (!tdStatus) return; - - if (!tdStatus.value().reservationSessionId) { - tdStatus.value().reservationSessionId = mountId; - tdStatus.value().reservedBytes = 0; - } - - if (tdStatus.value().reservationSessionId != mountId) { - tdStatus.value().reservationSessionId = mountId; - tdStatus.value().reservedBytes = 0; - } - - tdStatus.value().diskSystemName = diskSpaceReservation.begin()->first; - tdStatus.value().reservedBytes.value() += diskSpaceReservation.begin()->second; - updateTapeDriveStatus(tdStatus.value()); -} - -void DummyCatalogue::releaseDiskSpace(const std::string& driveName, const uint64_t mountId, - const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { - if (diskSpaceReservation.empty()) return; - - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::DEBUG, "In RetrieveMount::releaseDiskSpace(): reservation release request."); - - auto tdStatus = getTapeDrive(driveName); - - if (!tdStatus) return; - if (!tdStatus.value().reservationSessionId) { - return; - } - if (tdStatus.value().reservationSessionId != mountId) { - return; - } - auto& bytes = diskSpaceReservation.begin()->second; - if (bytes > tdStatus.value().reservedBytes) throw NegativeDiskSpaceReservationReached( - "In DriveState::subtractDiskSpaceReservation(): we would reach a negative reservation size."); - tdStatus.value().diskSystemName = diskSpaceReservation.begin()->first; - tdStatus.value().reservedBytes.value() -= bytes; - updateTapeDriveStatus(tdStatus.value()); -} - - -/* - * Implemented for testing disk space reservation logic - */ -disk::DiskSystemList DummyCatalogue::getAllDiskSystems() const { - return m_diskSystemList; -} - -void DummyCatalogue::createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { - m_diskInstances[name] = {name, comment, common::dataStructures::EntryLog(), common::dataStructures::EntryLog()}; -} - -void DummyCatalogue::createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL, const uint64_t refreshInterval, const std::string &comment) { - m_diskInstanceSpaces[name] = {name, diskInstance, freeSpaceQueryURL, refreshInterval, 0, 0, comment, common::dataStructures::EntryLog(), common::dataStructures::EntryLog()}; -} - -void DummyCatalogue::createDiskSystem(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, const std::string &fileRegexp, const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) { - m_diskSystemList.push_back({name, m_diskInstanceSpaces.at(diskInstanceSpaceName), fileRegexp, targetedFreeSpace, sleepTime, common::dataStructures::EntryLog(), common::dataStructures::EntryLog{}, comment}); -} - -void DummyCatalogue::modifyDiskInstanceSpaceFreeSpace(const std::string &name, const std::string &diskInstance, const uint64_t freeSpace) { - m_diskInstanceSpaces[name].freeSpace = freeSpace; - m_diskInstanceSpaces[name].lastRefreshTime = time(nullptr); -} - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/DummyCatalogue.hpp b/catalogue/DummyCatalogue.hpp deleted file mode 100644 index 6e98eeb6ad..0000000000 --- a/catalogue/DummyCatalogue.hpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include <list> -#include <map> -#include <string> - -#include "catalogue/Catalogue.hpp" -#include "common/dataStructures/ArchiveFileSummary.hpp" -#include "common/dataStructures/DiskInstance.hpp" -#include "common/dataStructures/TapeDrive.hpp" -#include "common/threading/MutexLocker.hpp" -#include "disk/DiskSystem.hpp" - -namespace cta { -namespace catalogue { - -/** - * An empty implementation of the Catalogue used to populate unit tests of the scheduler database - * as they need a reference to a Catalogue, used in very few situations (requeueing of retrieve - * requests). - */ -class DummyCatalogue: public Catalogue { -public: - DummyCatalogue() = default; - ~DummyCatalogue() override = default; - - void createAdminUser(const common::dataStructures::SecurityIdentity& admin, const std::string& username, const std::string& comment) override; - void createArchiveRoute(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName, const std::string& comment) override; - void createLogicalLibrary(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool isDisabled, const std::string& comment) override; - void createMountPolicy(const common::dataStructures::SecurityIdentity& admin, const CreateMountPolicyAttributes & mountPolicy) override; - void createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstanceName, const std::string& requesterGroupName, const std::string& comment) override; - void createRequesterMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstance, const std::string& requesterName, const std::string& comment) override; - void createRequesterActivityMountRule(const common::dataStructures::SecurityIdentity& admin, const std::string& mountPolicyName, const std::string& diskInstance, const std::string& requesterName, const std::string &activityRegex, const std::string& comment) override; - void createStorageClass(const common::dataStructures::SecurityIdentity& admin, const common::dataStructures::StorageClass& storageClass) override; - void createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes & tape) override; - void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) override; - void deleteMediaType(const std::string &name) override; - std::list<MediaTypeWithLogs> getMediaTypes() const override; - MediaType getMediaTypeByVid(const std::string & vid) const override; - void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; - void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &cartridge) override; - void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) override; - void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) override; - void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) override; - void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint32_t> &nbWraps) override; - void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &minLPos) override; - void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &maxLPos) override; - void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - void createTapePool(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string & vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::optional<std::string> &supply, const std::string& comment) override; - void deleteAdminUser(const std::string& username) override; - void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string& instanceName, const uint64_t archiveFileId, log::LogContext &lc) override; - void deleteArchiveRoute(const std::string& storageClassName, const uint32_t copyNb) override; - void deleteLogicalLibrary(const std::string& name) override; - void deleteMountPolicy(const std::string& name) override; - void deleteRequesterGroupMountRule(const std::string& diskInstanceName, const std::string& requesterGroupName) override; - void deleteRequesterMountRule(const std::string& diskInstanceName, const std::string& requesterName) override; - void deleteRequesterActivityMountRule(const std::string& diskInstanceName, const std::string& requesterName, const std::string &activityRegex) override; - void deleteStorageClass(const std::string& storageClassName) override; - void deleteTape(const std::string& vid) override; - void deleteTapePool(const std::string& name) override; - void filesWrittenToTape(const std::set<TapeItemWrittenPointer>& event) override; - void deleteDiskSystem(const std::string &name) override; - void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &fileRegexp) override; - void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t targetedFreeSpace) override; - void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t sleepTime) override; - void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName) override; - void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceSpaceName) override; - std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const override; - void deleteDiskInstance(const std::string &name) override; - void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const override; - void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) override; - void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &comment) override; - void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) override; - void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) override; - std::list<common::dataStructures::AdminUser> getAdminUsers() const override; - common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override; - ArchiveFileItor getArchiveFilesItor(const TapeFileSearchCriteria& searchCriteria) const; - FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const; - void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, const std::string &newFid); - void deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc); - void deleteFilesFromRecycleLog(const std::string & vid, log::LogContext & lc); - void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive); - void deleteTapeDrive(const std::string &tapeDriveName); - void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, const std::string &keyName, const std::string &value, const std::string &source); - std::list<cta::catalogue::Catalogue::DriveConfig> getTapeDriveConfigs() const; - std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const; - void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, const std::string &keyName, const std::string &value, const std::string &source); - std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig( const std::string &tapeDriveName, const std::string &keyName) const; - void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName); - std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, const uint64_t maxNbFiles) const override; - ArchiveFileItor getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const override; - std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const; - std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &storageClassName, const std::string &tapePoolName) const override; - std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const; - std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const; - std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const; - std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const; - std::list<common::dataStructures::StorageClass> getStorageClasses() const; - common::dataStructures::StorageClass getStorageClass(const std::string &name) const; - common::dataStructures::ArchiveFileSummary getTapeFileSummary(const TapeFileSearchCriteria& searchCriteria) const; - common::dataStructures::ArchiveFile getArchiveFileForDeletion(const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; - void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) override; - std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria) const; - std::optional<TapePool> getTapePool(const std::string &tapePoolName) const override; - std::optional<common::dataStructures::MountPolicy> getMountPolicy(const std::string &mountPolicyName) const override; - std::list<common::dataStructures::Tape> getTapes(const TapeSearchCriteria& searchCriteria) const; - // getTapesByVid is implemented below (and works). - std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const override; - common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const override; - std::list<TapeForWriting> getTapesForWriting(const std::string& logicalLibraryName) const; - bool isAdmin(const common::dataStructures::SecurityIdentity& admin) const; - void modifyAdminUserComment(const common::dataStructures::SecurityIdentity& admin, const std::string& username, const std::string& comment) override; - void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo) override; - void deleteVirtualOrganization(const std::string &voName) override; - std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const override; - common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool(const std::string & tapepoolName) const override; - common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool(const std::string & tapepoolName) const override; - void modifyVirtualOrganizationName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, const std::string &newVoName) override; - void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) override; - void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) override; - void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) override; - void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) override; - void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) override; - void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& comment) override; - void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& storageClassName, const uint32_t copyNb, const std::string& tapePoolName) override; - void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; - void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override; - void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& disabledReason) override; - void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) override; - void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t minArchiveRequestAge) override; - void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t archivePriority) override; - void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override; - void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t minRetrieveRequestAge) override; - void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t retrievePriority) override; - void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string &activityRegex, const std::string& comment) override; - void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string& comment) override; - void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterGroupName, const std::string& comment) override; - void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterGroupName, const std::string& mountPolicy) override; - void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string& mountPolicy) override; - void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity& admin, const std::string& instanceName, const std::string& requesterName, const std::string &activityRegex, const std::string& mountPolicy) override; - void modifyStorageClassComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override; - void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override; - void modifyStorageClassName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) override; - void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbCopies) override; - void modifyTapeComment(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::optional<std::string> &comment) override; - void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& encryptionKeyName) override; - void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& verificationStatus) override; - void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, const common::dataStructures::Tape::State & state, const std::optional<common::dataStructures::Tape::State> & prev_state, const std::optional<std::string> & stateReason) override; - void modifyTapeMediaType(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& mediaType) override; - void modifyTapeVendor(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& vendor) override; - void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& logicalLibraryName) override; - void modifyTapePoolComment(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& comment) override; - void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override; - void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const uint64_t nbPartialTapes) override; - void modifyTapePoolSupply(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const std::string& supply) override; - void modifyTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentName, const std::string& newName) override; - void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string& tapePoolName) override; - void noSpaceLeftOnTape(const std::string& vid) override; - void ping() override; - void verifySchemaVersion() override; - SchemaVersion getSchemaVersion() const override; - uint64_t checkAndGetNextArchiveFileId(const std::string &diskInstanceName, const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override; - common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName, - const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override; - common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string& diskInstanceName, const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity& user, const std::optional<std::string>& activity, log::LogContext& lc, const std::optional<std::string> &mountPolicyName) override; - void reclaimTape(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, cta::log::LogContext & lc) override; - void checkTapeForLabel(const std::string& vid) override; - uint64_t getNbFilesOnTape(const std::string& vid) const override; - void setTapeDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string & reason) override; - void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const std::string & reason) override; - void setTapeFull(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool fullValue) override; - void setTapeDirty(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, const bool dirtyValue) override; - void setTapeDirty(const std::string & vid) override; - void setTapeIsFromCastorInUnitTests(const std::string &vid) override; - void setTapePoolEncryption(const common::dataStructures::SecurityIdentity& admin, const std::string& name, const bool encryptionValue) override; - bool tapeExists(const std::string& vid) const; - bool diskSystemExists(const std::string& name) const; - void tapeLabelled(const std::string& vid, const std::string& drive) override; - void tapeMountedForArchive(const std::string& vid, const std::string& drive) override; - void tapeMountedForRetrieve(const std::string& vid, const std::string& drive) override; - bool tapePoolExists(const std::string& tapePoolName) const; - void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, const std::string &diskFileId) override; - void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; - void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, const std::string &newStorageClassName) const override; - void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, const std::string &diskInstance) const; - - common::dataStructures::Tape::State getTapeState(const std::string & vid) const; - - common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const override; - - common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string>& vids) const override; - - std::list<common::dataStructures::MountPolicy> getMountPolicies() const override; - - std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const override; - - std::list<std::string> getTapeDriveNames() const override; - - std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const override; - - std::list<common::dataStructures::TapeDrive> getTapeDrives() const override; - - void setDesiredTapeDriveState(const std::string&, const common::dataStructures::DesiredDriveState &desiredState) override; - - void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, const std::string &comment) override; - - void updateTapeDriveStatistics(const std::string& tapeDriveName, - const std::string& host, const std::string& logicalLibrary, - const common::dataStructures::TapeDriveStatistics& statistics) override; - - void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) override; - - std::map<std::string, uint64_t> getDiskSpaceReservations() const override; - - void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; - - void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; - - /* - * Implemented for testing disk space reservation logic - */ - disk::DiskSystemList getAllDiskSystems() const override; - - void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - - void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL, const uint64_t refreshInterval, const std::string &comment) override; - - void createDiskSystem(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, const std::string &fileRegexp, const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) override; - - void modifyDiskInstanceSpaceFreeSpace(const std::string &name, const std::string &diskInstance, const uint64_t freeSpace) override; - - // This special funcitons for unit tests should be put in private - void addEnabledTape(const std::string & vid); - void addDisabledTape(const std::string & vid); - void addRepackingTape(const std::string & vid); - -private: - mutable threading::Mutex m_tapeEnablingMutex; - std::map<std::string, common::dataStructures::Tape::State> m_tapeEnabling; - - common::dataStructures::TapeDrive m_tapeDriveStatus; - - disk::DiskSystemList m_diskSystemList; - std::map<std::string, common::dataStructures::DiskInstance> m_diskInstances; - std::map<std::string, common::dataStructures::DiskInstanceSpace> m_diskInstanceSpaces; -}; - -} // namespace catalogue -} // namespace cta. - diff --git a/catalogue/Group.hpp b/catalogue/Group.hpp new file mode 100644 index 0000000000..0ad7ce1c48 --- /dev/null +++ b/catalogue/Group.hpp @@ -0,0 +1,64 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +namespace cta { +namespace catalogue { + +/** + * A fully qualified user group, in other words the name of the disk instance + * and the name of the group. + */ +struct Group { + /** + * The name of the disk instance to which the group name belongs. + */ + std::string diskInstanceName; + + /** + * The name of the group which is only guaranteed to be unique within its + * disk instance. + */ + std::string groupName; + + /** + * Constructor. + * + * @param d The name of the disk instance to which the group name belongs. + * @param g The name of the group which is only guaranteed to be unique + * within its disk instance. + */ + Group(const std::string &d, const std::string &g): diskInstanceName(d), groupName(g) { + } + + /** + * Less than operator. + * + * @param rhs The argument on the right hand side of the operator. + * @return True if this object is less than the argument on the right hand + * side of the operator. + */ + bool operator<(const Group &rhs) const { + return diskInstanceName < rhs.diskInstanceName || groupName < rhs.groupName; + } +}; // struct Group + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/InMemoryCatalogueFactory.cpp b/catalogue/InMemoryCatalogueFactory.cpp index a3b4003c94..fd54791fcb 100644 --- a/catalogue/InMemoryCatalogueFactory.cpp +++ b/catalogue/InMemoryCatalogueFactory.cpp @@ -15,9 +15,13 @@ * submit itself to any jurisdiction. */ -#include "catalogue/CatalogueRetryWrapper.hpp" -#include "catalogue/InMemoryCatalogueFactory.hpp" +#include <memory> +#include <string> +#include <utility> + #include "catalogue/InMemoryCatalogue.hpp" +#include "catalogue/InMemoryCatalogueFactory.hpp" +#include "catalogue/retrywrappers/CatalogueRetryWrapper.hpp" #include "common/exception/Exception.hpp" namespace cta { diff --git a/catalogue/InMemoryVersionOfCatalogueTest.cpp b/catalogue/InMemoryVersionOfCatalogueTest.cpp deleted file mode 100644 index 7386e156d0..0000000000 --- a/catalogue/InMemoryVersionOfCatalogueTest.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include "catalogue/CatalogueTest.hpp" -#include "catalogue/InMemoryCatalogueFactory.hpp" -#ifdef STDOUT_LOGGING -#include "common/log/StdoutLogger.hpp" -#else -#include "common/log/DummyLogger.hpp" -#endif - -namespace unitTests { - -namespace { - -const uint64_t g_in_memory_CatalogueTest_nbConn = 1; -const uint64_t g_in_memory_nbArchiveFileListingConns = 1; -const uint64_t g_in_memory_maxTriesToConnect = 1; -#ifdef STDOUT_LOGGING -cta::log::StdoutLogger g_in_memory_CatalogueTest_dummyLogger("stdout", "stdout"); -#else -cta::log::DummyLogger g_in_memory_CatalogueTest_dummyLogger("dummy", "dummy"); -#endif - -cta::catalogue::InMemoryCatalogueFactory g_inMemoryCatalogueFactory(g_in_memory_CatalogueTest_dummyLogger, - g_in_memory_CatalogueTest_nbConn, g_in_memory_nbArchiveFileListingConns, g_in_memory_maxTriesToConnect); - -cta::catalogue::CatalogueFactory *g_inMemoryCatalogueFactoryPtr = &g_inMemoryCatalogueFactory; - -} // anonymous namespace - -INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_CatalogueTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); - -} // namespace unitTests diff --git a/catalogue/OracleCatalogue.cpp b/catalogue/OracleCatalogue.cpp deleted file mode 100644 index 8eedc3a3ce..0000000000 --- a/catalogue/OracleCatalogue.cpp +++ /dev/null @@ -1,1247 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include <algorithm> - -#include "catalogue/ArchiveFileRow.hpp" -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/InsertFileRecycleLog.hpp" -#include "catalogue/OracleCatalogue.hpp" -#include "catalogue/retryOnLostConnection.hpp" -#include "catalogue/TapeItemWrittenPointer.hpp" -#include "common/dataStructures/DeleteArchiveRequest.hpp" -#include "common/dataStructures/FileRecycleLog.hpp" -#include "common/exception/Exception.hpp" -#include "common/exception/FileSizeMismatch.hpp" -#include "common/exception/LostDatabaseConnection.hpp" -#include "common/exception/TapeFseqMismatch.hpp" -#include "common/exception/UserError.hpp" -#include "common/log/TimingList.hpp" -#include "common/threading/MutexLocker.hpp" -#include "common/Timer.hpp" -#include "common/utils/utils.hpp" -#include "rdbms/AutoRollback.hpp" -#include "rdbms/rdbms.hpp" -#include "rdbms/wrapper/OcciColumn.hpp" -#include "rdbms/wrapper/OcciStmt.hpp" - -namespace cta { -namespace catalogue { - -namespace { - /** - * Structure used to assemble a batch of rows to insert into the TAPE_FILE - * table. - */ - struct TapeFileBatch { - size_t nbRows; - rdbms::wrapper::OcciColumn vid; - rdbms::wrapper::OcciColumn fSeq; - rdbms::wrapper::OcciColumn blockId; - rdbms::wrapper::OcciColumn fileSize; - rdbms::wrapper::OcciColumn copyNb; - rdbms::wrapper::OcciColumn creationTime; - rdbms::wrapper::OcciColumn archiveFileId; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - TapeFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - vid("VID", nbRows), - fSeq("FSEQ", nbRows), - blockId("BLOCK_ID", nbRows), - fileSize("LOGICAL_SIZE_IN_BYTES", nbRows), - copyNb("COPY_NB", nbRows), - creationTime("CREATION_TIME", nbRows), - archiveFileId("ARCHIVE_FILE_ID", nbRows) { - } - }; // struct TapeFileBatch - - /** - * Structure used to assemble a batch of rows to insert into the ARCHIVE_FILE - * table. - */ - struct ArchiveFileBatch { - size_t nbRows; - rdbms::wrapper::OcciColumn archiveFileId; - rdbms::wrapper::OcciColumn diskInstance; - rdbms::wrapper::OcciColumn diskFileId; - rdbms::wrapper::OcciColumn diskFileUser; - rdbms::wrapper::OcciColumn diskFileGroup; - rdbms::wrapper::OcciColumn size; - rdbms::wrapper::OcciColumn checksumBlob; - rdbms::wrapper::OcciColumn checksumAdler32; - rdbms::wrapper::OcciColumn storageClassName; - rdbms::wrapper::OcciColumn creationTime; - rdbms::wrapper::OcciColumn reconciliationTime; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - ArchiveFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - archiveFileId("ARCHIVE_FILE_ID", nbRows), - diskInstance("DISK_INSTANCE_NAME", nbRows), - diskFileId("DISK_FILE_ID", nbRows), - diskFileUser("DISK_FILE_UID", nbRows), - diskFileGroup("DISK_FILE_GID", nbRows), - size("SIZE_IN_BYTES", nbRows), - checksumBlob("CHECKSUM_BLOB", nbRows), - checksumAdler32("CHECKSUM_ADLER32", nbRows), - storageClassName("STORAGE_CLASS_NAME", nbRows), - creationTime("CREATION_TIME", nbRows), - reconciliationTime("RECONCILIATION_TIME", nbRows) { - } - }; // struct ArchiveFileBatch - - /** - * Structure used to assemble a batch of rows to insert into the - * TAPE_FILE_BATCH temporary table. - */ - struct TempTapeFileBatch { - size_t nbRows; - rdbms::wrapper::OcciColumn archiveFileId; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - TempTapeFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - archiveFileId("ARCHIVE_FILE_ID", nbRows) { - } - }; // struct TempTapeFileBatch -} // anonymous namespace - -//------------------------------------------------------------------------------ -// constructor -//------------------------------------------------------------------------------ -OracleCatalogue::OracleCatalogue( - log::Logger &log, - const std::string &username, - const std::string &password, - const std::string &database, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns): - RdbmsCatalogue( - log, - rdbms::Login(rdbms::Login::DBTYPE_ORACLE, username, password, database, "", 0), - nbConns, - nbArchiveFileListingConns) { -} - -//------------------------------------------------------------------------------ -// destructor -//------------------------------------------------------------------------------ -OracleCatalogue::~OracleCatalogue() { -} - -//------------------------------------------------------------------------------ -// createAndPopulateTempTableFxid -//------------------------------------------------------------------------------ -std::string OracleCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const { - const std::string tempTableName = "ORA$PTT_DISK_FXIDS"; - - try { - if(diskFileIds) { - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - std::string sql = "CREATE PRIVATE TEMPORARY TABLE " + tempTableName + - "(DISK_FILE_ID VARCHAR2(100))"; - conn.executeNonQuery(sql); - - sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; - auto stmt = conn.createStmt(sql); - for(auto &diskFileId : diskFileIds.value()) { - stmt.bindString(":DISK_FILE_ID", diskFileId); - stmt.executeNonQuery(); - } - } - - return tempTableName; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextArchiveFileId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE_ID_SEQ.NEXTVAL AS ARCHIVE_FILE_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("ARCHIVE_FILE_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextLogicalLibraryId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "LOGICAL_LIBRARY_ID_SEQ.NEXTVAL AS LOGICAL_LIBRARY_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("LOGICAL_LIBRARY_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextVirtualOrganizationId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION_ID_SEQ.NEXTVAL AS VIRTUAL_ORGANIZATION_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("VIRTUAL_ORGANIZATION_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMediaTypeId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextMediaTypeId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "MEDIA_TYPE_ID_SEQ.NEXTVAL AS MEDIA_TYPE_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("MEDIA_TYPE_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextStorageClassId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextStorageClassId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS_ID_SEQ.NEXTVAL AS STORAGE_CLASS_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("STORAGE_CLASS_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextTapePoolId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextTapePoolId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "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; - } -} - -//------------------------------------------------------------------------------ -// getNextFileRecyleLogId -//------------------------------------------------------------------------------ -uint64_t OracleCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) { - try { - const char *const sql = - "SELECT " - "FILE_RECYCLE_LOG_ID_SEQ.NEXTVAL AS FILE_RECYCLE_LOG_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("FILE_RECYCLE_LOG_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 " - "VID = :VID " - "FOR UPDATE"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - if (!rset.next()) { - throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); - } - - return rset.columnUint64("LAST_FSEQ"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// filesWrittenToTape -//------------------------------------------------------------------------------ -void OracleCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { - try { - if (events.empty()) { - return; - } - - auto firstEventItor = events.begin(); - const auto &firstEvent = **firstEventItor; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); - const time_t now = time(nullptr); - threading::MutexLocker locker(m_mutex); - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - - const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid); - uint64_t expectedFSeq = lastFSeq + 1; - uint64_t totalLogicalBytesWritten = 0; - - uint32_t i = 0; - // We have a mix of files and items. Only files will be recorded, but items - // allow checking fSeq coherency. - // determine the number of files - size_t filesCount=std::count_if(events.cbegin(), events.cend(), - [](const TapeItemWrittenPointer &e) -> bool {return typeid(*e)==typeid(TapeFileWritten);}); - TapeFileBatch tapeFileBatch(filesCount); - - std::set<TapeFileWritten> fileEvents; - - for (const auto &eventP: events) { - // Check for all item types. - const auto &event = *eventP; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); - - if (event.vid != firstEvent.vid) { - throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); - } - - if (expectedFSeq != event.fSeq) { - exception::TapeFseqMismatch ex; - ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << - event.fSeq; - throw ex; - } - expectedFSeq++; - - try { - // If this is a file (as opposed to a placeholder), do the full processing. - const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); - - checkTapeFileWrittenFieldsAreSet(__FUNCTION__, fileEvent); - - totalLogicalBytesWritten += fileEvent.size; - - // Store the length of each field and implicitly calculate the maximum field - // length of each column - tapeFileBatch.vid.setFieldLenToValueLen(i, fileEvent.vid); - tapeFileBatch.fSeq.setFieldLenToValueLen(i, fileEvent.fSeq); - tapeFileBatch.blockId.setFieldLenToValueLen(i, fileEvent.blockId); - tapeFileBatch.fileSize.setFieldLenToValueLen(i, fileEvent.size); - tapeFileBatch.copyNb.setFieldLenToValueLen(i, fileEvent.copyNb); - tapeFileBatch.creationTime.setFieldLenToValueLen(i, now); - tapeFileBatch.archiveFileId.setFieldLenToValueLen(i, fileEvent.archiveFileId); - - fileEvents.insert(fileEvent); - i++; - } catch (std::bad_cast&) {} - } - - // Store the value of each field - i = 0; - for (const auto &event: fileEvents) { - tapeFileBatch.vid.setFieldValue(i, event.vid); - tapeFileBatch.fSeq.setFieldValue(i, event.fSeq); - tapeFileBatch.blockId.setFieldValue(i, event.blockId); - tapeFileBatch.fileSize.setFieldValue(i, event.size); - tapeFileBatch.copyNb.setFieldValue(i, event.copyNb); - tapeFileBatch.creationTime.setFieldValue(i, now); - tapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); - i++; - } - - // Update the tape because all the necessary information is now available - auto lastEventItor = events.cend(); - lastEventItor--; - const TapeItemWritten &lastEvent = **lastEventItor; - updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, lastEvent.tapeDrive); - - // If we had only placeholders and no file recorded, we are done (but we still commit the update of the tape's fSeq). - if (fileEvents.empty()) { - conn.commit(); - return; - } - - // Create the archive file entries, skipping those that already exist - idempotentBatchInsertArchiveFiles(conn, fileEvents); - - { - const char *const sql = - "INSERT INTO TEMP_TAPE_FILE_INSERTION_BATCH(" "\n" - "VID," "\n" - "FSEQ," "\n" - "BLOCK_ID," "\n" - "LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB," "\n" - "CREATION_TIME," "\n" - "ARCHIVE_FILE_ID)" "\n" - "VALUES(" "\n" - ":VID," "\n" - ":FSEQ," "\n" - ":BLOCK_ID," "\n" - ":LOGICAL_SIZE_IN_BYTES," "\n" - ":COPY_NB," "\n" - ":CREATION_TIME," "\n" - ":ARCHIVE_FILE_ID)" "\n"; - auto stmt = conn.createStmt(sql); - rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt()); - occiStmt.setColumn(tapeFileBatch.vid); - occiStmt.setColumn(tapeFileBatch.fSeq); - occiStmt.setColumn(tapeFileBatch.blockId); - occiStmt.setColumn(tapeFileBatch.fileSize); - occiStmt.setColumn(tapeFileBatch.copyNb); - occiStmt.setColumn(tapeFileBatch.creationTime); - occiStmt.setColumn(tapeFileBatch.archiveFileId); - try { - occiStmt->executeArrayUpdate(tapeFileBatch.nbRows); - } catch(oracle::occi::SQLException &ex) { - std::ostringstream msg; - msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << - ex.what(); - - if(rdbms::wrapper::OcciStmt::connShouldBeClosed(ex)) { - // Close the statement first and then the connection - try { - occiStmt.close(); - } catch(...) { - } - - try { - conn.closeUnderlyingStmtsAndConn(); - } catch(...) { - } - throw exception::LostDatabaseConnection(msg.str()); - } - throw exception::Exception(msg.str()); - } catch(std::exception &se) { - std::ostringstream msg; - msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << - se.what(); - - throw exception::Exception(msg.str()); - } - } - - // Verify that the archive file entries in the catalogue database agree with - // the tape file written events - const auto fileSizesAndChecksums = selectArchiveFileSizesAndChecksums(conn, fileEvents); - for (const auto &event: fileEvents) { - const auto fileSizeAndChecksumItor = fileSizesAndChecksums.find(event.archiveFileId); - - std::ostringstream fileContext; - fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << - ", diskFileId=" << event.diskFileId; - - // This should never happen - if(fileSizesAndChecksums.end() == fileSizeAndChecksumItor) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << ": Failed to find archive file entry in the catalogue: " << fileContext.str(); - throw ex; - } - - const auto &fileSizeAndChecksum = fileSizeAndChecksumItor->second; - - if(fileSizeAndChecksum.fileSize != event.size) { - catalogue::FileSizeMismatch ex; - ex.getMessage() << __FUNCTION__ << ": File size mismatch: expected=" << fileSizeAndChecksum.fileSize << - ", actual=" << event.size << ": " << fileContext.str(); - throw ex; - } - - fileSizeAndChecksum.checksumBlob.validate(event.checksumBlob); - } - - std::list<InsertFileRecycleLog> recycledFiles = insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn); - - { - const char *const sql = - "INSERT INTO TAPE_FILE (VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID)" "\n" - "SELECT VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID FROM TEMP_TAPE_FILE_INSERTION_BATCH"; - auto stmt = conn.createStmt(sql); - stmt.executeNonQuery(); - } - - for(auto & recycledFile: recycledFiles){ - const char *const sql = - "DELETE FROM " - "TAPE_FILE " - "WHERE " - "TAPE_FILE.VID = :VID AND TAPE_FILE.FSEQ = :FSEQ"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID",recycledFile.vid); - stmt.bindUint64(":FSEQ",recycledFile.fSeq); - stmt.executeNonQuery(); - } - - { - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); - conn.commit(); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// idempotentBatchInsertArchiveFiles -//------------------------------------------------------------------------------ -void OracleCatalogue::idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const std::set<TapeFileWritten> &events) { - try { - ArchiveFileBatch archiveFileBatch(events.size()); - const time_t now = time(nullptr); - std::vector<uint32_t> adler32(events.size()); - - // Store the length of each field and implicitly calculate the maximum field length of each column - uint32_t i = 0; - for (const auto &event: events) { - // Keep transition ADLER32 checksum column up-to-date with the ChecksumBlob - try { - std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(event.checksumBlob.at(checksum::ADLER32)); - adler32[i] = strtoul(adler32hex.c_str(), 0, 16); - } catch(exception::ChecksumTypeMismatch &ex) { - // No ADLER32 checksum exists in the checksumBlob - adler32[i] = 0; - } - - archiveFileBatch.archiveFileId.setFieldLenToValueLen(i, event.archiveFileId); - archiveFileBatch.diskInstance.setFieldLenToValueLen(i, event.diskInstance); - archiveFileBatch.diskFileId.setFieldLenToValueLen(i, event.diskFileId); - archiveFileBatch.diskFileUser.setFieldLenToValueLen(i, event.diskFileOwnerUid); - archiveFileBatch.diskFileGroup.setFieldLenToValueLen(i, event.diskFileGid); - archiveFileBatch.size.setFieldLenToValueLen(i, event.size); - archiveFileBatch.checksumBlob.setFieldLen(i, 2 + event.checksumBlob.length()); - archiveFileBatch.checksumAdler32.setFieldLenToValueLen(i, adler32[i]); - archiveFileBatch.storageClassName.setFieldLenToValueLen(i, event.storageClassName); - archiveFileBatch.creationTime.setFieldLenToValueLen(i, now); - archiveFileBatch.reconciliationTime.setFieldLenToValueLen(i, now); - i++; - } - - // Store the value of each field - i = 0; - for (const auto &event: events) { - archiveFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); - archiveFileBatch.diskInstance.setFieldValue(i, event.diskInstance); - archiveFileBatch.diskFileId.setFieldValue(i, event.diskFileId); - archiveFileBatch.diskFileUser.setFieldValue(i, event.diskFileOwnerUid); - archiveFileBatch.diskFileGroup.setFieldValue(i, event.diskFileGid); - archiveFileBatch.size.setFieldValue(i, event.size); - archiveFileBatch.checksumBlob.setFieldValueToRaw(i, event.checksumBlob.serialize()); - archiveFileBatch.checksumAdler32.setFieldValue(i, adler32[i]); - archiveFileBatch.storageClassName.setFieldValue(i, event.storageClassName); - archiveFileBatch.creationTime.setFieldValue(i, now); - archiveFileBatch.reconciliationTime.setFieldValue(i, now); - i++; - } - - const char *const sql = - "INSERT INTO ARCHIVE_FILE(" - "ARCHIVE_FILE_ID," - "DISK_INSTANCE_NAME," - "DISK_FILE_ID," - "DISK_FILE_UID," - "DISK_FILE_GID," - "SIZE_IN_BYTES," - "CHECKSUM_BLOB," - "CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - "CREATION_TIME," - "RECONCILIATION_TIME)" - "SELECT " - ":ARCHIVE_FILE_ID," - ":DISK_INSTANCE_NAME," - ":DISK_FILE_ID," - ":DISK_FILE_UID," - ":DISK_FILE_GID," - ":SIZE_IN_BYTES," - ":CHECKSUM_BLOB," - ":CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - ":CREATION_TIME," - ":RECONCILIATION_TIME " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt()); - occiStmt->setBatchErrorMode(true); - - occiStmt.setColumn(archiveFileBatch.archiveFileId); - occiStmt.setColumn(archiveFileBatch.diskInstance); - occiStmt.setColumn(archiveFileBatch.diskFileId); - occiStmt.setColumn(archiveFileBatch.diskFileUser); - occiStmt.setColumn(archiveFileBatch.diskFileGroup); - occiStmt.setColumn(archiveFileBatch.size); - occiStmt.setColumn(archiveFileBatch.checksumBlob, oracle::occi::OCCI_SQLT_VBI); - occiStmt.setColumn(archiveFileBatch.checksumAdler32); - occiStmt.setColumn(archiveFileBatch.storageClassName); - occiStmt.setColumn(archiveFileBatch.creationTime); - occiStmt.setColumn(archiveFileBatch.reconciliationTime); - - try { - occiStmt->executeArrayUpdate(archiveFileBatch.nbRows); - } catch(oracle::occi::BatchSQLException &be) { - const unsigned int nbFailedRows = be.getFailedRowCount(); - exception::Exception ex; - ex.getMessage() << "Caught a BatchSQLException" << nbFailedRows; - bool foundErrorOtherThanUniqueConstraint = false; - for (unsigned int row = 0; row < nbFailedRows; row++ ) { - oracle::occi::SQLException err = be.getException(row); - const unsigned int rowIndex = be.getRowNum(row); - const int errorCode = err.getErrorCode(); - - // If the error is anything other than a unique constraint error - if(1 != errorCode) { - foundErrorOtherThanUniqueConstraint = true; - ex.getMessage() << ": Row " << rowIndex << " generated ORA error " << errorCode; - } - } - if (foundErrorOtherThanUniqueConstraint) { - throw ex; - } - } catch(oracle::occi::SQLException &ex) { - std::ostringstream msg; - msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << - ex.what(); - - if(rdbms::wrapper::OcciStmt::connShouldBeClosed(ex)) { - // Close the statement first and then the connection - try { - occiStmt.close(); - } catch(...) { - } - - try { - conn.closeUnderlyingStmtsAndConn(); - } catch(...) { - } - throw exception::LostDatabaseConnection(msg.str()); - } - throw exception::Exception(msg.str()); - } catch(std::exception &se) { - std::ostringstream msg; - msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << - se.what(); - - throw exception::Exception(msg.str()); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::list<cta::catalogue::InsertFileRecycleLog> OracleCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn& conn) { - std::list<cta::catalogue::InsertFileRecycleLog> fileRecycleLogsToInsert; - try { - //Get the TAPE_FILE entry to put on the file recycle log - { - const char *const sql = - "SELECT " - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," - "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " - "FROM " - "TAPE_FILE " - "JOIN " - "TEMP_TAPE_FILE_INSERTION_BATCH " - "ON " - "TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID AND TEMP_TAPE_FILE_INSERTION_BATCH.COPY_NB = TAPE_FILE.COPY_NB " - "WHERE " - "TAPE_FILE.VID != TEMP_TAPE_FILE_INSERTION_BATCH.VID OR TAPE_FILE.FSEQ != TEMP_TAPE_FILE_INSERTION_BATCH.FSEQ"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while(rset.next()){ - cta::catalogue::InsertFileRecycleLog fileRecycleLog; - fileRecycleLog.vid = rset.columnString("VID"); - fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); - fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); - fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); - fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); - fileRecycleLog.recycleLogTime = time(nullptr); - fileRecycleLogsToInsert.push_back(fileRecycleLog); - } - } - { - for(auto & fileRecycleLog: fileRecycleLogsToInsert){ - insertFileInFileRecycleLog(conn,fileRecycleLog); - } - } - return fileRecycleLogsToInsert; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// selectArchiveFileSizeAndChecksum -//------------------------------------------------------------------------------ -std::map<uint64_t, OracleCatalogue::FileSizeAndChecksum> OracleCatalogue::selectArchiveFileSizesAndChecksums( - rdbms::Conn &conn, const std::set<TapeFileWritten> &events) { - try { - std::vector<oracle::occi::Number> archiveFileIdList(events.size()); - for (const auto &event: events) { - archiveFileIdList.push_back(oracle::occi::Number(event.archiveFileId)); - } - - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32 " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN TEMP_TAPE_FILE_INSERTION_BATCH ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - - std::map<uint64_t, FileSizeAndChecksum> fileSizesAndChecksums; - while (rset.next()) { - const uint64_t archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - - if (fileSizesAndChecksums.end() != fileSizesAndChecksums.find(archiveFileId)) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed: " - "Found duplicate archive file identifier in batch of files written to tape: archiveFileId=" << archiveFileId; - throw ex; - } - FileSizeAndChecksum fileSizeAndChecksum; - fileSizeAndChecksum.fileSize = rset.columnUint64("SIZE_IN_BYTES"); - fileSizeAndChecksum.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - fileSizesAndChecksums[archiveFileId] = fileSizeAndChecksum; - } - - return fileSizesAndChecksums; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteArchiveFile -//------------------------------------------------------------------------------ -void OracleCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, - log::LogContext &lc) { - try { - const char *selectSql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " - "FOR UPDATE"; - utils::Timer t; - - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - - const auto getConnTime = t.secs(utils::Timer::resetCounter); - auto selectStmt = conn.createStmt(selectSql); - const auto createStmtTime = t.secs(); - selectStmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - t.reset(); - rdbms::Rset selectRset = selectStmt.executeQuery(); - const auto selectFromArchiveFileTime = t.secs(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - std::set<std::string> vidsToSetDirty; - while(selectRset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = selectRset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = selectRset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = selectRset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = selectRset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = selectRset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = selectRset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(selectRset.columnBlob("CHECKSUM_BLOB"), selectRset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = selectRset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = selectRset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = selectRset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file - if(!selectRset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = selectRset.columnString("VID"); - vidsToSetDirty.insert(tapeFile.vid); - tapeFile.fSeq = selectRset.columnUint64("FSEQ"); - tapeFile.blockId = selectRset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = selectRset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = selectRset.columnUint8("COPY_NB"); - tapeFile.creationTime = selectRset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - if(nullptr == archiveFile.get()) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", archiveFileId); - lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); - return; - } - - if(diskInstanceName != archiveFile->diskInstance) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("requestDiskInstance", diskInstanceName) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("createStmtTime", createStmtTime) - .add("selectFromArchiveFileTime", selectFromArchiveFileTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " - "of the archived file"); - - exception::UserError ue; - ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " - "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << - archiveFile->diskInstance; - throw ue; - } - - t.reset(); - { - const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - - const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); - - //Set the tapes where the files have been deleted to dirty - for(auto &vidToSetDirty: vidsToSetDirty){ - setTapeDirty(conn,vidToSetDirty); - } - - const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); - - { - const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); - - conn.commit(); - const auto commitTime = t.secs(); - - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("createStmtTime", createStmtTime) - .add("selectFromArchiveFileTime", selectFromArchiveFileTime) - .add("deleteFromTapeFileTime", deleteFromTapeFileTime) - .add("setTapeDirtyTime",setTapeDirtyTime) - .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) - .add("commitTime", commitTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << it->copyNb - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::INFO, "Archive file deleted from CTA catalogue"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - std::ostringstream msg; - msg << __FUNCTION__ << ": diskInstanceName=" << diskInstanceName <<",archiveFileId=" << - archiveFileId << ": " << ex.getMessage().str(); - ex.getMessage().str(msg.str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyArchiveFileToRecycleBinAndDelete -//------------------------------------------------------------------------------ -void OracleCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc){ - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO, update and two DELETE FROM - //in a single transaction - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - copyArchiveFileToFileRecycleLog(conn,request); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn,request.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,request); - tl.insertAndReset("deleteTapeFilesTime",t); - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); - RdbmsCatalogue::deleteArchiveFile(conn,request); - tl.insertAndReset("deleteArchiveFileTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",request.archiveFileID); - spc.add("diskFileId",request.diskFileId); - spc.add("diskFilePath",request.diskFilePath); - spc.add("diskInstance",request.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In OracleCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFilesAndArchiveFileFromRecycleBin -//------------------------------------------------------------------------------ -void OracleCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId, log::LogContext& lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do two delete in one transaction - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - deleteTapeFilesFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteTapeFilesTime",t); - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); - deleteArchiveFileFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteArchiveFileTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",archiveFileId); - tl.addToLog(spc); - lc.log(log::INFO,"In OracleCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin: tape files and archiveFiles deleted from the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyTapeFileToFileRecyleLogAndDelete -//------------------------------------------------------------------------------ -void OracleCatalogue::copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO and a DELETE FROM - //in a single transaction - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - copyTapeFilesToFileRecycleLog(conn, file, reason); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn, file.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,file); - tl.insertAndReset("deleteTapeFilesTime",t); - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId", file.archiveFileID); - spc.add("diskFileId", file.diskFileId); - spc.add("diskFilePath", file.diskFileInfo.path); - spc.add("diskInstance", file.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In OracleCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreEntryInRecycleLog -//------------------------------------------------------------------------------ -void OracleCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, - const std::string &newFid, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - - if (!fileRecycleLogItor.hasMore()) { - throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); - } - auto fileRecycleLog = fileRecycleLogItor.next(); - if (fileRecycleLogItor.hasMore()) { - //stop restoring more than one file at once - throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); - } - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); - - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFilePtr = getArchiveFileById(conn, fileRecycleLog.archiveFileId); - if (!archiveFilePtr) { - restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); - } else { - if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { - //copy with same copy_nb exists, cannot restore - UserSpecifiedExistingDeletedFileCopy ex; - ex.getMessage() << "Cannot restore file copy with archiveFileId " << std::to_string(fileRecycleLog.archiveFileId) - << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) << " because a tapefile with same archiveFileId and copy_nb already exists"; - throw ex; - } - } - - - restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); - - conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); - conn.commit(); - - log::ScopedParamContainer spc(lc); - tl.insertAndReset("commitTime",t); - tl.addToLog(spc); - lc.log(log::INFO,"In OracleCatalogue::restoreEntryInRecycleLog: all file copies successfully restored."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreFileCopyInRecycleLog -//------------------------------------------------------------------------------ -void OracleCatalogue::restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - cta::common::dataStructures::TapeFile tapeFile; - tapeFile.vid = fileRecycleLog.vid; - tapeFile.fSeq = fileRecycleLog.fSeq; - tapeFile.copyNb = fileRecycleLog.copyNb; - tapeFile.blockId = fileRecycleLog.blockId; - tapeFile.fileSize = fileRecycleLog.sizeInBytes; - tapeFile.creationTime = fileRecycleLog.tapeFileCreationTime; - - insertTapeFile(conn, tapeFile, fileRecycleLog.archiveFileId); - tl.insertAndReset("insertTapeFileTime",t); - - deleteTapeFileCopyFromRecycleBin(conn, fileRecycleLog); - tl.insertAndReset("deleteTapeFileCopyFromRecycleBinTime",t); - - log::ScopedParamContainer spc(lc); - spc.add("vid", tapeFile.vid); - spc.add("archiveFileId", fileRecycleLog.archiveFileId); - spc.add("fSeq", tapeFile.fSeq); - spc.add("copyNb", tapeFile.copyNb); - spc.add("fileSize", tapeFile.fileSize); - tl.addToLog(spc); - lc.log(log::INFO,"In OracleCatalogue::restoreFileCopyInRecycleLog: File restored from the recycle log."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/OracleCatalogue.hpp b/catalogue/OracleCatalogue.hpp deleted file mode 100644 index 26fdd5674e..0000000000 --- a/catalogue/OracleCatalogue.hpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include "catalogue/RdbmsCatalogue.hpp" -#include "catalogue/InsertFileRecycleLog.hpp" -#include "rdbms/Conn.hpp" - -namespace cta { -namespace catalogue { - -/** - * An Oracle based implementation of the CTA catalogue. - */ -class OracleCatalogue: public RdbmsCatalogue { -public: - - /** - * Constructor. - * - * @param log Object representing the API to the CTA logging system. - * @param username The database username. - * @param password The database password. - * @param database The database name. - * @param nbConns The maximum number of concurrent connections to the - * underlying relational database for all operations accept listing archive - * files which can be relatively long operations. - * @param nbArchiveFileListingConns The maximum number of concurrent - * connections to the underlying relational database for the sole purpose of - * listing archive files. - */ - OracleCatalogue( - log::Logger &log, - const std::string &username, - const std::string &password, - const std::string &database, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns); - - /** - * Destructor. - */ - ~OracleCatalogue() override; - - /** - * Creates a temporary table from the list of disk file IDs provided in the search criteria. - * - * @param conn The database connection. - * @param diskFileIds List of disk file IDs (fxid). - * @return Name of the temporary table - */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const override; - - /** - * Returns a unique archive ID that can be used by a new archive file 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 archive ID that can be used by a new archive file within - * the catalogue. - */ - uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; - - /** - * Returns a unique logical library ID that can be used by a new logical - * library 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 logical library ID that can be used by a new logical - * library storage class within the catalogue. - */ - uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) override; - - /** - * Returns a unique virtual organization ID that can be used by a new Virtual Organization - * 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 virtual organization ID that can be used by a new Virtual Organization - * within the catalogue. - */ - uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; - - /** - * Returns a unique media type ID that can be used by a new media type 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 media type ID that can be used by a new media type - * within the catalogue. - */ - uint64_t getNextMediaTypeId(rdbms::Conn &conn) override; - - /** - * Returns a unique storage class ID that can be used by a new storage class - * 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 storage class ID that can be used by a new storage class - * within the catalogue. - */ - 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; - - /** - * Returns a unique file recycle log ID that can be used by a new entry of file recycle log 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 file recycle log ID that can be used by a new entry of file recycle log within - * the catalogue. - */ - uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) override; - - - /** - * Notifies the catalogue that the specified files have been written to tape. - * - * @param events The tape file written events. - */ - void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) override; - - /** - * !!!!!!!!!!!!!!!!!!! THIS METHOD SHOULD NOT BE USED !!!!!!!!!!!!!!!!!!!!!!! - * Deletes the specified archive file and its associated tape copies from the - * catalogue. - * - * Please note that the name of the disk instance is specified in order to - * prevent a disk instance deleting an archive file that belongs to another - * disk instance. - * - * Please note that this method is idempotent. If the file to be deleted does - * not exist in the CTA catalogue then this method returns without error. - * - * @param instanceName The name of the instance from where the deletion request - * originated - * @param archiveFileId The unique identifier of the archive file. - * @param lc The log context. - * @return The metadata of the deleted archive file including the metadata of - * the associated and also deleted tape copies. - */ - void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &instanceName, const uint64_t archiveFileId, - log::LogContext &lc) override; - -private: - - /** - * 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. - */ - uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid); - - /** - * Batch inserts rows into the ARCHIVE_FILE table that correspond to the - * specified TapeFileWritten events. - * - * This method has idempotent behaviour in the case where an ARCHIVE_FILE - * already exists. Such a situation will occur when a file has more than one - * copy on tape. The first tape copy will cause two successful inserts, one - * into the ARCHIVE_FILE table and one into the TAPE_FILE table. The second - * tape copy will try to do the same, but the insert into the ARCHIVE_FILE - * table will fail or simply bounce as the row will already exists. The - * insert into the TABLE_FILE table will succeed because the two TAPE_FILE - * rows will be unique. - * - * @param conn The database connection. - * @param events The tape file written events. - */ - void idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const std::set<TapeFileWritten> &events); - - /** - * In the case we insert a TAPE_FILE that already has a copy on the catalogue (same copyNb), - * this TAPE_FILE will go to the FILE_RECYCLE_LOG table. - * - * This case happens always during the repacking of a tape: the new TAPE_FILE created - * will replace the old one, the old one will then be moved to the FILE_RECYCLE_LOG table - * - * @param conn The database connection. - * @returns the list of inserted fileRecycleLog - */ - std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn); - - /** - * Copy the archiveFile and the associated tape files from the ARCHIVE_FILE and TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the ARCHIVE_FILE and TAPE_FILE entries. - * @param conn the database connection - * @param request the request that contains the necessary informations to identify the archiveFile to copy to the FILE_RECYCLE_LOG table - * @param lc the log context - */ - void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; - - /** - * Delete the TapeFiles and the ArchiveFile from the recycle-bin in one transaction - * @param conn the database connection - * @param archiveFileId the archiveFileId of the file to delete from the recycle-bin - */ - void deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId, log::LogContext& lc) override; - - /** - * Copy the tape files from the TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the TAPE_FILE entry. - * @param conn the database connection - * @param file the file to be deleted - * @param reason The reason for deleting the tape file copy - * @param lc the log context - */ - void copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, - const std::string &reason, log::LogContext & lc) override; - - /** - * Copy the files in fileRecycleLogItor to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entries - * @param conn the database connection - * @param fileRecycleLogItor the collection of fileRecycleLogs we want to restore - * @param lc the log context - */ - void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) override; - - /** - * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry - * @param conn the database connection - * @param fileRecycleLog the fileRecycleLog we want to restore - * @param lc the log context - */ - void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLogItor, log::LogContext & lc); - - /** - * The size and checksum of a file. - */ - struct FileSizeAndChecksum { - uint64_t fileSize; - checksum::ChecksumBlob checksumBlob; - }; - - /** - * Returns the sizes and checksums of the specified archive files. - * - * @param conn The database connection. - * @param events The tape file written events that identify the archive files. - * @return A map from the identifier of each archive file to its size and checksum. - */ - std::map<uint64_t, FileSizeAndChecksum> selectArchiveFileSizesAndChecksums(rdbms::Conn &conn, - const std::set<TapeFileWritten> &events); - -}; // class OracleCatalogue - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/OracleCatalogueFactory.cpp b/catalogue/OracleCatalogueFactory.cpp index 3df6517956..4347879d19 100644 --- a/catalogue/OracleCatalogueFactory.cpp +++ b/catalogue/OracleCatalogueFactory.cpp @@ -15,9 +15,13 @@ * submit itself to any jurisdiction. */ -#include "catalogue/CatalogueRetryWrapper.hpp" +#include <memory> +#include <string> +#include <utility> + #include "catalogue/OracleCatalogueFactory.hpp" -#include "catalogue/OracleCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleCatalogue.hpp" +#include "catalogue/retrywrappers/CatalogueRetryWrapper.hpp" #include "common/exception/Exception.hpp" namespace cta { @@ -37,7 +41,7 @@ OracleCatalogueFactory::OracleCatalogueFactory( m_nbConns(nbConns), m_nbArchiveFileListingConns(nbArchiveFileListingConns), m_maxTriesToConnect(maxTriesToConnect) { - if(rdbms::Login::DBTYPE_ORACLE != login.dbType) { + if (rdbms::Login::DBTYPE_ORACLE != login.dbType) { exception::Exception ex; ex.getMessage() << __FUNCTION__ << "failed: Incorrect database type: expected=DBTYPE_ORACLE actual=" << login.dbTypeToString(login.dbType); @@ -58,5 +62,5 @@ std::unique_ptr<Catalogue> OracleCatalogueFactory::create() { } } -} // namespace catalogue -} // namespace cta +} // namespace catalogue +} // namespace cta diff --git a/catalogue/OracleCatalogueFactory.hpp b/catalogue/OracleCatalogueFactory.hpp index f4addb1f4b..8ebb524529 100644 --- a/catalogue/OracleCatalogueFactory.hpp +++ b/catalogue/OracleCatalogueFactory.hpp @@ -21,6 +21,11 @@ #include "rdbms/Login.hpp" namespace cta { + +namespace log { +class Logger; +} + namespace catalogue { /** diff --git a/catalogue/PostgresCatalogue.cpp b/catalogue/PostgresCatalogue.cpp deleted file mode 100644 index 031ab83fce..0000000000 --- a/catalogue/PostgresCatalogue.cpp +++ /dev/null @@ -1,1204 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include <algorithm> - -#include "catalogue/ArchiveFileRow.hpp" -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/InsertFileRecycleLog.hpp" -#include "catalogue/PostgresCatalogue.hpp" -#include "catalogue/retryOnLostConnection.hpp" -#include "catalogue/TapeItemWrittenPointer.hpp" -#include "common/dataStructures/DeleteArchiveRequest.hpp" -#include "common/dataStructures/FileRecycleLog.hpp" -#include "common/exception/Exception.hpp" -#include "common/exception/FileSizeMismatch.hpp" -#include "common/exception/LostDatabaseConnection.hpp" -#include "common/exception/TapeFseqMismatch.hpp" -#include "common/exception/UserError.hpp" -#include "common/log/TimingList.hpp" -#include "common/Timer.hpp" -#include "common/utils/utils.hpp" -#include "rdbms/AutoRollback.hpp" -#include "rdbms/rdbms.hpp" -#include "rdbms/wrapper/PostgresColumn.hpp" -#include "rdbms/wrapper/PostgresStmt.hpp" - -namespace cta { -namespace catalogue { - -namespace { - /** - * Structure used to assemble a batch of rows to insert into the TAPE_FILE - * table. - */ - struct TapeFileBatch { - size_t nbRows; - rdbms::wrapper::PostgresColumn vid; - rdbms::wrapper::PostgresColumn fSeq; - rdbms::wrapper::PostgresColumn blockId; - rdbms::wrapper::PostgresColumn fileSize; - rdbms::wrapper::PostgresColumn copyNb; - rdbms::wrapper::PostgresColumn creationTime; - rdbms::wrapper::PostgresColumn archiveFileId; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - TapeFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - vid("VID", nbRows), - fSeq("FSEQ", nbRows), - blockId("BLOCK_ID", nbRows), - fileSize("LOGICAL_SIZE_IN_BYTES", nbRows), - copyNb("COPY_NB", nbRows), - creationTime("CREATION_TIME", nbRows), - archiveFileId("ARCHIVE_FILE_ID", nbRows) { - } - }; // struct TapeFileBatch - - /** - * Structure used to assemble a batch of rows to insert into the TEMP_ARCHIVE_FILE_BATCH - * table. - */ - struct ArchiveFileBatch { - size_t nbRows; - rdbms::wrapper::PostgresColumn archiveFileId; - rdbms::wrapper::PostgresColumn diskInstance; - rdbms::wrapper::PostgresColumn diskFileId; - rdbms::wrapper::PostgresColumn diskFileUser; - rdbms::wrapper::PostgresColumn diskFileGroup; - rdbms::wrapper::PostgresColumn size; - rdbms::wrapper::PostgresColumn checksumBlob; - rdbms::wrapper::PostgresColumn checksumAdler32; - rdbms::wrapper::PostgresColumn storageClassName; - rdbms::wrapper::PostgresColumn creationTime; - rdbms::wrapper::PostgresColumn reconciliationTime; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - ArchiveFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - archiveFileId("ARCHIVE_FILE_ID", nbRows), - diskInstance("DISK_INSTANCE_NAME", nbRows), - diskFileId("DISK_FILE_ID", nbRows), - diskFileUser("DISK_FILE_UID", nbRows), - diskFileGroup("DISK_FILE_GID", nbRows), - size("SIZE_IN_BYTES", nbRows), - checksumBlob("CHECKSUM_BLOB", nbRows), - checksumAdler32("CHECKSUM_ADLER32", nbRows), - storageClassName("STORAGE_CLASS_NAME", nbRows), - creationTime("CREATION_TIME", nbRows), - reconciliationTime("RECONCILIATION_TIME", nbRows) { - } - }; // struct ArchiveFileBatch - - /** - * Structure used to assemble a batch of rows to insert into the - * TAPE_FILE_BATCH temporary table. - */ - struct TempTapeFileBatch { - size_t nbRows; - rdbms::wrapper::PostgresColumn archiveFileId; - - /** - * Constructor. - * - * @param nbRowsValue The Number of rows to be inserted. - */ - TempTapeFileBatch(const size_t nbRowsValue): - nbRows(nbRowsValue), - archiveFileId("ARCHIVE_FILE_ID", nbRows) { - } - }; // struct TempTapeFileBatch -} // anonymous namespace - -//------------------------------------------------------------------------------ -// constructor -//------------------------------------------------------------------------------ -PostgresCatalogue::PostgresCatalogue( - log::Logger &log, - const rdbms::Login &login, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns): - RdbmsCatalogue( - log, - rdbms::Login(rdbms::Login::DBTYPE_POSTGRESQL, - login.username, login.password, login.database, - login.hostname, login.port), - nbConns, - nbArchiveFileListingConns) { -} - -//------------------------------------------------------------------------------ -// destructor -//------------------------------------------------------------------------------ -PostgresCatalogue::~PostgresCatalogue() { -} - -//------------------------------------------------------------------------------ -// createAndPopulateTempTableFxid -//------------------------------------------------------------------------------ -std::string PostgresCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const { - const std::string tempTableName = "TEMP_DISK_FXIDS"; - - if(diskFileIds) { - try { - std::string sql = "CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID VARCHAR(100))"; - try { - conn.executeNonQuery(sql); - } catch(exception::Exception &ex) { - // Postgres does not drop temporary tables until the end of the session; trying to create another - // temporary table in the same unit test will fail. If this happens, truncate the table and carry on. - sql = "TRUNCATE TABLE " + tempTableName; - conn.executeNonQuery(sql); - } - - sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; - auto stmt = conn.createStmt(sql); - for(auto &diskFileId : diskFileIds.value()) { - stmt.bindString(":DISK_FILE_ID", diskFileId); - stmt.executeNonQuery(); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - } - return tempTableName; -} - -//------------------------------------------------------------------------------ -// getNextArchiveFileId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { - try { - const char *const sql = - "select NEXTVAL('ARCHIVE_FILE_ID_SEQ') AS ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("ARCHIVE_FILE_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextLogicalLibraryId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) { - try { - const char *const sql = - "select NEXTVAL('LOGICAL_LIBRARY_ID_SEQ') AS LOGICAL_LIBRARY_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("LOGICAL_LIBRARY_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextVirtualOrganizationId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { - try { - const char *const sql = - "select NEXTVAL('VIRTUAL_ORGANIZATION_ID_SEQ') AS VIRTUAL_ORGANIZATION_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("VIRTUAL_ORGANIZATION_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextMediaTypeId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextMediaTypeId(rdbms::Conn &conn) { - try { - const char *const sql = "select NEXTVAL('MEDIA_TYPE_ID_SEQ') AS MEDIA_TYPE_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("MEDIA_TYPE_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextStorageClassId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextStorageClassId(rdbms::Conn &conn) { - try { - const char *const sql = - "select NEXTVAL('STORAGE_CLASS_ID_SEQ') AS STORAGE_CLASS_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("STORAGE_CLASS_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextTapePoolId -//------------------------------------------------------------------------------ -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; - } -} - -//------------------------------------------------------------------------------ -// getNextFileRecyleLogId -//------------------------------------------------------------------------------ -uint64_t PostgresCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) { - try { - const char *const sql = - "select NEXTVAL('FILE_RECYCLE_LOG_ID_SEQ') AS FILE_RECYCLE_LOG_ID"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set is unexpectedly empty"); - } - return rset.columnUint64("FILE_RECYCLE_LOG_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 " - "LAST_FSEQ AS LAST_FSEQ " - "FROM " - "TAPE " - "WHERE " - "VID = :VID " - "FOR UPDATE"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - if (!rset.next()) { - throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); - } - - return rset.columnUint64("LAST_FSEQ"); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// filesWrittenToTape -//------------------------------------------------------------------------------ -void PostgresCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { - try { - if (events.empty()) { - return; - } - - auto firstEventItor = events.begin(); - const auto &firstEvent = **firstEventItor; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); - const time_t now = time(nullptr); - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - - // Start DB transaction and create temporary tables TEMP_ARCHIVE_FILE_BATCH and TEMP_TAPE_FILE_BATCH. - // These two tables will exist only for the duration of the transaction. - // Set deferrable for second (disk instance, disk file id) constraint of the ARCHIVE_FILE table - // to avoid violation in the case of concurrent inserts of a previously not existing archive file. - beginCreateTemporarySetDeferred(conn); - - 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 - // allow checking fSeq coherency. - // determine the number of files - size_t filesCount=std::count_if(events.cbegin(), events.cend(), - [](const TapeItemWrittenPointer &e) -> bool {return typeid(*e)==typeid(TapeFileWritten);}); - TapeFileBatch tapeFileBatch(filesCount); - - std::set<TapeFileWritten> fileEvents; - - for (const auto &eventP: events) { - // Check for all item types. - const auto &event = *eventP; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); - - if (event.vid != firstEvent.vid) { - throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); - } - - if (expectedFSeq != event.fSeq) { - exception::TapeFseqMismatch ex; - ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << - event.fSeq; - throw ex; - } - expectedFSeq++; - - try { - // If this is a file (as opposed to a placeholder), do the full processing. - const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); - - checkTapeFileWrittenFieldsAreSet(__FUNCTION__, fileEvent); - - totalLogicalBytesWritten += fileEvent.size; - - fileEvents.insert(fileEvent); - } catch (std::bad_cast&) {} - } - - // Update the tape because all the necessary information is now available - auto lastEventItor = events.cend(); - lastEventItor--; - const TapeItemWritten &lastEvent = **lastEventItor; - updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, lastEvent.tapeDrive); - - // If we had only placeholders and no file recorded, we are done (but we still commit the update of the tape's fSeq). - if (fileEvents.empty()) { - conn.commit(); - return; - } - - // Create the archive file entries, skipping those that already exist - // However we don't currently lock existing rows, so this transaction may - // still fail later, in the face of certain concurrent modifications such - // as the deletion of one of the existing archive files for which we are - // inserting another tape file. - idempotentBatchInsertArchiveFiles(conn, fileEvents); - - insertTapeFileBatchIntoTempTable(conn, fileEvents); - - // Verify that the archive file entries in the catalogue database agree with - // the tape file written events - const auto fileSizesAndChecksums = selectArchiveFileSizesAndChecksums(conn, fileEvents); - for (const auto &event: fileEvents) { - const auto fileSizeAndChecksumItor = fileSizesAndChecksums.find(event.archiveFileId); - - std::ostringstream fileContext; - fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << - ", diskFileId=" << event.diskFileId; - - // This should never happen - if(fileSizesAndChecksums.end() == fileSizeAndChecksumItor) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << ": Failed to find archive file entry in the catalogue: " << fileContext.str(); - throw ex; - } - - const auto &fileSizeAndChecksum = fileSizeAndChecksumItor->second; - - if(fileSizeAndChecksum.fileSize != event.size) { - catalogue::FileSizeMismatch ex; - ex.getMessage() << __FUNCTION__ << ": File size mismatch: expected=" << fileSizeAndChecksum.fileSize << - ", actual=" << event.size << ": " << fileContext.str(); - throw ex; - } - - fileSizeAndChecksum.checksumBlob.validate(event.checksumBlob); - } - - // Store the value of each field - uint32_t i = 0; - for (const auto &event: fileEvents) { - tapeFileBatch.vid.setFieldValue(i, event.vid); - tapeFileBatch.fSeq.setFieldValue(i, event.fSeq); - tapeFileBatch.blockId.setFieldValue(i, event.blockId); - tapeFileBatch.fileSize.setFieldValue(i, event.size); - tapeFileBatch.copyNb.setFieldValue(i, event.copyNb); - tapeFileBatch.creationTime.setFieldValue(i, now); - tapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); - i++; - } - - const char *const sql = - "CREATE TEMPORARY TABLE TEMP_TAPE_FILE_INSERTION_BATCH (" "\n" - "LIKE TAPE_FILE) " "\n" - "ON COMMIT DROP;" "\n" - "COPY TEMP_TAPE_FILE_INSERTION_BATCH(" "\n" - "VID," "\n" - "FSEQ," "\n" - "BLOCK_ID," "\n" - "LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB," "\n" - "CREATION_TIME," "\n" - "ARCHIVE_FILE_ID) " "\n" - "FROM STDIN; --" "\n" - "-- :VID," "\n" - "-- :FSEQ," "\n" - "-- :BLOCK_ID," "\n" - "-- :LOGICAL_SIZE_IN_BYTES," "\n" - "-- :COPY_NB," "\n" - "-- :CREATION_TIME," "\n" - "-- :ARCHIVE_FILE_ID;" "\n"; - - auto stmt = conn.createStmt(sql); - rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); - postgresStmt.setColumn(tapeFileBatch.vid); - postgresStmt.setColumn(tapeFileBatch.fSeq); - postgresStmt.setColumn(tapeFileBatch.blockId); - postgresStmt.setColumn(tapeFileBatch.fileSize); - postgresStmt.setColumn(tapeFileBatch.copyNb); - postgresStmt.setColumn(tapeFileBatch.creationTime); - postgresStmt.setColumn(tapeFileBatch.archiveFileId); - - postgresStmt.executeCopyInsert(tapeFileBatch.nbRows); - - auto recycledFiles = insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn); - - { - //Insert the tapefiles from the TEMP_TAPE_FILE_INSERTION_BATCH - const char * const insertTapeFileSql = - "INSERT INTO TAPE_FILE (VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID) " "\n" - "SELECT VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES," "\n" - "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID FROM TEMP_TAPE_FILE_INSERTION_BATCH;" "\n"; - conn.executeNonQuery(insertTapeFileSql); - } - - for(auto & recycledFile: recycledFiles){ - const char * const deleteTapeFileSql = - "DELETE FROM TAPE_FILE WHERE TAPE_FILE.VID = :VID AND TAPE_FILE.FSEQ = :FSEQ"; - auto deleteTapeFileStmt = conn.createStmt(deleteTapeFileSql); - deleteTapeFileStmt.bindString(":VID",recycledFile.vid); - deleteTapeFileStmt.bindUint64(":FSEQ",recycledFile.fSeq); - deleteTapeFileStmt.executeNonQuery(); - } - - autoRollback.cancel(); - conn.commit(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// idempotentBatchInsertArchiveFiles -//------------------------------------------------------------------------------ -void PostgresCatalogue::idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, - const std::set<TapeFileWritten> &events) const { - try { - ArchiveFileBatch archiveFileBatch(events.size()); - const time_t now = time(nullptr); - - // Store the value of each field - uint32_t i = 0; - for (const auto &event: events) { - archiveFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); - archiveFileBatch.diskInstance.setFieldValue(i, event.diskInstance); - archiveFileBatch.diskFileId.setFieldValue(i, event.diskFileId); - archiveFileBatch.diskFileUser.setFieldValue(i, event.diskFileOwnerUid); - archiveFileBatch.diskFileGroup.setFieldValue(i, event.diskFileGid); - archiveFileBatch.size.setFieldValue(i, event.size); - archiveFileBatch.checksumBlob.setFieldByteA(conn, i, event.checksumBlob.serialize()); - // Keep transition ADLER32 checksum up-to-date if it exists - std::string adler32str; - try { - std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(event.checksumBlob.at(checksum::ADLER32)); - uint32_t adler32 = strtoul(adler32hex.c_str(), 0, 16); - adler32str = std::to_string(adler32); - } catch(exception::ChecksumTypeMismatch &ex) { - adler32str = "0"; - } - archiveFileBatch.checksumAdler32.setFieldValue(i, adler32str); - archiveFileBatch.storageClassName.setFieldValue(i, event.storageClassName); - archiveFileBatch.creationTime.setFieldValue(i, now); - archiveFileBatch.reconciliationTime.setFieldValue(i, now); - i++; - } - - const char *const sql = - "COPY TEMP_ARCHIVE_FILE_BATCH(" - "ARCHIVE_FILE_ID," - "DISK_INSTANCE_NAME," - "DISK_FILE_ID," - "DISK_FILE_UID," - "DISK_FILE_GID," - "SIZE_IN_BYTES," - "CHECKSUM_BLOB," - "CHECKSUM_ADLER32," - "STORAGE_CLASS_NAME," - "CREATION_TIME," - "RECONCILIATION_TIME) " - "FROM STDIN --" - ":ARCHIVE_FILE_ID," - ":DISK_INSTANCE_NAME," - ":DISK_FILE_ID," - ":DISK_FILE_UID," - ":DISK_FILE_GID," - ":SIZE_IN_BYTES," - ":CHECKSUM_BLOB," - ":CHECKSUM_ADLER32," - ":STORAGE_CLASS_NAME," - ":CREATION_TIME," - ":RECONCILIATION_TIME"; - - auto stmt = conn.createStmt(sql); - rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); - - postgresStmt.setColumn(archiveFileBatch.archiveFileId); - postgresStmt.setColumn(archiveFileBatch.diskInstance); - postgresStmt.setColumn(archiveFileBatch.diskFileId); - postgresStmt.setColumn(archiveFileBatch.diskFileUser); - postgresStmt.setColumn(archiveFileBatch.diskFileGroup); - postgresStmt.setColumn(archiveFileBatch.size); - postgresStmt.setColumn(archiveFileBatch.checksumBlob); - postgresStmt.setColumn(archiveFileBatch.checksumAdler32); - postgresStmt.setColumn(archiveFileBatch.storageClassName); - postgresStmt.setColumn(archiveFileBatch.creationTime); - postgresStmt.setColumn(archiveFileBatch.reconciliationTime); - - postgresStmt.executeCopyInsert(archiveFileBatch.nbRows); - - const char *const sql_insert = - "INSERT INTO ARCHIVE_FILE(" - "ARCHIVE_FILE_ID," - "DISK_INSTANCE_NAME," - "DISK_FILE_ID," - "DISK_FILE_UID," - "DISK_FILE_GID," - "SIZE_IN_BYTES," - "CHECKSUM_BLOB," - "CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - "CREATION_TIME," - "RECONCILIATION_TIME) " - "SELECT " - "A.ARCHIVE_FILE_ID," - "A.DISK_INSTANCE_NAME," - "A.DISK_FILE_ID," - "A.DISK_FILE_UID," - "A.DISK_FILE_GID," - "A.SIZE_IN_BYTES," - "A.CHECKSUM_BLOB," - "A.CHECKSUM_ADLER32," - "S.STORAGE_CLASS_ID," - "A.CREATION_TIME," - "A.RECONCILIATION_TIME " - "FROM TEMP_ARCHIVE_FILE_BATCH AS A, STORAGE_CLASS AS S " - "WHERE A.STORAGE_CLASS_NAME = S.STORAGE_CLASS_NAME " - "ORDER BY A.ARCHIVE_FILE_ID " - "ON CONFLICT (ARCHIVE_FILE_ID) DO NOTHING"; - - // Concerns for bulk insertion in archive_file: deadlock with concurrent - // inserts of previously not-existing entry for the same archive file, - // hence insert with ORDER BY to define an update order. - - auto stmt_insert = conn.createStmt(sql_insert); - stmt_insert.executeNonQuery(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::list<cta::catalogue::InsertFileRecycleLog> PostgresCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn& conn){ - std::list<cta::catalogue::InsertFileRecycleLog> fileRecycleLogsToInsert; - try { - //Get the TAPE_FILE entry to put on the file recycle log - { - const char *const sql = - "SELECT " - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," - "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " - "FROM " - "TAPE_FILE " - "JOIN " - "TEMP_TAPE_FILE_INSERTION_BATCH " - "ON " - "TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID AND TEMP_TAPE_FILE_INSERTION_BATCH.COPY_NB = TAPE_FILE.COPY_NB " - "WHERE " - "TAPE_FILE.VID != TEMP_TAPE_FILE_INSERTION_BATCH.VID OR TAPE_FILE.FSEQ != TEMP_TAPE_FILE_INSERTION_BATCH.FSEQ"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while(rset.next()){ - cta::catalogue::InsertFileRecycleLog fileRecycleLog; - fileRecycleLog.vid = rset.columnString("VID"); - fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); - fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); - fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); - fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); - fileRecycleLog.recycleLogTime = time(nullptr); - fileRecycleLogsToInsert.push_back(fileRecycleLog); - } - } - { - for(auto & fileRecycleLog: fileRecycleLogsToInsert){ - insertFileInFileRecycleLog(conn,fileRecycleLog); - } - return fileRecycleLogsToInsert; - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// selectArchiveFileSizeAndChecksum -//------------------------------------------------------------------------------ -std::map<uint64_t, PostgresCatalogue::FileSizeAndChecksum> PostgresCatalogue::selectArchiveFileSizesAndChecksums( - rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const { - try { - std::vector<uint64_t> archiveFileIdList(events.size()); - for (const auto &event: events) { - archiveFileIdList.push_back(event.archiveFileId); - } - - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32 " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN TEMP_TAPE_FILE_BATCH ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TEMP_TAPE_FILE_BATCH.ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - - auto rset = stmt.executeQuery(); - - std::map<uint64_t, FileSizeAndChecksum> fileSizesAndChecksums; - while (rset.next()) { - const uint64_t archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - - if (fileSizesAndChecksums.end() != fileSizesAndChecksums.find(archiveFileId)) { - exception::Exception ex; - ex.getMessage() << __FUNCTION__ << " failed: " - "Found duplicate archive file identifier in batch of files written to tape: archiveFileId=" << archiveFileId; - throw ex; - } - - FileSizeAndChecksum fileSizeAndChecksum; - fileSizeAndChecksum.fileSize = rset.columnUint64("SIZE_IN_BYTES"); - fileSizeAndChecksum.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - fileSizesAndChecksums[archiveFileId] = fileSizeAndChecksum; - } - - return fileSizesAndChecksums; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// insertArchiveFilesIntoTempTable -//------------------------------------------------------------------------------ -void PostgresCatalogue::insertTapeFileBatchIntoTempTable(rdbms::Conn &conn, - const std::set<TapeFileWritten> &events) const { - try { - TempTapeFileBatch tempTapeFileBatch(events.size()); - - // Store the value of each field - uint32_t i = 0; - for (const auto &event: events) { - tempTapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); - i++; - } - - const char *const sql = - "COPY TEMP_TAPE_FILE_BATCH(" - "ARCHIVE_FILE_ID) " - "FROM STDIN --" - ":ARCHIVE_FILE_ID"; - - auto stmt = conn.createStmt(sql); - rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); - - postgresStmt.setColumn(tempTapeFileBatch.archiveFileId); - postgresStmt.executeCopyInsert(tempTapeFileBatch.nbRows); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteArchiveFile -//------------------------------------------------------------------------------ -void PostgresCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, - log::LogContext &lc) { - try { - const char *selectSql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " - "FOR UPDATE OF ARCHIVE_FILE"; - utils::Timer t; - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - conn.executeNonQuery("BEGIN"); - - const auto getConnTime = t.secs(utils::Timer::resetCounter); - auto selectStmt = conn.createStmt(selectSql); - const auto createStmtTime = t.secs(); - selectStmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - t.reset(); - rdbms::Rset selectRset = selectStmt.executeQuery(); - const auto selectFromArchiveFileTime = t.secs(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - std::set<std::string> vidsToSetDirty; - while(selectRset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = selectRset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = selectRset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = selectRset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = selectRset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = selectRset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = selectRset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(selectRset.columnBlob("CHECKSUM_BLOB"), selectRset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = selectRset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = selectRset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = selectRset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file - if(!selectRset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = selectRset.columnString("VID"); - vidsToSetDirty.insert(tapeFile.vid); - tapeFile.fSeq = selectRset.columnUint64("FSEQ"); - tapeFile.blockId = selectRset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = selectRset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = selectRset.columnUint64("COPY_NB"); - tapeFile.creationTime = selectRset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - if(nullptr == archiveFile.get()) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", archiveFileId); - lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); - return; - } - - if(diskInstanceName != archiveFile->diskInstance) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("requestDiskInstance", diskInstanceName) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("createStmtTime", createStmtTime) - .add("selectFromArchiveFileTime", selectFromArchiveFileTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << it->copyNb - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << it->copyNb; - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " - "of the archived file"); - - exception::UserError ue; - ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " - "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << - archiveFile->diskInstance; - throw ue; - } - - t.reset(); - { - const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - - const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); - - for(auto &vidToSetDirty: vidsToSetDirty){ - //We deleted the TAPE_FILE so the tapes containing them should be set as dirty - setTapeDirty(conn,vidToSetDirty); - } - - const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); - - { - const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); - - conn.commit(); - autoRollback.cancel(); - const auto commitTime = t.secs(); - - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("createStmtTime", createStmtTime) - .add("selectFromArchiveFileTime", selectFromArchiveFileTime) - .add("deleteFromTapeFileTime", deleteFromTapeFileTime) - .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) - .add("setTapeDirtyTime",setTapeDirtyTime) - .add("commitTime", commitTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << it->copyNb - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::INFO, "Archive file deleted from CTA catalogue"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// beginCreateTemporarySetDeferred -//------------------------------------------------------------------------------ -void PostgresCatalogue::beginCreateTemporarySetDeferred(rdbms::Conn &conn) const { - conn.executeNonQuery("BEGIN"); - conn.executeNonQuery("CREATE TEMPORARY TABLE TEMP_ARCHIVE_FILE_BATCH (LIKE ARCHIVE_FILE) ON COMMIT DROP"); - conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ADD COLUMN STORAGE_CLASS_NAME VARCHAR(100)"); - conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ALTER COLUMN STORAGE_CLASS_ID DROP NOT NULL"); - conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ALTER COLUMN IS_DELETED DROP NOT NULL"); - conn.executeNonQuery("CREATE INDEX TEMP_A_F_B_ARCHIVE_FILE_ID_I ON TEMP_ARCHIVE_FILE_BATCH(ARCHIVE_FILE_ID)"); - conn.executeNonQuery("CREATE INDEX TEMP_A_F_B_DIN_SCN_I ON TEMP_ARCHIVE_FILE_BATCH(DISK_INSTANCE_NAME, STORAGE_CLASS_NAME)"); - conn.executeNonQuery("CREATE TEMPORARY TABLE TEMP_TAPE_FILE_BATCH(ARCHIVE_FILE_ID NUMERIC(20,0)) ON COMMIT DROP"); - conn.executeNonQuery("CREATE INDEX TEMP_T_F_B_ARCHIVE_FILE_ID_I ON TEMP_TAPE_FILE_BATCH(ARCHIVE_FILE_ID)"); - conn.executeNonQuery("SET CONSTRAINTS ARCHIVE_FILE_DIN_DFI_UN DEFERRED"); -} - -//------------------------------------------------------------------------------ -// copyArchiveFileToRecycleBinAndDelete -//------------------------------------------------------------------------------ -void PostgresCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO and a DELETE FROM - //in a single transaction - conn.executeNonQuery("BEGIN"); - copyArchiveFileToFileRecycleLog(conn,request); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn,request.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,request); - tl.insertAndReset("deleteTapeFilesTime",t); - RdbmsCatalogue::deleteArchiveFile(conn,request); - tl.insertAndReset("deleteArchiveFileTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",request.archiveFileID); - spc.add("diskFileId",request.diskFileId); - spc.add("diskFilePath",request.diskFilePath); - spc.add("diskInstance",request.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In PostgresCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFilesAndArchiveFileFromRecycleBin -//------------------------------------------------------------------------------ -void PostgresCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId, log::LogContext& lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do two delete in one transaction - conn.executeNonQuery("BEGIN"); - deleteTapeFilesFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteTapeFilesTime",t); - deleteArchiveFileFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteArchiveFileTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",archiveFileId); - tl.addToLog(spc); - lc.log(log::INFO,"In PostgresCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin: tape files and archiveFiles deleted from the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyTapeFileToFileRecyleLogAndDelete -//------------------------------------------------------------------------------ -void PostgresCatalogue::copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, - const std::string &reason, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO and a DELETE FROM - //in a single transaction - conn.executeNonQuery("BEGIN"); - copyTapeFilesToFileRecycleLog(conn, file, reason); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn, file.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,file); - tl.insertAndReset("deleteTapeFilesTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId", file.archiveFileID); - spc.add("diskFileId", file.diskFileId); - spc.add("diskFilePath", file.diskFileInfo.path); - spc.add("diskInstance", file.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In PostgresCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreEntryInRecycleLog -//------------------------------------------------------------------------------ -void PostgresCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, - const std::string &newFid, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - - if (!fileRecycleLogItor.hasMore()) { - throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); - } - auto fileRecycleLog = fileRecycleLogItor.next(); - if (fileRecycleLogItor.hasMore()) { - //stop restoring more than one file at once - throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); - } - - //We currently do all file copies restoring in a single transaction - conn.executeNonQuery("BEGIN"); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFilePtr = getArchiveFileById(conn, fileRecycleLog.archiveFileId); - if (!archiveFilePtr) { - restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); - } else { - if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { - //copy with same copy_nb exists, cannot restore - UserSpecifiedExistingDeletedFileCopy ex; - ex.getMessage() << "Cannot restore file copy with archiveFileId " << std::to_string(fileRecycleLog.archiveFileId) - << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) << " because a tapefile with same archiveFileId and copy_nb already exists"; - throw ex; - } - } - - restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); - conn.commit(); - - log::ScopedParamContainer spc(lc); - tl.insertAndReset("commitTime",t); - tl.addToLog(spc); - lc.log(log::INFO,"In PostgresCatalogue::restoreEntryInRecycleLog: all file copies successfully restored."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreFileCopyInRecycleLog -//------------------------------------------------------------------------------ -void PostgresCatalogue::restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - cta::common::dataStructures::TapeFile tapeFile; - tapeFile.vid = fileRecycleLog.vid; - tapeFile.fSeq = fileRecycleLog.fSeq; - tapeFile.copyNb = fileRecycleLog.copyNb; - tapeFile.blockId = fileRecycleLog.blockId; - tapeFile.fileSize = fileRecycleLog.sizeInBytes; - tapeFile.creationTime = fileRecycleLog.tapeFileCreationTime; - - insertTapeFile(conn, tapeFile, fileRecycleLog.archiveFileId); - tl.insertAndReset("insertTapeFileTime",t); - - deleteTapeFileCopyFromRecycleBin(conn, fileRecycleLog); - tl.insertAndReset("deleteTapeFileCopyFromRecycleBinTime",t); - - log::ScopedParamContainer spc(lc); - spc.add("vid", tapeFile.vid); - spc.add("archiveFileId", fileRecycleLog.archiveFileId); - spc.add("fSeq", tapeFile.fSeq); - spc.add("copyNb", tapeFile.copyNb); - spc.add("fileSize", tapeFile.fileSize); - tl.addToLog(spc); - lc.log(log::INFO,"In PostgresCatalogue::restoreFileCopyInRecycleLog: File restored from the recycle log."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/PostgresCatalogue.hpp b/catalogue/PostgresCatalogue.hpp deleted file mode 100644 index a3932aebfe..0000000000 --- a/catalogue/PostgresCatalogue.hpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include "catalogue/RdbmsCatalogue.hpp" -#include "rdbms/Conn.hpp" -#include "InsertFileRecycleLog.hpp" - -namespace cta { -namespace catalogue { - -/** - * An Postgres based implementation of the CTA catalogue. - */ -class PostgresCatalogue: public RdbmsCatalogue { -public: - - /** - * Constructor. - * - * @param log Object representing the API to the CTA logging system. - * @param username The database username. - * @param password The database password. - * @param database The database name. - * @param nbConns The maximum number of concurrent connections to the - * underlying relational database for all operations accept listing archive - * files which can be relatively long operations. - * @param nbArchiveFileListingConns The maximum number of concurrent - * connections to the underlying relational database for the sole purpose of - * listing archive files. - */ - PostgresCatalogue( - log::Logger &log, - const rdbms::Login &login, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns); - - /** - * Destructor. - */ - ~PostgresCatalogue() override; - - /** - * !!!!!!!!!!!!!!!!!!! THIS METHOD SHOULD NOT BE USED !!!!!!!!!!!!!!!!!!!!!!! - * Deletes the specified archive file and its associated tape copies from the - * catalogue. - * - * Please note that the name of the disk instance is specified in order to - * prevent a disk instance deleting an archive file that belongs to another - * disk instance. - * - * Please note that this method is idempotent. If the file to be deleted does - * not exist in the CTA catalogue then this method returns without error. - * - * @param instanceName The name of the instance from where the deletion request - * originated - * @param archiveFileId The unique identifier of the archive file. - * @param lc The log context. - * @return The metadata of the deleted archive file including the metadata of - * the associated and also deleted tape copies. - */ - void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &instanceName, const uint64_t archiveFileId, - log::LogContext &lc) override; - - /** - * Notifies the catalogue that the specified files have been written to tape. - * - * @param events The tape file written events. - */ - void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) override; - - /** - * Creates a temporary table from the list of disk file IDs provided in the search criteria. - * - * @param conn The database connection. - * @param diskFileIds List of disk file IDs (fxid). - * @return Name of the temporary table - */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const override; - - /** - * Returns a unique archive ID that can be used by a new archive file 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 archive ID that can be used by a new archive file within - * the catalogue. - */ - uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; - - /** - * Returns a unique logical library ID that can be used by a new logical - * library 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 logical library ID that can be used by a new logical - * library storage class within the catalogue. - */ - uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) override; - - /** - * Returns a unique virtual organization ID that can be used by a new Virtual Organization - * 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 virtual organization ID that can be used by a new Virtual Organization - * within the catalogue. - */ - uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; - - /** - * Returns a unique media type ID that can be used by a new media type 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 media type ID that can be used by a new media type - * within the catalogue. - */ - uint64_t getNextMediaTypeId(rdbms::Conn &conn) override; - - /** - * Returns a unique storage class ID that can be used by a new storage class - * 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 storage class ID that can be used by a new storage class - * within the catalogue. - */ - 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; - - /** - * Returns a unique file recycle log ID that can be used by a new entry of file recycle log 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 file recycle log ID that can be used by a new entry of file recycle log within - * the catalogue. - */ - uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) override; - -private: - - /** - * Start a database transaction and then create the temporary - * tables TEMP_ARCHIVE_FILE_BATCH and TEMP_TAPE_FILE_BATCH. - * Sets deferred mode for one of the db constraints to avoid - * violations during concurrent bulk insert. - * - * @parm conn The database connection. - */ - void beginCreateTemporarySetDeferred(rdbms::Conn &conn) const; - - /** - * 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. - */ - uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const; - - /** - * Batch inserts rows into the ARCHIVE_FILE table that correspond to the - * specified TapeFileWritten events. - * - * This method has idempotent behaviour in the case where an ARCHIVE_FILE - * already exists. Such a situation will occur when a file has more than one - * copy on tape. The first tape copy will cause two successful inserts, one - * into the ARCHIVE_FILE table and one into the TAPE_FILE table. The second - * tape copy will try to do the same, but the insert into the ARCHIVE_FILE - * table will fail or simply bounce as the row will already exists. The - * insert into the TABLE_FILE table will succeed because the two TAPE_FILE - * rows will be unique. - * - * @param conn The database connection. - * @param events The tape file written events. - */ - void idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const; - - /** - * In the case we insert a TAPE_FILE that already has a copy on the catalogue (same copyNb), - * this TAPE_FILE will go to the FILE_RECYCLE_LOG table. - * - * This case happens always during the repacking of a tape: the new TAPE_FILE created - * will replace the old one, the old one will then be moved to the FILE_RECYCLE_LOG table - * - * @param conn The database connection. - * @returns the list of inserted fileRecycleLog - */ - std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn); - - /** - * The size and checksum of a file. - */ - struct FileSizeAndChecksum { - uint64_t fileSize; - checksum::ChecksumBlob checksumBlob; - }; - - /** - * Returns the sizes and checksums of the specified archive files. - * - * @param conn The database connection. - * @param events The tape file written events that identify the archive files. - * @return A map from the identifier of each archive file to its size and checksum. - */ - std::map<uint64_t, FileSizeAndChecksum> selectArchiveFileSizesAndChecksums(rdbms::Conn &conn, - const std::set<TapeFileWritten> &events) const; - - /** - * Batch inserts rows into the TAPE_FILE_BATCH temporary table that correspond - * to the specified TapeFileWritten events. - * - * @param conn The database connection. - * @param events The tape file written events. - */ - void insertTapeFileBatchIntoTempTable(rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const; - - /** - * Copy the archiveFile and the associated tape files from the ARCHIVE_FILE and TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the ARCHIVE_FILE and TAPE_FILE entries. - * @param conn the database connection - * @param request the request that contains the necessary informations to identify the archiveFile to copy to the FILE_RECYCLE_LOG table - * @param lc the log context - */ - void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; - - /** - * Delete the TapeFiles and the ArchiveFile from the recycle-bin in one transaction - * @param conn the database connection - * @param archiveFileId the archiveFileId of the file to delete from the recycle-bin - */ - virtual void deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn & conn, const uint64_t archiveFileId, log::LogContext & lc); - - /** - * Copy the tape files from the TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the TAPE_FILE entry. - * @param conn the database connection - * @param file the file to be deleted - * @param reason The reason for deleting the tape file copy - * @param lc the log context - */ - void copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, - const std::string &reason, log::LogContext & lc) override; - - /** - * Copy the files in fileRecycleLogItor to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entries - * @param conn the database connection - * @param fileRecycleLogItor the collection of fileRecycleLogs we want to restore - * @param lc the log context - */ - void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) override; - - /** - * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry - * @param conn the database connection - * @param fileRecycleLog the fileRecycleLog we want to restore - * @param lc the log context - */ - void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLogItor, log::LogContext & lc); - -}; // class PostgresCatalogue - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/PostgresqlCatalogueFactory.cpp b/catalogue/PostgresqlCatalogueFactory.cpp index f5443a38b4..3b8cb9253b 100644 --- a/catalogue/PostgresqlCatalogueFactory.cpp +++ b/catalogue/PostgresqlCatalogueFactory.cpp @@ -15,10 +15,12 @@ * submit itself to any jurisdiction. */ -#include "catalogue/CatalogueRetryWrapper.hpp" #include "catalogue/PostgresqlCatalogueFactory.hpp" -#include "catalogue/PostgresCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresCatalogue.hpp" +#include "catalogue/retrywrappers/CatalogueRetryWrapper.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" #include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" namespace cta { namespace catalogue { @@ -40,7 +42,7 @@ PostgresqlCatalogueFactory::PostgresqlCatalogueFactory( if(rdbms::Login::DBTYPE_POSTGRESQL != login.dbType) { exception::Exception ex; ex.getMessage() << __FUNCTION__ << "failed: Incorrect database type: expected=DBTYPE_POSTGRESQL actual=" << - login.dbTypeToString(login.dbType); + rdbms::Login::dbTypeToString(login.dbType); throw ex; } } diff --git a/catalogue/PostgresqlCatalogueFactory.hpp b/catalogue/PostgresqlCatalogueFactory.hpp index 6669f423ff..1314d68512 100644 --- a/catalogue/PostgresqlCatalogueFactory.hpp +++ b/catalogue/PostgresqlCatalogueFactory.hpp @@ -21,6 +21,15 @@ #include "rdbms/Login.hpp" namespace cta { + +namespace log { +class Logger; +} + +namespace rdbms { +class Login; +} + namespace catalogue { /** diff --git a/catalogue/RdbmsCatalogue.cpp b/catalogue/RdbmsCatalogue.cpp deleted file mode 100644 index 64b895c93a..0000000000 --- a/catalogue/RdbmsCatalogue.cpp +++ /dev/null @@ -1,12101 +0,0 @@ - /* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include <algorithm> -#include <climits> -#include <ctype.h> -#include <list> -#include <memory> -#include <string> -#include <time.h> -#include <tuple> -#include <utility> - -#include "catalogue/ArchiveFileRow.hpp" -#include "catalogue/ArchiveFileRowWithoutTimestamps.hpp" -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/CreateMountPolicyAttributes.hpp" -#include "catalogue/CreateTapeAttributes.hpp" -#include "catalogue/MediaType.hpp" -#include "catalogue/MediaTypeWithLogs.hpp" -#include "catalogue/RdbmsCatalogue.hpp" -#include "catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp" -#include "catalogue/RdbmsCatalogueGetArchiveFilesItor.hpp" -#include "catalogue/RdbmsCatalogueTapeContentsItor.hpp" -#include "catalogue/RecyleTapeFileSearchCriteria.hpp" -#include "catalogue/SchemaVersion.hpp" -#include "catalogue/SqliteCatalogueSchema.hpp" -#include "catalogue/TapeForWriting.hpp" -#include "catalogue/TapePool.hpp" -#include "common/dataStructures/AdminUser.hpp" -#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" -#include "common/dataStructures/ArchiveFileSummary.hpp" -#include "common/dataStructures/ArchiveRoute.hpp" -#include "common/dataStructures/DeleteArchiveRequest.hpp" -#include "common/dataStructures/DesiredDriveState.hpp" -#include "common/dataStructures/DiskInstance.hpp" -#include "common/dataStructures/EntryLog.hpp" -#include "common/dataStructures/FileRecycleLog.hpp" -#include "common/dataStructures/LabelFormat.hpp" -#include "common/dataStructures/LogicalLibrary.hpp" -#include "common/dataStructures/RequesterActivityMountRule.hpp" -#include "common/dataStructures/RequesterGroupMountRule.hpp" -#include "common/dataStructures/RequesterMountRule.hpp" -#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" -#include "common/dataStructures/SecurityIdentity.hpp" -#include "common/dataStructures/StorageClass.hpp" -#include "common/dataStructures/TapeDrive.hpp" -#include "common/dataStructures/TapeDriveStatistics.hpp" -#include "common/dataStructures/TapeFile.hpp" -#include "common/exception/Exception.hpp" -#include "common/exception/LostDatabaseConnection.hpp" -#include "common/exception/UserError.hpp" -#include "common/exception/UserErrorWithCacheInfo.hpp" -#include "common/log/TimingList.hpp" -#include "common/threading/MutexLocker.hpp" -#include "common/Timer.hpp" -#include "common/utils/Regex.hpp" -#include "common/utils/utils.hpp" -#include "disk/DiskSystem.hpp" -#include "rdbms/AutoRollback.hpp" -#include "RdbmsCatalogueGetFileRecycleLogItor.hpp" -#include "version.h" - -namespace cta { -namespace catalogue { - -//------------------------------------------------------------------------------ -// constructor -//------------------------------------------------------------------------------ -RdbmsCatalogue::RdbmsCatalogue( - log::Logger &log, - const rdbms::Login &login, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns): - m_log(log), - m_connPool(login, nbConns), - m_archiveFileListingConnPool(login, nbArchiveFileListingConns), - m_tapeCopyToPoolCache(10), - m_groupMountPolicyCache(10), - m_userMountPolicyCache(10), - m_allMountPoliciesCache(60), - m_tapepoolVirtualOrganizationCache(60), - m_expectedNbArchiveRoutesCache(10), - m_isAdminCache(10) {} - -//------------------------------------------------------------------------------ -// destructor -//------------------------------------------------------------------------------ -RdbmsCatalogue::~RdbmsCatalogue() { -} - -//------------------------------------------------------------------------------ -// createAdminUser -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createAdminUser( - const common::dataStructures::SecurityIdentity &admin, - const std::string &username, - const std::string &comment) { - try { - if (username.empty()) { - throw UserSpecifiedAnEmptyStringUsername("Cannot create admin user because the username is an empty string"); - } - - if (comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create admin user because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - auto conn = m_connPool.getConn(); - if (adminUserExists(conn, username)) { - throw exception::UserError(std::string("Cannot create admin user " + username + - " because an admin user with the same name already exists")); - } - const uint64_t now = time(nullptr); - const char *const sql = - "INSERT INTO ADMIN_USER(" - "ADMIN_USER_NAME," - - "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(" - ":ADMIN_USER_NAME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":ADMIN_USER_NAME", username); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// adminUserExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const { - try { - const char *const sql = - "SELECT " - "ADMIN_USER_NAME AS ADMIN_USER_NAME " - "FROM " - "ADMIN_USER " - "WHERE " - "ADMIN_USER_NAME = :ADMIN_USER_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":ADMIN_USER_NAME", adminUsername); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// virtualOrganizationExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::virtualOrganizationExists(rdbms::Conn &conn, const std::string &voName) const { - try { - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " - "FROM " - "VIRTUAL_ORGANIZATION " - "WHERE " - "UPPER(VIRTUAL_ORGANIZATION_NAME) = UPPER(:VIRTUAL_ORGANIZATION_NAME)"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteAdminUser -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteAdminUser(const std::string &username) { - try { - const char *const sql = "DELETE FROM ADMIN_USER WHERE ADMIN_USER_NAME = :ADMIN_USER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":ADMIN_USER_NAME", username); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete admin-user ") + username + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getAdminUsers -//------------------------------------------------------------------------------ -std::list<common::dataStructures::AdminUser> RdbmsCatalogue::getAdminUsers() const { - try { - std::list<common::dataStructures::AdminUser> admins; - const char *const sql = - "SELECT " - "ADMIN_USER_NAME AS ADMIN_USER_NAME," - - "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 " - "FROM " - "ADMIN_USER " - "ORDER BY " - "ADMIN_USER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::AdminUser admin; - - admin.name = rset.columnString("ADMIN_USER_NAME"); - admin.comment = rset.columnString("USER_COMMENT"); - admin.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - admin.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - admin.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - admin.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - admin.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - admin.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - admins.push_back(admin); - } - - return admins; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyAdminUserComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &username, const std::string &comment) { - try { - if (username.empty()) { - throw UserSpecifiedAnEmptyStringUsername("Cannot modify admin user because the username is an empty string"); - } - - if (comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot modify admin user because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE ADMIN_USER SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "ADMIN_USER_NAME = :ADMIN_USER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":ADMIN_USER_NAME", username); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify admin user ") + username + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createVirtualOrganization -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo){ - try { - if (vo.name.empty()){ - throw UserSpecifiedAnEmptyStringVo("Cannot create virtual organization because the name is an empty string"); - } - if (vo.comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create virtual organization because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(vo.comment); - if (vo.diskInstanceName.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create virtual organization because the disk instance is an empty string"); - } - - auto conn = m_connPool.getConn(); - if (virtualOrganizationExists(conn, vo.name)) { - throw exception::UserError(std::string("Cannot create vo : ") + - vo.name + " because it already exists"); - } - const uint64_t virtualOrganizationId = getNextVirtualOrganizationId(conn); - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO VIRTUAL_ORGANIZATION(" - "VIRTUAL_ORGANIZATION_ID," - "VIRTUAL_ORGANIZATION_NAME," - - "READ_MAX_DRIVES," - "WRITE_MAX_DRIVES," - "MAX_FILE_SIZE," - - "DISK_INSTANCE_NAME," - - "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(" - ":VIRTUAL_ORGANIZATION_ID," - ":VIRTUAL_ORGANIZATION_NAME," - ":READ_MAX_DRIVES," - ":WRITE_MAX_DRIVES," - ":MAX_FILE_SIZE," - - ":DISK_INSTANCE_NAME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindUint64(":VIRTUAL_ORGANIZATION_ID", virtualOrganizationId); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", vo.name); - - stmt.bindUint64(":READ_MAX_DRIVES",vo.readMaxDrives); - stmt.bindUint64(":WRITE_MAX_DRIVES",vo.writeMaxDrives); - stmt.bindUint64(":MAX_FILE_SIZE", vo.maxFileSize); - - stmt.bindString(":DISK_INSTANCE_NAME", vo.diskInstanceName); - - stmt.bindString(":USER_COMMENT", vo.comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteVirtualOrganization -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteVirtualOrganization(const std::string &voName){ - try { - auto conn = m_connPool.getConn(); - - if(virtualOrganizationIsUsedByStorageClasses(conn, voName)) { - throw UserSpecifiedStorageClassUsedByArchiveRoutes(std::string("The Virtual Organization ") + voName + - " is being used by one or more storage classes"); - } - - if(virtualOrganizationIsUsedByTapepools(conn, voName)) { - throw UserSpecifiedStorageClassUsedByArchiveFiles(std::string("The Virtual Organization ") + voName + - " is being used by one or more Tapepools"); - } - - const char *const sql = - "DELETE FROM " - "VIRTUAL_ORGANIZATION " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - - stmt.executeNonQuery(); - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete Virtual Organization : ") + - voName + " because it does not exist"); - } - m_tapepoolVirtualOrganizationCache.invalidate(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getVirtualOrganizations -//------------------------------------------------------------------------------ -std::list<common::dataStructures::VirtualOrganization> RdbmsCatalogue::getVirtualOrganizations() const { - try { - std::list<common::dataStructures::VirtualOrganization> virtualOrganizations; - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," - - "READ_MAX_DRIVES AS READ_MAX_DRIVES," - "WRITE_MAX_DRIVES AS WRITE_MAX_DRIVES," - "MAX_FILE_SIZE AS MAX_FILE_SIZE," - - "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," - - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - - "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 " - "FROM " - "VIRTUAL_ORGANIZATION " - "ORDER BY " - "VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::VirtualOrganization virtualOrganization; - - virtualOrganization.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); - - virtualOrganization.readMaxDrives = rset.columnUint64("READ_MAX_DRIVES"); - virtualOrganization.writeMaxDrives = rset.columnUint64("WRITE_MAX_DRIVES"); - virtualOrganization.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); - virtualOrganization.comment = rset.columnString("USER_COMMENT"); - virtualOrganization.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - virtualOrganization.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - virtualOrganization.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - virtualOrganization.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - virtualOrganization.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - virtualOrganization.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - virtualOrganization.diskInstanceName = rset.columnString("DISK_INSTANCE_NAME"); - - virtualOrganizations.push_back(virtualOrganization); - } - - return virtualOrganizations; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getVirtualOrganizationOfTapepool -//------------------------------------------------------------------------------ -common::dataStructures::VirtualOrganization RdbmsCatalogue::getVirtualOrganizationOfTapepool(const std::string & tapepoolName) const { - try { - auto conn = m_connPool.getConn(); - return getVirtualOrganizationOfTapepool(conn,tapepoolName); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getVirtualOrganizationOfTapepool -//------------------------------------------------------------------------------ -common::dataStructures::VirtualOrganization RdbmsCatalogue::getVirtualOrganizationOfTapepool(rdbms::Conn & conn, const std::string & tapepoolName) const { - try { - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," - - "VIRTUAL_ORGANIZATION.READ_MAX_DRIVES AS READ_MAX_DRIVES," - "VIRTUAL_ORGANIZATION.WRITE_MAX_DRIVES AS WRITE_MAX_DRIVES," - "VIRTUAL_ORGANIZATION.MAX_FILE_SIZE AS MAX_FILE_SIZE," - - "VIRTUAL_ORGANIZATION.USER_COMMENT AS USER_COMMENT," - - "VIRTUAL_ORGANIZATION.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "VIRTUAL_ORGANIZATION.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "VIRTUAL_ORGANIZATION.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "VIRTUAL_ORGANIZATION.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - - "VIRTUAL_ORGANIZATION.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "VIRTUAL_ORGANIZATION.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "VIRTUAL_ORGANIZATION.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE_POOL " - "INNER JOIN " - "VIRTUAL_ORGANIZATION " - "ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME",tapepoolName); - auto rset = stmt.executeQuery(); - if(!rset.next()){ - throw exception::UserError(std::string("In RdbmsCatalogue::getVirtualOrganizationsOfTapepool() unable to find the Virtual Organization of the tapepool ") + tapepoolName + "."); - } - common::dataStructures::VirtualOrganization virtualOrganization; - - virtualOrganization.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); - virtualOrganization.readMaxDrives = rset.columnUint64("READ_MAX_DRIVES"); - virtualOrganization.writeMaxDrives = rset.columnUint64("WRITE_MAX_DRIVES"); - virtualOrganization.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); - virtualOrganization.comment = rset.columnString("USER_COMMENT"); - virtualOrganization.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - virtualOrganization.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - virtualOrganization.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - virtualOrganization.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - virtualOrganization.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - virtualOrganization.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - virtualOrganization.diskInstanceName = rset.columnString("DISK_INSTANCE_NAME"); - return virtualOrganization; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getCachedVirtualOrganizationOfTapepool -//------------------------------------------------------------------------------ -common::dataStructures::VirtualOrganization RdbmsCatalogue::getCachedVirtualOrganizationOfTapepool(const std::string & tapepoolName) const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getVirtualOrganizationOfTapepool(conn,tapepoolName); - }; - return m_tapepoolVirtualOrganizationCache.getCachedValue(tapepoolName,getNonCachedValue).value; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// modifyVirtualOrganizationName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyVirtualOrganizationName(const common::dataStructures::SecurityIdentity& admin, const std::string& currentVoName, const std::string& newVoName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "VIRTUAL_ORGANIZATION_NAME = :NEW_VIRTUAL_ORGANIZATION_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :CUR_VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - if(newVoName != currentVoName){ - if(virtualOrganizationExists(conn,newVoName)){ - throw exception::UserError(std::string("Cannot modify the virtual organization name ") + currentVoName +". The new name : " + newVoName+" already exists in the database."); - } - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":NEW_VIRTUAL_ORGANIZATION_NAME", newVoName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":CUR_VIRTUAL_ORGANIZATION_NAME", currentVoName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + currentVoName + - " because it does not exist"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives){ - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "READ_MAX_DRIVES = :READ_MAX_DRIVES," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":READ_MAX_DRIVES", readMaxDrives); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + - " because it does not exist"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives){ - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "WRITE_MAX_DRIVES = :WRITE_MAX_DRIVES," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":WRITE_MAX_DRIVES", writeMaxDrives); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + - " because it does not exist"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize){ - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "MAX_FILE_SIZE = :MAX_FILE_SIZE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":MAX_FILE_SIZE", maxFileSize); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + - " because it does not exist"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity& admin, const std::string& voName, const std::string& comment) { -try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyVirtualOrganizationDiskInstanceName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity& admin, const std::string& voName, const std::string& diskInstance) { -try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE VIRTUAL_ORGANIZATION SET " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// createStorageClass -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createStorageClass( - const common::dataStructures::SecurityIdentity &admin, - const common::dataStructures::StorageClass &storageClass) { - try { - - if(storageClass.name.empty()) { - throw UserSpecifiedAnEmptyStringStorageClassName("Cannot create storage class because the storage class name is" - " an empty string"); - } - - if (storageClass.comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create storage class because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(storageClass.comment); - std::string vo = storageClass.vo.name; - - if(vo.empty()) { - throw UserSpecifiedAnEmptyStringVo("Cannot create storage class because the vo is an empty string"); - } - - auto conn = m_connPool.getConn(); - if(storageClassExists(conn, storageClass.name)) { - throw exception::UserError(std::string("Cannot create storage class : ") + - storageClass.name + " because it already exists"); - } - if(!virtualOrganizationExists(conn,vo)){ - throw exception::UserError(std::string("Cannot create storage class : ") + - storageClass.name + " because the vo : " + vo + " does not exist"); - } - const uint64_t storageClassId = getNextStorageClassId(conn); - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO STORAGE_CLASS(" - "STORAGE_CLASS_ID," - "STORAGE_CLASS_NAME," - "NB_COPIES," - "VIRTUAL_ORGANIZATION_ID," - - "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(" - ":STORAGE_CLASS_ID," - ":STORAGE_CLASS_NAME," - ":NB_COPIES," - "(SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME = :VO)," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindUint64(":STORAGE_CLASS_ID", storageClassId); - stmt.bindString(":STORAGE_CLASS_NAME", storageClass.name); - stmt.bindUint64(":NB_COPIES", storageClass.nbCopies); - stmt.bindString(":VO",vo); - - stmt.bindString(":USER_COMMENT", storageClass.comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// storageClassExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::storageClassExists(rdbms::Conn &conn, - const std::string &storageClassName) const { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteStorageClass -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteStorageClass(const std::string &storageClassName) { - try { - auto conn = m_connPool.getConn(); - - if(storageClassIsUsedByArchiveRoutes(conn, storageClassName)) { - throw UserSpecifiedStorageClassUsedByArchiveRoutes(std::string("The ") + storageClassName + - " storage class is being used by one or more archive routes"); - } - - if(storageClassIsUsedByArchiveFiles(conn, storageClassName)) { - throw UserSpecifiedStorageClassUsedByArchiveFiles(std::string("The ") + storageClassName + - " storage class is being used by one or more archive files"); - } - - if(storageClassIsUsedByFileRecyleLogs(conn,storageClassName)){ - throw UserSpecifiedStorageClassUsedByFileRecycleLogs(std::string("The ") + storageClassName + - " storage class is being used by one or more file in the recycle logs"); - } - - const char *const sql = - "DELETE FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - - stmt.executeNonQuery(); - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete storage-class : ") + - storageClassName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// MediaTypeIsUsedByTapes -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::mediaTypeIsUsedByTapes(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT" "\n" - "MEDIA_TYPE.MEDIA_TYPE_NAME" "\n" - "FROM" "\n" - "TAPE" "\n" - "INNER JOIN" "\n" - "MEDIA_TYPE" "\n" - "ON" "\n" - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID" "\n" - "WHERE" "\n" - "MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":MEDIA_TYPE_NAME", name); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// storageClassIsUsedByArchiveRoutes -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::storageClassIsUsedByArchiveRoutes(rdbms::Conn &conn, const std::string &storageClassName) const { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " - "FROM " - "ARCHIVE_ROUTE " - "INNER JOIN " - "STORAGE_CLASS " - "ON " - "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// storageClassIsUsedByARchiveFiles -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::storageClassIsUsedByArchiveFiles(rdbms::Conn &conn, const std::string &storageClassName) const { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN " - "STORAGE_CLASS " - "ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// storageClassIsUsedByFileRecyleLogs -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::storageClassIsUsedByFileRecyleLogs(rdbms::Conn &conn, const std::string &storageClassName) const { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " - "FROM " - "FILE_RECYCLE_LOG " - "INNER JOIN " - "STORAGE_CLASS " - "ON " - "FILE_RECYCLE_LOG.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// virtualOrganizationIsUsedByStorageClasses -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::virtualOrganizationIsUsedByStorageClasses(rdbms::Conn &conn, const std::string &voName) const { - try { - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " - "FROM " - "VIRTUAL_ORGANIZATION " - "INNER JOIN " - "STORAGE_CLASS " - "ON " - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID = STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// virtualOrganizationIsUsedByTapepools -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::virtualOrganizationIsUsedByTapepools(rdbms::Conn &conn, const std::string &voName) const { - try { - const char *const sql = - "SELECT " - "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " - "FROM " - "VIRTUAL_ORGANIZATION " - "INNER JOIN " - "TAPE_POOL " - "ON " - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID = TAPE_POOL.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getStorageClasses -//------------------------------------------------------------------------------ -std::list<common::dataStructures::StorageClass> RdbmsCatalogue::getStorageClasses() const { - try { - std::list<common::dataStructures::StorageClass> storageClasses; - const char *const sql = - "SELECT " - "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "NB_COPIES AS NB_COPIES," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," - - "STORAGE_CLASS.USER_COMMENT AS USER_COMMENT," - - "STORAGE_CLASS.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "STORAGE_CLASS.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "STORAGE_CLASS.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "STORAGE_CLASS.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "STORAGE_CLASS.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "STORAGE_CLASS.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "STORAGE_CLASS " - "INNER JOIN " - "VIRTUAL_ORGANIZATION ON STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "ORDER BY " - "STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::StorageClass storageClass; - - storageClass.name = rset.columnString("STORAGE_CLASS_NAME"); - storageClass.nbCopies = rset.columnUint64("NB_COPIES"); - storageClass.vo.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); - storageClass.comment = rset.columnString("USER_COMMENT"); - storageClass.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - storageClass.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - storageClass.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - storageClass.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - storageClass.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - storageClass.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - storageClasses.push_back(storageClass); - } - - return storageClasses; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getStorageClasses -//------------------------------------------------------------------------------ -common::dataStructures::StorageClass RdbmsCatalogue::getStorageClass(const std::string &name) const { - try { - const char *const sql = - "SELECT " - "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "NB_COPIES AS NB_COPIES," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," - "VIRTUAL_ORGANIZATION.MAX_FILE_SIZE AS MAX_FILE_SIZE," - "STORAGE_CLASS.USER_COMMENT AS USER_COMMENT," - - "STORAGE_CLASS.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "STORAGE_CLASS.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "STORAGE_CLASS.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "STORAGE_CLASS.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "STORAGE_CLASS.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "STORAGE_CLASS.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "STORAGE_CLASS " - "INNER JOIN " - "VIRTUAL_ORGANIZATION ON STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", name); - auto rset = stmt.executeQuery(); - if (rset.isEmpty()) { - throw exception::UserError(std::string("Cannot get storage class : ") + name + - " because it does not exist"); - } - rset.next(); - common::dataStructures::StorageClass storageClass; - - storageClass.name = rset.columnString("STORAGE_CLASS_NAME"); - storageClass.nbCopies = rset.columnUint64("NB_COPIES"); - storageClass.vo.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); - storageClass.vo.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); - storageClass.comment = rset.columnString("USER_COMMENT"); - storageClass.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - storageClass.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - storageClass.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - storageClass.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - storageClass.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - storageClass.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - return storageClass; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// modifyStorageClassNbCopies -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t nbCopies) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE STORAGE_CLASS SET " - "NB_COPIES = :NB_COPIES," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":NB_COPIES", nbCopies); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":STORAGE_CLASS_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify storage class : ") + name + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyStorageClassComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE STORAGE_CLASS SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":STORAGE_CLASS_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify storage class : ") + name + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo){ - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE STORAGE_CLASS SET " - "VIRTUAL_ORGANIZATION_ID = (SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME = :VO)," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - if(vo.empty()){ - throw UserSpecifiedAnEmptyStringVo(std::string("Cannot modify the vo of the storage class : ") + name + " because the vo is an empty string"); - } - if(!virtualOrganizationExists(conn,vo)){ - throw exception::UserError(std::string("Cannot modify storage class : ") + name + - " because the vo " + vo + " does not exist"); - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":VO", vo); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":STORAGE_CLASS_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify storage class : ") + name + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyStorageClassName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, - const std::string ¤tName, const std::string &newName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE STORAGE_CLASS SET " - "STORAGE_CLASS_NAME = :NEW_STORAGE_CLASS_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "STORAGE_CLASS_NAME = :CURRENT_STORAGE_CLASS_NAME"; - auto conn = m_connPool.getConn(); - if(newName != currentName){ - if(storageClassExists(conn,newName)){ - throw exception::UserError(std::string("Cannot modify the storage class name ") + currentName +". The new name : " + newName+" already exists in the database."); - } - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":NEW_STORAGE_CLASS_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_STORAGE_CLASS_NAME", currentName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify storage class : ") + currentName + - " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -// ----------------------------------------------------------------------------- -// modifyArchiveFileStorageClassId -// ----------------------------------------------------------------------------- -void RdbmsCatalogue::modifyArchiveFileStorageClassId(const uint64_t archiveFileId, const std::string& newStorageClassName) const { - try { - auto conn = m_connPool.getConn(); - if(!storageClassExists(conn, newStorageClassName)) { - exception::UserError ue; - ue.getMessage() << "Cannot modify archive file " << ": " << archiveFileId << " because storage class " - << ":" << newStorageClassName << " does not exist"; - throw ue; - } - - const char *const sql = - "UPDATE ARCHIVE_FILE " - "SET STORAGE_CLASS_ID = (" - "SELECT STORAGE_CLASS_ID FROM STORAGE_CLASS WHERE STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME " - ") " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", newStorageClassName); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - auto rset = stmt.executeQuery(); - - } catch(exception::UserError &ue) { - throw ue; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - } -} - -//------------------------------------------------------------------------------ -// createMediaType -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createMediaType( - const common::dataStructures::SecurityIdentity &admin, - const MediaType &mediaType) { - try { - if (mediaType.name.empty()) { - throw UserSpecifiedAnEmptyStringMediaTypeName("Cannot create media type because the media type name is an" - " empty string"); - } - - if (mediaType.cartridge.empty()) { - throw UserSpecifiedAnEmptyStringCartridge(std::string("Cannot create media type ") + mediaType.name + - " because the cartridge is an empty string"); - } - - if (mediaType.comment.empty()) { - throw UserSpecifiedAnEmptyStringComment(std::string("Cannot create media type ") + mediaType.name + - " because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(mediaType.comment); - if (mediaType.capacityInBytes == 0){ - throw UserSpecifiedAZeroCapacity(std::string("Cannot create media type ") + mediaType.name + " because the capacity is zero"); - } - auto conn = m_connPool.getConn(); - if (mediaTypeExists(conn, mediaType.name)) { - throw exception::UserError(std::string("Cannot create media type ") + mediaType.name + - " because it already exists"); - } - const uint64_t mediaTypeId = getNextMediaTypeId(conn); - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO MEDIA_TYPE(" - "MEDIA_TYPE_ID," - "MEDIA_TYPE_NAME," - "CARTRIDGE," - "CAPACITY_IN_BYTES," - "PRIMARY_DENSITY_CODE," - "SECONDARY_DENSITY_CODE," - "NB_WRAPS," - "MIN_LPOS," - "MAX_LPOS," - - "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(" - ":MEDIA_TYPE_ID," - ":MEDIA_TYPE_NAME," - ":CARTRIDGE," - ":CAPACITY_IN_BYTES," - ":PRIMARY_DENSITY_CODE," - ":SECONDARY_DENSITY_CODE," - ":NB_WRAPS," - ":MIN_LPOS," - ":MAX_LPOS," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindUint64(":MEDIA_TYPE_ID", mediaTypeId); - stmt.bindString(":MEDIA_TYPE_NAME", mediaType.name); - stmt.bindString(":CARTRIDGE", mediaType.cartridge); - stmt.bindUint64(":CAPACITY_IN_BYTES", mediaType.capacityInBytes); - stmt.bindUint8(":PRIMARY_DENSITY_CODE", mediaType.primaryDensityCode); - stmt.bindUint8(":SECONDARY_DENSITY_CODE", mediaType.secondaryDensityCode); - stmt.bindUint32(":NB_WRAPS", mediaType.nbWraps); - stmt.bindUint64(":MIN_LPOS", mediaType.minLPos); - stmt.bindUint64(":MAX_LPOS", mediaType.maxLPos); - - stmt.bindString(":USER_COMMENT", mediaType.comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// mediaTypeExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::mediaTypeExists(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT" "\n" - "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME" "\n" - "FROM" "\n" - "MEDIA_TYPE" "\n" - "WHERE" "\n" - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":MEDIA_TYPE_NAME", name); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteMediaType -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteMediaType(const std::string &name) { - try { - auto conn = m_connPool.getConn(); - - if(mediaTypeIsUsedByTapes(conn, name)) { - throw UserSpecifiedMediaTypeUsedByTapes(std::string("The ") + name + - " media type is being used by one or more tapes"); - } - - const char *const sql = - "DELETE FROM" "\n" - "MEDIA_TYPE" "\n" - "WHERE" "\n" - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":MEDIA_TYPE_NAME", name); - - stmt.executeNonQuery(); - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMediaTypes -//------------------------------------------------------------------------------ -std::list<MediaTypeWithLogs> RdbmsCatalogue::getMediaTypes() const { - try { - std::list<MediaTypeWithLogs> mediaTypes; - const char *const sql = - "SELECT" "\n" - "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME," "\n" - "CARTRIDGE AS CARTRIDGE," "\n" - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," "\n" - "PRIMARY_DENSITY_CODE AS PRIMARY_DENSITY_CODE," "\n" - "SECONDARY_DENSITY_CODE AS SECONDARY_DENSITY_CODE," "\n" - "NB_WRAPS AS NB_WRAPS," "\n" - "MIN_LPOS AS MIN_LPOS," "\n" - "MAX_LPOS AS MAX_LPOS," "\n" - - "USER_COMMENT AS USER_COMMENT," "\n" - - "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," "\n" - "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," "\n" - "CREATION_LOG_TIME AS CREATION_LOG_TIME," "\n" - - "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," "\n" - "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," "\n" - "LAST_UPDATE_TIME AS LAST_UPDATE_TIME" "\n" - "FROM" "\n" - "MEDIA_TYPE" "\n" - "ORDER BY" "\n" - "MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - MediaTypeWithLogs mediaType; - - mediaType.name = rset.columnString("MEDIA_TYPE_NAME"); - mediaType.cartridge = rset.columnString("CARTRIDGE"); - mediaType.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - mediaType.primaryDensityCode = rset.columnOptionalUint8("PRIMARY_DENSITY_CODE"); - mediaType.secondaryDensityCode = rset.columnOptionalUint8("SECONDARY_DENSITY_CODE"); - mediaType.nbWraps = rset.columnOptionalUint32("NB_WRAPS"); - mediaType.minLPos = rset.columnOptionalUint64("MIN_LPOS"); - mediaType.maxLPos = rset.columnOptionalUint64("MAX_LPOS"); - mediaType.comment = rset.columnString("USER_COMMENT"); - mediaType.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - mediaType.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - mediaType.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - mediaType.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - mediaType.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - mediaType.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - mediaTypes.push_back(mediaType); - } - - return mediaTypes; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -MediaType RdbmsCatalogue::getMediaTypeByVid(const std::string& vid) const { - try { - std::list<MediaTypeWithLogs> mediaTypes; - const char *const sql = - "SELECT" "\n" - "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME," "\n" - "CARTRIDGE AS CARTRIDGE," "\n" - "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," "\n" - "PRIMARY_DENSITY_CODE AS PRIMARY_DENSITY_CODE," "\n" - "SECONDARY_DENSITY_CODE AS SECONDARY_DENSITY_CODE," "\n" - "NB_WRAPS AS NB_WRAPS," "\n" - "MIN_LPOS AS MIN_LPOS," "\n" - "MAX_LPOS AS MAX_LPOS," "\n" - - "MEDIA_TYPE.USER_COMMENT AS USER_COMMENT " "\n" - "FROM" "\n" - "MEDIA_TYPE " "\n" - "INNER JOIN TAPE " "\n" - "ON MEDIA_TYPE.MEDIA_TYPE_ID = TAPE.MEDIA_TYPE_ID " "\n" - "WHERE " "\n" - "TAPE.VID = :VID" "\n"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID",vid); - auto rset = stmt.executeQuery(); - if(rset.next()){ - MediaType mediaType; - - mediaType.name = rset.columnString("MEDIA_TYPE_NAME"); - mediaType.cartridge = rset.columnString("CARTRIDGE"); - mediaType.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - mediaType.primaryDensityCode = rset.columnOptionalUint8("PRIMARY_DENSITY_CODE"); - mediaType.secondaryDensityCode = rset.columnOptionalUint8("SECONDARY_DENSITY_CODE"); - mediaType.nbWraps = rset.columnOptionalUint32("NB_WRAPS"); - mediaType.minLPos = rset.columnOptionalUint64("MIN_LPOS"); - mediaType.maxLPos = rset.columnOptionalUint64("MAX_LPOS"); - mediaType.comment = rset.columnString("USER_COMMENT"); - - return mediaType; - } else { - throw exception::Exception("The tape vid "+vid+" does not exist."); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, - const std::string ¤tName, const std::string &newName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "MEDIA_TYPE_NAME = :NEW_MEDIA_TYPE_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :CURRENT_MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - if(newName != currentName){ - if(mediaTypeExists(conn, newName)){ - throw exception::UserError(std::string("Cannot modify the media type name ") + currentName +". The new name : " - + newName + " already exists in the database."); - } - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":NEW_MEDIA_TYPE_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_MEDIA_TYPE_NAME", currentName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + currentName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeCartridge -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &cartridge) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "CARTRIDGE = :CARTRIDGE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":CARTRIDGE", cartridge); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeCapacityInBytes -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t capacityInBytes) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "CAPACITY_IN_BYTES = :CAPACITY_IN_BYTES," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypePrimaryDensityCode -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint8_t primaryDensityCode) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "PRIMARY_DENSITY_CODE = :PRIMARY_DENSITY_CODE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint8(":PRIMARY_DENSITY_CODE", primaryDensityCode); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeSecondaryDensityCode -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint8_t secondaryDensityCode) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "SECONDARY_DENSITY_CODE = :SECONDARY_DENSITY_CODE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint8(":SECONDARY_DENSITY_CODE", secondaryDensityCode); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeNbWraps -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, - const std::optional<std::uint32_t> &nbWraps) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "NB_WRAPS = :NB_WRAPS," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint32(":NB_WRAPS", nbWraps); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeMinLPos -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::optional<std::uint64_t> &minLPos) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "MIN_LPOS = :MIN_LPOS," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":MIN_LPOS", minLPos); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeMaxLPos -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::optional<std::uint64_t> &maxLPos) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "MAX_LPOS = :MAX_LPOS," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":MAX_LPOS", maxLPos); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyMediaTypeComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MEDIA_TYPE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MEDIA_TYPE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createTapePool -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createTapePool( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &vo, - const uint64_t nbPartialTapes, - const bool encryptionValue, - const std::optional<std::string> &supply, - const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create tape pool because the tape pool name is an empty string"); - } - - if(vo.empty()) { - throw UserSpecifiedAnEmptyStringVo("Cannot create tape pool because the VO is an empty string"); - } - - if (comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create tape pool because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - auto conn = m_connPool.getConn(); - - if(tapePoolExists(conn, name)) { - throw exception::UserError(std::string("Cannot create tape pool ") + name + - " because a tape pool with the same name already exists"); - } - if(!virtualOrganizationExists(conn,vo)){ - throw exception::UserError(std::string("Cannot create tape pool ") + name + \ - " because vo : "+vo+" does not exist."); - } - 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," - "VIRTUAL_ORGANIZATION_ID," - "NB_PARTIAL_TAPES," - "IS_ENCRYPTED," - "SUPPLY," - - "USER_COMMENT," - - "CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME)" - "SELECT " - ":TAPE_POOL_ID," - ":TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION_ID," - ":NB_PARTIAL_TAPES," - ":IS_ENCRYPTED," - ":SUPPLY," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME " - "FROM " - "VIRTUAL_ORGANIZATION " - "WHERE " - "VIRTUAL_ORGANIZATION_NAME = :VO"; - 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); - stmt.bindBool(":IS_ENCRYPTED", encryptionValue); - stmt.bindString(":SUPPLY", supply); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapePoolExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::tapePoolExists(const std::string &tapePoolName) const { - try { - auto conn = m_connPool.getConn(); - return tapePoolExists(conn, tapePoolName); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapePoolExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) const { - try { - const char *const sql = - "SELECT " - "TAPE_POOL_NAME AS TAPE_POOL_NAME " - "FROM " - "TAPE_POOL " - "WHERE " - "TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapePoolUsedInAnArchiveRoute -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::tapePoolUsedInAnArchiveRoute(rdbms::Conn &conn, const std::string &tapePoolName) const { - try { - const char *const sql = - "SELECT" "\n" - "TAPE_POOL_NAME AS TAPE_POOL_NAME" "\n" - "FROM" "\n" - "TAPE_POOL" "\n" - "INNER JOIN ARCHIVE_ROUTE ON" "\n" - "TAPE_POOL.TAPE_POOL_ID = ARCHIVE_ROUTE.TAPE_POOL_ID" "\n" - "WHERE" "\n" - "TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// archiveFileExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " - "FROM " - "ARCHIVE_FILE " - "WHERE " - "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskFileIdExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName, - const std::string &diskFileId) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " - "DISK_FILE_ID AS DISK_FILE_ID " - "FROM " - "ARCHIVE_FILE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "DISK_FILE_ID = :DISK_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":DISK_FILE_ID", diskFileId); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskFileUserExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName, - uint32_t diskFileOwnerUid) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " - "DISK_FILE_UID AS DISK_FILE_UID " - "FROM " - "ARCHIVE_FILE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "DISK_FILE_UID = :DISK_FILE_UID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindUint64(":DISK_FILE_UID", diskFileOwnerUid); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskFileGroupExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName, - uint32_t diskFileGid) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " - "DISK_FILE_GID AS DISK_FILE_GID " - "FROM " - "ARCHIVE_FILE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "DISK_FILE_GID = :DISK_FILE_GID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindUint64(":DISK_FILE_GID", diskFileGid); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// archiveRouteExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::archiveRouteExists(rdbms::Conn &conn, - const std::string &storageClassName, const uint32_t copyNb) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_ROUTE.STORAGE_CLASS_ID AS STORAGE_CLASS_ID," - "ARCHIVE_ROUTE.COPY_NB AS COPY_NB " - "FROM " - "ARCHIVE_ROUTE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "WHERE " - "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND " - "ARCHIVE_ROUTE.COPY_NB = :COPY_NB"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindUint64(":COPY_NB", copyNb); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapePool -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTapePool(const std::string &name) { - try { - auto conn = m_connPool.getConn(); - - if(tapePoolUsedInAnArchiveRoute(conn, name)) { - UserSpecifiedTapePoolUsedInAnArchiveRoute ex; - ex.getMessage() << "Cannot delete tape-pool " << name << " because it is used in an archive route"; - throw ex; - } - - const uint64_t nbTapesInPool = getNbTapesInPool(conn, name); - - if(0 == nbTapesInPool) { - const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } else { - throw UserSpecifiedAnEmptyTapePool(std::string("Cannot delete tape-pool ") + name + " because it is not empty"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// getTapePools -//------------------------------------------------------------------------------ -std::list<TapePool> RdbmsCatalogue::getTapePools(const TapePoolSearchCriteria &searchCriteria) const { - try { - auto conn = m_connPool.getConn(); - return getTapePools(conn, searchCriteria); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -std::list<TapePool> RdbmsCatalogue::getTapePools(rdbms::Conn &conn, const TapePoolSearchCriteria &searchCriteria) const { - if (isSetAndEmpty(searchCriteria.name)) throw exception::UserError("Pool name cannot be an empty string"); - if (isSetAndEmpty(searchCriteria.vo)) throw exception::UserError("Virtual organisation cannot be an empty string"); - try { - - if (searchCriteria.name && !tapePoolExists(conn, searchCriteria.name.value())) { - UserSpecifiedANonExistentTapePool ex; - ex.getMessage() << "Cannot list tape pools because tape pool " + searchCriteria.name.value() + " does not exist"; - throw ex; - } - - if (searchCriteria.vo && !virtualOrganizationExists(conn, searchCriteria.vo.value())) { - UserSpecifiedANonExistentVirtualOrganization ex; - ex.getMessage() << "Cannot list tape pools because virtual organization " + searchCriteria.vo.value() + " does not exist"; - throw ex; - } - - std::list<TapePool> pools; - std::string sql = - "SELECT " - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES," - "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED," - "TAPE_POOL.SUPPLY AS SUPPLY," - - "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.DATA_IN_BYTES = 0 THEN 1 ELSE 0 END), 0) AS NB_EMPTY_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_DISABLED THEN 1 ELSE 0 END), 0) AS NB_DISABLED_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.IS_FULL <> '0' THEN 1 ELSE 0 END), 0) AS NB_FULL_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_ACTIVE AND TAPE.IS_FULL = '0' THEN 1 ELSE 0 END), 0) AS NB_WRITABLE_TAPES," - "COALESCE(SUM(MEDIA_TYPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES," - "COALESCE(SUM(TAPE.DATA_IN_BYTES), 0) AS DATA_IN_BYTES," - "COALESCE(SUM(TAPE.LAST_FSEQ), 0) AS NB_PHYSICAL_FILES," - - "TAPE_POOL.USER_COMMENT AS USER_COMMENT," - - "TAPE_POOL.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "TAPE_POOL.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "TAPE_POOL.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "TAPE_POOL.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "TAPE_POOL.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "TAPE_POOL.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE_POOL " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "LEFT OUTER JOIN TAPE ON " - "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID " - "LEFT OUTER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID"; - - if (searchCriteria.name || searchCriteria.vo || searchCriteria.encrypted) { - sql += " WHERE "; - } - bool addedAWhereConstraint = false; - if (searchCriteria.name) { - sql += "TAPE_POOL.TAPE_POOL_NAME = :NAME"; - addedAWhereConstraint = true; - } - - if (searchCriteria.vo) { - if (addedAWhereConstraint) sql += " AND "; - sql += "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME = :VO"; - addedAWhereConstraint = true; - } - - if (searchCriteria.encrypted) { - if (addedAWhereConstraint) sql += " AND "; - sql += "TAPE_POOL.IS_ENCRYPTED = :ENCRYPTED"; - } - - sql += - " GROUP BY " - "TAPE_POOL.TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME," - "TAPE_POOL.NB_PARTIAL_TAPES," - "TAPE_POOL.IS_ENCRYPTED," - "TAPE_POOL.SUPPLY," - "TAPE_POOL.USER_COMMENT," - "TAPE_POOL.CREATION_LOG_USER_NAME," - "TAPE_POOL.CREATION_LOG_HOST_NAME," - "TAPE_POOL.CREATION_LOG_TIME," - "TAPE_POOL.LAST_UPDATE_USER_NAME," - "TAPE_POOL.LAST_UPDATE_HOST_NAME," - "TAPE_POOL.LAST_UPDATE_TIME " - "ORDER BY " - "TAPE_POOL_NAME"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":STATE_DISABLED",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::DISABLED)); - stmt.bindString(":STATE_ACTIVE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); - - if (searchCriteria.name) { - stmt.bindString(":NAME", searchCriteria.name.value()); - } - - if (searchCriteria.vo) { - stmt.bindString(":VO", searchCriteria.vo.value()); - } - - if(searchCriteria.encrypted) { - stmt.bindBool(":ENCRYPTED", searchCriteria.encrypted.value()); - } - - auto rset = stmt.executeQuery(); - while (rset.next()) { - TapePool pool; - - pool.name = rset.columnString("TAPE_POOL_NAME"); - pool.vo.name = rset.columnString("VO"); - pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES"); - pool.encryption = rset.columnBool("IS_ENCRYPTED"); - pool.supply = rset.columnOptionalString("SUPPLY"); - pool.nbTapes = rset.columnUint64("NB_TAPES"); - pool.nbEmptyTapes = rset.columnUint64("NB_EMPTY_TAPES"); - pool.nbDisabledTapes = rset.columnUint64("NB_DISABLED_TAPES"); - pool.nbFullTapes = rset.columnUint64("NB_FULL_TAPES"); - pool.nbWritableTapes = rset.columnUint64("NB_WRITABLE_TAPES"); - pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - pool.dataBytes = rset.columnUint64("DATA_IN_BYTES"); - pool.nbPhysicalFiles = rset.columnUint64("NB_PHYSICAL_FILES"); - pool.comment = rset.columnString("USER_COMMENT"); - pool.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - pool.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - pool.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - pool.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - pool.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - pool.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - pools.push_back(pool); - } - - return pools; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapePool -//------------------------------------------------------------------------------ -std::optional<TapePool> RdbmsCatalogue::getTapePool(const std::string &tapePoolName) const { - try { - const char *const sql = - "SELECT " - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES," - "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED," - "TAPE_POOL.SUPPLY AS SUPPLY," - - "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.DATA_IN_BYTES = 0 THEN 1 ELSE 0 END), 0) AS NB_EMPTY_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_DISABLED THEN 1 ELSE 0 END), 0) AS NB_DISABLED_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.IS_FULL <> '0' THEN 1 ELSE 0 END), 0) AS NB_FULL_TAPES," - "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_ACTIVE AND TAPE.IS_FULL = '0' THEN 1 ELSE 0 END), 0) AS NB_WRITABLE_TAPES," - "COALESCE(SUM(MEDIA_TYPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES," - "COALESCE(SUM(TAPE.DATA_IN_BYTES), 0) AS DATA_IN_BYTES," - "COALESCE(SUM(TAPE.LAST_FSEQ), 0) AS NB_PHYSICAL_FILES," - - "TAPE_POOL.USER_COMMENT AS USER_COMMENT," - - "TAPE_POOL.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "TAPE_POOL.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "TAPE_POOL.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "TAPE_POOL.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "TAPE_POOL.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "TAPE_POOL.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE_POOL " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "LEFT OUTER JOIN TAPE ON " - "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID " - "LEFT OUTER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " - "GROUP BY " - "TAPE_POOL.TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME," - "TAPE_POOL.NB_PARTIAL_TAPES," - "TAPE_POOL.IS_ENCRYPTED," - "TAPE_POOL.SUPPLY," - "TAPE_POOL.USER_COMMENT," - "TAPE_POOL.CREATION_LOG_USER_NAME," - "TAPE_POOL.CREATION_LOG_HOST_NAME," - "TAPE_POOL.CREATION_LOG_TIME," - "TAPE_POOL.LAST_UPDATE_USER_NAME," - "TAPE_POOL.LAST_UPDATE_HOST_NAME," - "TAPE_POOL.LAST_UPDATE_TIME " - "HAVING " - "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME " - "ORDER BY " - "TAPE_POOL_NAME"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - stmt.bindString(":STATE_DISABLED",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::DISABLED)); - stmt.bindString(":STATE_ACTIVE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); - - auto rset = stmt.executeQuery(); - - if (!rset.next()) { - return std::nullopt; - } - - TapePool pool; - pool.name = rset.columnString("TAPE_POOL_NAME"); - pool.vo.name = rset.columnString("VO"); - pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES"); - pool.encryption = rset.columnBool("IS_ENCRYPTED"); - pool.supply = rset.columnOptionalString("SUPPLY"); - pool.nbTapes = rset.columnUint64("NB_TAPES"); - pool.nbEmptyTapes = rset.columnUint64("NB_EMPTY_TAPES"); - pool.nbDisabledTapes = rset.columnUint64("NB_DISABLED_TAPES"); - pool.nbFullTapes = rset.columnUint64("NB_FULL_TAPES"); - pool.nbWritableTapes = rset.columnUint64("NB_WRITABLE_TAPES"); - pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - pool.dataBytes = rset.columnUint64("DATA_IN_BYTES"); - pool.nbPhysicalFiles = rset.columnUint64("NB_PHYSICAL_FILES"); - pool.comment = rset.columnString("USER_COMMENT"); - pool.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - pool.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - pool.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - pool.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - pool.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - pool.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - return pool; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapePoolVO -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &vo) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" - " string"); - } - - if(vo.empty()) { - throw UserSpecifiedAnEmptyStringVo("Cannot modify tape pool because the new VO is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE_POOL SET " - "VIRTUAL_ORGANIZATION_ID = (SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME=:VO)," - "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 = :TAPE_POOL_NAME"; - auto conn = m_connPool.getConn(); - - if(!virtualOrganizationExists(conn,vo)){ - throw exception::UserError(std::string("Cannot modify tape pool ") + name +" because the vo " + vo + " does not exist"); - } - - auto stmt = conn.createStmt(sql); - stmt.bindString(":VO", vo); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); - } - //The VO of this tapepool has changed, invalidate the tapepool-VO cache - m_tapepoolVirtualOrganizationCache.invalidate(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapePoolNbPartialTapes -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t nbPartialTapes) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" - " string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE_POOL SET " - "NB_PARTIAL_TAPES = :NB_PARTIAL_TAPES," - "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 = :TAPE_POOL_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapePoolComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" - " string"); - } - - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot modify tape pool because the new comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE_POOL SET " - "USER_COMMENT = :USER_COMMENT," - "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 = :TAPE_POOL_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapePoolEncryption -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const bool encryptionValue) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE_POOL SET " - "IS_ENCRYPTED = :IS_ENCRYPTED," - "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 = :TAPE_POOL_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindBool(":IS_ENCRYPTED", encryptionValue); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapePoolSupply -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &supply) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" - " string"); - } - - std::optional<std::string> optionalSupply; - if(!supply.empty()) { - optionalSupply = supply; - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE_POOL SET " - "SUPPLY = :SUPPLY," - "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 = :TAPE_POOL_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":SUPPLY", optionalSupply); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":TAPE_POOL_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// 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"); - } - - m_tapepoolVirtualOrganizationCache.invalidate(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createArchiveRoute -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createArchiveRoute( - const common::dataStructures::SecurityIdentity &admin, - const std::string &storageClassName, - const uint32_t copyNb, - const std::string &tapePoolName, - const std::string &comment) { - try { - if(storageClassName.empty()) { - throw UserSpecifiedAnEmptyStringStorageClassName("Cannot create archive route because storage class name is an" - " empty string"); - } - if(0 == copyNb) { - throw UserSpecifiedAZeroCopyNb("Cannot create archive route because copy number is zero"); - } - if(tapePoolName.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create archive route because tape pool name is an empty" - " string"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create archive route because comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - auto conn = m_connPool.getConn(); - if(archiveRouteExists(conn, storageClassName, copyNb)) { - exception::UserError ue; - ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb - << "->" << tapePoolName << " because it already exists"; - throw ue; - } - { - const auto routes = getArchiveRoutes(conn, storageClassName, tapePoolName); - if(!routes.empty()) { - exception::UserError ue; - ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb - << "->" << tapePoolName << " because a route already exists for this storage class and tape pool"; - throw ue; - } - } - if(!storageClassExists(conn, storageClassName)) { - exception::UserError ue; - ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb - << "->" << tapePoolName << " because storage class " << ":" << storageClassName << - " does not exist"; - throw ue; - } - if(!tapePoolExists(conn, tapePoolName)) { - exception::UserError ue; - ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb - << "->" << tapePoolName << " because tape pool " << tapePoolName + " does not exist"; - throw ue; - } - - const char *const sql = - "INSERT INTO ARCHIVE_ROUTE(" - "STORAGE_CLASS_ID," - "COPY_NB," - "TAPE_POOL_ID," - - "USER_COMMENT," - - "CREATION_LOG_USER_NAME," - "CREATION_LOG_HOST_NAME," - "CREATION_LOG_TIME," - - "LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME)" - "SELECT " - "STORAGE_CLASS_ID," - ":COPY_NB," - "(SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME) AS TAPE_POOL_ID," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindUint64(":COPY_NB", copyNb); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteArchiveRoute -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteArchiveRoute(const std::string &storageClassName, - const uint32_t copyNb) { - try { - const char *const sql = - "DELETE FROM " - "ARCHIVE_ROUTE " - "WHERE " - "STORAGE_CLASS_ID = (" - "SELECT " - "STORAGE_CLASS_ID " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " - "COPY_NB = :COPY_NB"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindUint64(":COPY_NB", copyNb); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - exception::UserError ue; - ue.getMessage() << "Cannot delete archive route for storage-class " << ":" + storageClassName + - " and copy number " << copyNb << " because it does not exist"; - throw ue; - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveRoutes -//------------------------------------------------------------------------------ -std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes() const { - try { - std::list<common::dataStructures::ArchiveRoute> routes; - const char *const sql = - "SELECT " - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - - "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT," - - "ARCHIVE_ROUTE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "ARCHIVE_ROUTE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "ARCHIVE_ROUTE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "ARCHIVE_ROUTE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "ARCHIVE_ROUTE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "ARCHIVE_ROUTE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "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 " - "ORDER BY " - "STORAGE_CLASS_NAME, COPY_NB"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::ArchiveRoute route; - - route.storageClassName = rset.columnString("STORAGE_CLASS_NAME"); - route.copyNb = rset.columnUint64("COPY_NB"); - route.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - route.comment = rset.columnString("USER_COMMENT"); - route.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - route.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - route.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - route.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - route.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - route.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - routes.push_back(route); - } - - return routes; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveRoutes -//------------------------------------------------------------------------------ -std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes( - const std::string &storageClassName, - const std::string &tapePoolName) const { - try { - auto conn = m_connPool.getConn(); - return getArchiveRoutes(conn, storageClassName, tapePoolName); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveRoutes -//------------------------------------------------------------------------------ -std::list<common::dataStructures::ArchiveRoute> RdbmsCatalogue::getArchiveRoutes(rdbms::Conn &conn, - const std::string &storageClassName, const std::string &tapePoolName) const { - try { - std::list<common::dataStructures::ArchiveRoute> routes; - const char *const sql = - "SELECT" "\n" - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," "\n" - "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," "\n" - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," "\n" - - "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT," "\n" - - "ARCHIVE_ROUTE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," "\n" - "ARCHIVE_ROUTE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," "\n" - "ARCHIVE_ROUTE.CREATION_LOG_TIME AS CREATION_LOG_TIME," "\n" - - "ARCHIVE_ROUTE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," "\n" - "ARCHIVE_ROUTE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," "\n" - "ARCHIVE_ROUTE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME" "\n" - "FROM" "\n" - "ARCHIVE_ROUTE" "\n" - "INNER JOIN STORAGE_CLASS ON" "\n" - "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID" "\n" - "INNER JOIN TAPE_POOL ON" "\n" - "ARCHIVE_ROUTE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID" "\n" - "WHERE" "\n" - "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND" "\n" - "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME" "\n" - "ORDER BY" "\n" - "STORAGE_CLASS_NAME, COPY_NB"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::ArchiveRoute route; - - route.storageClassName = rset.columnString("STORAGE_CLASS_NAME"); - route.copyNb = rset.columnUint64("COPY_NB"); - route.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - route.comment = rset.columnString("USER_COMMENT"); - route.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - route.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - route.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - route.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - route.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - route.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - routes.push_back(route); - } - - return routes; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyArchiveRouteTapePoolName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, - const std::string &storageClassName, const uint32_t copyNb, - const std::string &tapePoolName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE ARCHIVE_ROUTE SET " - "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 " - "WHERE " - "STORAGE_CLASS_ID = (" - "SELECT " - "STORAGE_CLASS_ID " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " - "COPY_NB = :COPY_NB"; - auto conn = m_connPool.getConn(); - - if(!archiveRouteExists(conn, storageClassName, copyNb)) { - throw UserSpecifiedANonExistentArchiveRoute("Archive route does not exist"); - } - - if(!tapePoolExists(conn, tapePoolName)) { - throw UserSpecifiedANonExistentTapePool("Tape pool does not exist"); - } - - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindUint64(":COPY_NB", copyNb); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentArchiveRoute("Archive route does not exist"); - } - } catch(exception::UserError &ue) { - std::ostringstream msg; - msg << "Cannot modify tape pool of archive route: storageClassName=" << storageClassName << " copyNb=" << copyNb << - " tapePoolName=" << tapePoolName << ": " << ue.getMessage().str(); - ue.getMessage().str(msg.str()); - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyArchiveRouteComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &storageClassName, const uint32_t copyNb, - const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE ARCHIVE_ROUTE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "STORAGE_CLASS_ID = (" - "SELECT " - "STORAGE_CLASS_ID " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " - "COPY_NB = :COPY_NB"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); - stmt.bindUint64(":COPY_NB", copyNb); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - exception::UserError ue; - ue.getMessage() << "Cannot modify archive route for storage-class " << ":" + storageClassName + - " and copy number " << copyNb << " because it does not exist"; - throw ue; - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createLogicalLibrary -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createLogicalLibrary( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const bool isDisabled, - const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - auto conn = m_connPool.getConn(); - if(logicalLibraryExists(conn, name)) { - throw exception::UserError(std::string("Cannot create logical library ") + name + - " because a logical library with the same name already exists"); - } - const uint64_t logicalLibraryId = getNextLogicalLibraryId(conn); - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO LOGICAL_LIBRARY(" - "LOGICAL_LIBRARY_ID," - "LOGICAL_LIBRARY_NAME," - "IS_DISABLED," - - "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(" - ":LOGICAL_LIBRARY_ID," - ":LOGICAL_LIBRARY_NAME," - ":IS_DISABLED," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindUint64(":LOGICAL_LIBRARY_ID", logicalLibraryId); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - stmt.bindBool(":IS_DISABLED", isDisabled); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// logicalLibraryExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName) const { - try { - const char *const sql = - "SELECT " - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME " - "FROM " - "LOGICAL_LIBRARY " - "WHERE " - "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteLogicalLibrary -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteLogicalLibrary(const std::string &name) { - try { - const char *const sql = - "DELETE FROM LOGICAL_LIBRARY" "\n" - "WHERE" "\n" - "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME AND" "\n" - "NOT EXISTS (" "\n" - "SELECT" "\n" - "TAPE.LOGICAL_LIBRARY_ID" "\n" - "FROM" "\n" - "TAPE" "\n" - "WHERE" "\n" - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID)"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - stmt.executeNonQuery(); - - // The delete statement will effect no rows and will not raise an error if - // either the logical library does not exist or if it still contains tapes - if(0 == stmt.getNbAffectedRows()) { - if(logicalLibraryExists(conn, name)) { - throw UserSpecifiedANonEmptyLogicalLibrary(std::string("Cannot delete logical library ") + name + - " because it contains one or more tapes"); - } else { - throw UserSpecifiedANonExistentLogicalLibrary(std::string("Cannot delete logical library ") + name + - " because it does not exist"); - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getLogicalLibraries -//------------------------------------------------------------------------------ -std::list<common::dataStructures::LogicalLibrary> RdbmsCatalogue::getLogicalLibraries() const { - try { - std::list<common::dataStructures::LogicalLibrary> libs; - const char *const sql = - "SELECT " - "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "IS_DISABLED AS IS_DISABLED," - - "USER_COMMENT AS USER_COMMENT," - "DISABLED_REASON AS DISABLED_REASON," - - "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 " - "FROM " - "LOGICAL_LIBRARY " - "ORDER BY " - "LOGICAL_LIBRARY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::LogicalLibrary lib; - - lib.name = rset.columnString("LOGICAL_LIBRARY_NAME"); - lib.isDisabled = rset.columnBool("IS_DISABLED"); - lib.comment = rset.columnString("USER_COMMENT"); - lib.disabledReason = rset.columnOptionalString("DISABLED_REASON"); - lib.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - lib.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - lib.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - lib.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - lib.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - lib.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - libs.push_back(lib); - } - - return libs; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyLogicalLibraryName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, - const std::string ¤tName, const std::string &newName) { - try { - if(currentName.empty()) { - throw UserSpecifiedAnEmptyStringLogicalLibraryName( - "Cannot modify logical library because the logical library name is an empty string"); - } - - if(newName.empty()) { - throw UserSpecifiedAnEmptyStringLogicalLibraryName( - "Cannot modify logical library because the new name is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE LOGICAL_LIBRARY SET " - "LOGICAL_LIBRARY_NAME = :NEW_LOGICAL_LIBRARY_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "LOGICAL_LIBRARY_NAME = :CURRENT_LOGICAL_LIBRARY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":NEW_LOGICAL_LIBRARY_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_LOGICAL_LIBRARY_NAME", currentName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify logical library ") + currentName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyLogicalLibraryComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE LOGICAL_LIBRARY SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyLogicalLibraryDisabledReason -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &disabledReason) { - try { - checkCommentOrReasonMaxLength(disabledReason); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE LOGICAL_LIBRARY SET " - "DISABLED_REASON = :DISABLED_REASON," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISABLED_REASON", disabledReason.empty() ? std::nullopt : std::optional<std::string>(disabledReason)); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setLogicalLibraryDisabled -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const bool disabledValue) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE LOGICAL_LIBRARY SET " - "IS_DISABLED = :IS_DISABLED," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindBool(":IS_DISABLED", disabledValue); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createTape -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createTape( - const common::dataStructures::SecurityIdentity &admin, - const CreateTapeAttributes &tape) { - // CTA hard code this field to FALSE - const bool isFromCastor = false; - try { - std::string vid = tape.vid; - std::string mediaTypeName = tape.mediaType; - std::string vendor = tape.vendor; - std::string logicalLibraryName = tape.logicalLibraryName; - std::string tapePoolName = tape.tapePoolName; - bool full = tape.full; - // Translate an empty comment string to a NULL database value - const std::optional<std::string> tapeComment = tape.comment && tape.comment->empty() ? std::nullopt : tape.comment; - checkCommentOrReasonMaxLength(tapeComment); - const std::optional<std::string> stateReason = tape.stateReason && cta::utils::trimString(tape.stateReason.value()).empty() ? std::nullopt : tape.stateReason; - checkCommentOrReasonMaxLength(stateReason); - if(vid.empty()) { - throw UserSpecifiedAnEmptyStringVid("Cannot create tape because the VID is an empty string"); - } - - if(!utils::isUpper(vid)) { - throw UserSpecifiedAnEmptyStringVid("Cannot create tape because the VID has non uppercase characters"); - } - - if(mediaTypeName.empty()) { - throw UserSpecifiedAnEmptyStringMediaType("Cannot create tape because the media type is an empty string"); - } - - if(vendor.empty()) { - throw UserSpecifiedAnEmptyStringVendor("Cannot create tape because the vendor is an empty string"); - } - - if(logicalLibraryName.empty()) { - throw UserSpecifiedAnEmptyStringLogicalLibraryName("Cannot create tape because the logical library name is an" - " empty string"); - } - - if(tapePoolName.empty()) { - throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create tape because the tape pool name is an empty string"); - } - - std::string tapeState; - try { - tapeState = common::dataStructures::Tape::stateToString(tape.state); - } catch(cta::exception::Exception &ex) { - std::string errorMsg = "Cannot create tape because the state specified does not exist. Possible values for state are: " + common::dataStructures::Tape::getAllPossibleStates(); - throw UserSpecifiedANonExistentTapeState(errorMsg); - } - - if(tape.state != common::dataStructures::Tape::ACTIVE){ - if(!stateReason){ - throw UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive("Cannot create tape because no reason has been provided for the state " + tapeState); - } - } - - auto conn = m_connPool.getConn(); - if(tapeExists(conn, vid)) { - throw exception::UserError(std::string("Cannot create tape ") + vid + - " because a tape with the same volume identifier already exists"); - } - const auto logicalLibraryId = getLogicalLibraryId(conn, logicalLibraryName); - if(!logicalLibraryId) { - throw exception::UserError(std::string("Cannot create tape ") + vid + " because logical library " + - logicalLibraryName + " does not exist"); - } - const auto tapePoolId = getTapePoolId(conn, tapePoolName); - if(!tapePoolId) { - throw exception::UserError(std::string("Cannot create tape ") + vid + " because tape pool " + - tapePoolName + " does not exist"); - } - - const auto mediaTypeId = getMediaTypeId(conn, mediaTypeName); - if(!mediaTypeId) { - throw exception::UserError(std::string("Cannot create tape ") + vid + " because media type " + - mediaTypeName + " does not exist"); - } - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO TAPE(" "\n" - "VID," "\n" - "MEDIA_TYPE_ID," "\n" - "VENDOR," "\n" - "LOGICAL_LIBRARY_ID," "\n" - "TAPE_POOL_ID," "\n" - "DATA_IN_BYTES," "\n" - "LAST_FSEQ," "\n" - "IS_FULL," "\n" - "IS_FROM_CASTOR," "\n" - - "USER_COMMENT," "\n" - - "TAPE_STATE," "\n" - "STATE_REASON," "\n" - "STATE_UPDATE_TIME," "\n" - "STATE_MODIFIED_BY," "\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" - "VALUES(" "\n" - ":VID," "\n" - ":MEDIA_TYPE_ID," "\n" - ":VENDOR," "\n" - ":LOGICAL_LIBRARY_ID," "\n" - ":TAPE_POOL_ID," "\n" - ":DATA_IN_BYTES," "\n" - ":LAST_FSEQ," "\n" - ":IS_FULL," "\n" - ":IS_FROM_CASTOR," "\n" - - ":USER_COMMENT," "\n" - - ":TAPE_STATE," "\n" - ":STATE_REASON," "\n" - ":STATE_UPDATE_TIME," "\n" - ":STATE_MODIFIED_BY," "\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" - ")"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":VID", vid); - stmt.bindUint64(":MEDIA_TYPE_ID", mediaTypeId.value()); - stmt.bindString(":VENDOR", vendor); - stmt.bindUint64(":LOGICAL_LIBRARY_ID", logicalLibraryId.value()); - stmt.bindUint64(":TAPE_POOL_ID", tapePoolId.value()); - stmt.bindUint64(":DATA_IN_BYTES", 0); - stmt.bindUint64(":LAST_FSEQ", 0); - stmt.bindBool(":IS_FULL", full); - stmt.bindBool(":IS_FROM_CASTOR", isFromCastor); - - stmt.bindString(":USER_COMMENT", tapeComment); - - std::string stateModifiedBy = RdbmsCatalogue::generateTapeStateModifiedBy(admin); - stmt.bindString(":TAPE_STATE",cta::common::dataStructures::Tape::stateToString(tape.state)); - stmt.bindString(":STATE_REASON",stateReason); - stmt.bindUint64(":STATE_UPDATE_TIME",now); - stmt.bindString(":STATE_MODIFIED_BY", stateModifiedBy); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("mediaType", mediaTypeName) - .add("vendor", vendor) - .add("logicalLibraryName", logicalLibraryName) - .add("tapePoolName", tapePoolName) - .add("isFull", full ? 1 : 0) - .add("isFromCastor", isFromCastor ? 1 : 0) - .add("userComment", tape.comment ? tape.comment.value() : "") - .add("tapeState",cta::common::dataStructures::Tape::stateToString(tape.state)) - .add("stateReason",stateReason ? stateReason.value() : "") - .add("stateUpdateTime",now) - .add("stateModifiedBy",stateModifiedBy) - .add("creationLogUserName", admin.username) - .add("creationLogHostName", admin.host) - .add("creationLogTime", now); - lc.log(log::INFO, "Catalogue - user created tape"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapeExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::tapeExists(const std::string &vid) const { - try { - auto conn = m_connPool.getConn(); - return tapeExists(conn, vid); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapeExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::tapeExists(rdbms::Conn &conn, const std::string &vid) const { - try { - const char *const sql = - "SELECT " - "VID AS VID " - "FROM " - "TAPE " - "WHERE " - "VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskSystemExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskSystemExists(const std::string &name) const { - try { - auto conn = m_connPool.getConn(); - return diskSystemExists(conn, name); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskSystemExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskSystemExists(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT " - "DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME " - "FROM " - "DISK_SYSTEM " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_SYSTEM_NAME", name); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskInstanceExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskInstanceExists(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME " - "FROM " - "DISK_INSTANCE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", name); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// diskInstanceSpaceExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::diskInstanceSpaceExists(rdbms::Conn &conn, const std::string &name, const std::string &diskInstance) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME " - "FROM " - "DISK_INSTANCE_SPACE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - " AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - - -//------------------------------------------------------------------------------ -// deleteTape -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTape(const std::string &vid) { - try { - const char *const delete_sql = - "DELETE " - "FROM " - "TAPE " - "WHERE " - "VID = :DELETE_VID AND " - "NOT EXISTS (SELECT VID FROM TAPE_FILE WHERE VID = :SELECT_VID) AND " - "NOT EXISTS (SELECT VID FROM FILE_RECYCLE_LOG WHERE VID = :SELECT_VID2)"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DELETE_VID", vid); - stmt.bindString(":SELECT_VID", vid); - stmt.bindString(":SELECT_VID2", vid); - stmt.executeNonQuery(); - - // The delete statement will effect no rows and will not raise an error if - // either the tape does not exist or if it still has tape files or files in the recycle log - if(0 == stmt.getNbAffectedRows()) { - if(tapeExists(conn, vid)) { - throw UserSpecifiedANonEmptyTape(std::string("Cannot delete tape ") + vid + " because either it contains one or more files or the files that were in it are in the file recycle log."); - } else { - throw UserSpecifiedANonExistentTape(std::string("Cannot delete tape ") + vid + " because it does not exist"); - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapes -//------------------------------------------------------------------------------ -std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(const TapeSearchCriteria &searchCriteria) const { - try { - auto conn = m_connPool.getConn(); - return getTapes(conn, searchCriteria); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapes -//------------------------------------------------------------------------------ -std::list<common::dataStructures::Tape> RdbmsCatalogue::getTapes(rdbms::Conn &conn, - const TapeSearchCriteria &searchCriteria) const { - if(isSetAndEmpty(searchCriteria.vid)) throw exception::UserError("VID cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.mediaType)) throw exception::UserError("Media type cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.vendor)) throw exception::UserError("Vendor cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.logicalLibrary)) throw exception::UserError("Logical library cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.tapePool)) throw exception::UserError("Tape pool cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.vo)) throw exception::UserError("Virtual organisation cannot be an empty string"); - if(isSetAndEmpty(searchCriteria.diskFileIds)) throw exception::UserError("Disk file ID list cannot be empty"); - - try { - if(searchCriteria.tapePool && !tapePoolExists(conn, searchCriteria.tapePool.value())) { - UserSpecifiedANonExistentTapePool ex; - ex.getMessage() << "Cannot list tapes because tape pool " + searchCriteria.tapePool.value() + " does not exist"; - throw ex; - } - - std::list<common::dataStructures::Tape> tapes; - std::string sql = - "SELECT " - "TAPE.VID AS VID," - "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," - "TAPE.VENDOR AS VENDOR," - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," - "TAPE.NB_MASTER_FILES AS NB_MASTER_FILES," - "TAPE.MASTER_DATA_IN_BYTES AS MASTER_DATA_IN_BYTES," - "TAPE.LAST_FSEQ AS LAST_FSEQ," - "TAPE.IS_FULL AS IS_FULL," - "TAPE.DIRTY AS DIRTY," - - "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "TAPE.LABEL_FORMAT AS LABEL_FORMAT," - - "TAPE.LABEL_DRIVE AS LABEL_DRIVE," - "TAPE.LABEL_TIME AS LABEL_TIME," - - "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," - "TAPE.LAST_READ_TIME AS LAST_READ_TIME," - - "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," - "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," - - "TAPE.VERIFICATION_STATUS AS VERIFICATION_STATUS," - - "TAPE.USER_COMMENT AS USER_COMMENT," - - "TAPE.TAPE_STATE AS TAPE_STATE," - "TAPE.STATE_REASON AS STATE_REASON," - "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," - "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," - - "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " - "INNER JOIN LOGICAL_LIBRARY ON " - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " - "INNER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID"; - - if(searchCriteria.vid || - searchCriteria.mediaType || - searchCriteria.vendor || - searchCriteria.logicalLibrary || - searchCriteria.tapePool || - searchCriteria.vo || - searchCriteria.capacityInBytes || - searchCriteria.full || - searchCriteria.diskFileIds || - searchCriteria.state || - searchCriteria.fromCastor) { - sql += " WHERE"; - } - - bool addedAWhereConstraint = false; - - if(searchCriteria.vid) { - sql += " TAPE.VID = :VID"; - addedAWhereConstraint = true; - } - if(searchCriteria.mediaType) { - if(addedAWhereConstraint) sql += " AND "; - sql += " MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE"; - addedAWhereConstraint = true; - } - if(searchCriteria.vendor) { - if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE.VENDOR = :VENDOR"; - addedAWhereConstraint = true; - } - if(searchCriteria.logicalLibrary) { - if(addedAWhereConstraint) sql += " AND "; - sql += " LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - addedAWhereConstraint = true; - } - if(searchCriteria.tapePool) { - if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; - addedAWhereConstraint = true; - } - if(searchCriteria.vo) { - if(addedAWhereConstraint) sql += " AND "; - sql += " VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME = :VO"; - addedAWhereConstraint = true; - } - if(searchCriteria.capacityInBytes) { - if(addedAWhereConstraint) sql += " AND "; - sql += " MEDIA_TYPE.CAPACITY_IN_BYTES = :CAPACITY_IN_BYTES"; - addedAWhereConstraint = true; - } - if(searchCriteria.full) { - if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE.IS_FULL = :IS_FULL"; - addedAWhereConstraint = true; - } - if(searchCriteria.diskFileIds) { - if(addedAWhereConstraint) sql += " AND "; - sql += " VID IN (" - "SELECT DISTINCT A.VID " - "FROM " - "TAPE_FILE A, ARCHIVE_FILE B " - "WHERE " - "A.ARCHIVE_FILE_ID = B.ARCHIVE_FILE_ID AND " - "B.DISK_FILE_ID IN (:DISK_FID0)" - //"B.DISK_FILE_ID IN (:DISK_FID0, :DISK_FID1, :DISK_FID2, :DISK_FID3, :DISK_FID4, :DISK_FID5, :DISK_FID6, :DISK_FID7, :DISK_FID8, :DISK_FID9)" - ")"; - addedAWhereConstraint = true; - } - - if(searchCriteria.state) { - if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE.TAPE_STATE = :TAPE_STATE"; - addedAWhereConstraint = true; - } - if(searchCriteria.fromCastor) { - if(addedAWhereConstraint) sql += " AND "; - sql += " TAPE.IS_FROM_CASTOR = :FROM_CASTOR"; - addedAWhereConstraint = true; - } - - sql += " ORDER BY TAPE.VID"; - - auto stmt = conn.createStmt(sql); - - if(searchCriteria.vid) stmt.bindString(":VID", searchCriteria.vid.value()); - if(searchCriteria.mediaType) stmt.bindString(":MEDIA_TYPE", searchCriteria.mediaType.value()); - if(searchCriteria.vendor) stmt.bindString(":VENDOR", searchCriteria.vendor.value()); - if(searchCriteria.logicalLibrary) stmt.bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary.value()); - if(searchCriteria.tapePool) stmt.bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value()); - if(searchCriteria.vo) stmt.bindString(":VO", searchCriteria.vo.value()); - if(searchCriteria.capacityInBytes) stmt.bindUint64(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes.value()); - if(searchCriteria.full) stmt.bindBool(":IS_FULL", searchCriteria.full.value()); - if(searchCriteria.fromCastor) stmt.bindBool(":FROM_CASTOR", searchCriteria.fromCastor.value()); - try{ - if(searchCriteria.state) stmt.bindString(":TAPE_STATE",cta::common::dataStructures::Tape::stateToString(searchCriteria.state.value())); - } catch(cta::exception::Exception &ex){ - throw cta::exception::UserError(std::string("The state provided does not exist. Possible values are: ") + cta::common::dataStructures::Tape::getAllPossibleStates()); - } - - // Disk file ID lookup requires multiple queries - std::vector<std::string>::const_iterator diskFileId_it; - std::set<std::string> vidsInList; - if(searchCriteria.diskFileIds) diskFileId_it = searchCriteria.diskFileIds.value().begin(); - int num_queries = searchCriteria.diskFileIds ? searchCriteria.diskFileIds.value().size() : 1; - - for(int i = 0; i < num_queries; ++i) { - if(searchCriteria.diskFileIds) { - stmt.bindString(":DISK_FID0", *diskFileId_it++); - } - - auto rset = stmt.executeQuery(); - while (rset.next()) { - auto vid = rset.columnString("VID"); - if(vidsInList.count(vid) == 1) continue; - vidsInList.insert(vid); - - common::dataStructures::Tape tape; - - tape.vid = vid; - tape.mediaType = rset.columnString("MEDIA_TYPE"); - tape.vendor = rset.columnString("VENDOR"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.vo = rset.columnString("VO"); - tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.nbMasterFiles = rset.columnUint64("NB_MASTER_FILES"); - tape.masterDataInBytes = rset.columnUint64("MASTER_DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.full = rset.columnBool("IS_FULL"); - tape.dirty = rset.columnBool("DIRTY"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), "[RdbmsCatalogue::getTapes()]"); - - 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.readMountCount = rset.columnUint64("READ_MOUNT_COUNT"); - tape.writeMountCount = rset.columnUint64("WRITE_MOUNT_COUNT"); - - tape.verificationStatus = rset.columnOptionalString("VERIFICATION_STATUS"); - - auto optionalComment = rset.columnOptionalString("USER_COMMENT"); - tape.comment = optionalComment ? optionalComment.value() : ""; - - tape.setState(rset.columnString("TAPE_STATE")); - tape.stateReason = rset.columnOptionalString("STATE_REASON"); - tape.stateUpdateTime = rset.columnUint64("STATE_UPDATE_TIME"); - tape.stateModifiedBy = rset.columnString("STATE_MODIFIED_BY"); - - tape.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - tape.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - tape.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - tape.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - tape.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - tape.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - tapes.push_back(tape); - } - } - if(searchCriteria.diskFileIds) { - // When searching by diskFileId, results are not guaranteed to be in sorted order - tapes.sort([](const common::dataStructures::Tape &a, const common::dataStructures::Tape &b) { return a.vid < b.vid; }); - } - - return tapes; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapesByVid (single VID) -//------------------------------------------------------------------------------ -common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::string& vid) const { - try { - const char* const sql = - "SELECT " - "TAPE.VID AS VID," - "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," - "TAPE.VENDOR AS VENDOR," - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," - "TAPE.LAST_FSEQ AS LAST_FSEQ," - "TAPE.IS_FULL AS IS_FULL," - "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," - "TAPE.LABEL_FORMAT AS LABEL_FORMAT," - "TAPE.LABEL_DRIVE AS LABEL_DRIVE," - "TAPE.LABEL_TIME AS LABEL_TIME," - "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," - "TAPE.LAST_READ_TIME AS LAST_READ_TIME," - "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," - "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," - "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," - "TAPE.USER_COMMENT AS USER_COMMENT," - "TAPE.TAPE_STATE AS TAPE_STATE," - "TAPE.STATE_REASON AS STATE_REASON," - "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," - "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," - "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " - "INNER JOIN LOGICAL_LIBRARY ON " - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " - "INNER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "VID = :VID"; - - common::dataStructures::VidToTapeMap vidToTapeMap; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); - - if(vidToTapeMap.size() != 1) { - exception::Exception ex; - ex.getMessage() << "Not all tapes were found: expected=1 actual=" << vidToTapeMap.size(); - throw ex; - } - return vidToTapeMap; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapesByVid (set of VIDs) -//------------------------------------------------------------------------------ -common::dataStructures::VidToTapeMap RdbmsCatalogue::getTapesByVid(const std::set<std::string> &vids) const { - try { - common::dataStructures::VidToTapeMap vidToTapeMap; - - if(vids.empty()) return vidToTapeMap; - - static const std::string selectTapesBy100VidsSql = getSelectTapesBy100VidsSql(); - - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(selectTapesBy100VidsSql); - uint64_t vidNb = 1; - - for(const auto &vid: vids) { - // Bind the current tape VID - std::ostringstream paramName; - paramName << ":V" << vidNb; - stmt.bindString(paramName.str(), vid); - - // If the 100th tape VID has not yet been reached - if(100 > vidNb) { - vidNb++; - } else { // The 100th VID has been reached - vidNb = 1; - - // Execute the query and collect the results - executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); - - // Create a new statement - stmt = conn.createStmt(selectTapesBy100VidsSql); - } - } - - // If there is a statement under construction - if(1 != vidNb) { - // Bind the remaining parameters with last tape VID. This has no effect - // on the search results but makes the statement valid. - const std::string &lastVid = *vids.rbegin(); - while(100 >= vidNb) { - std::ostringstream paramName; - paramName << ":V" << vidNb; - stmt.bindString(paramName.str(), lastVid); - vidNb++; - } - - // Execute the query and collect the results - executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); - } - - if(vids.size() != vidToTapeMap.size()) { - exception::Exception ex; - ex.getMessage() << "Not all tapes were found: expected=" << vids.size() << " actual=" << vidToTapeMap.size(); - throw ex; - } - - return vidToTapeMap; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getSelectTapesBy100VidsSql -//------------------------------------------------------------------------------ -std::string RdbmsCatalogue::getSelectTapesBy100VidsSql() const { - std::stringstream sql; - - sql << - "SELECT " - "TAPE.VID AS VID," - "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," - "TAPE.VENDOR AS VENDOR," - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," - "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," - "TAPE.LAST_FSEQ AS LAST_FSEQ," - "TAPE.IS_FULL AS IS_FULL," - "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," - - "TAPE.LABEL_FORMAT AS LABEL_FORMAT," - - "TAPE.LABEL_DRIVE AS LABEL_DRIVE," - "TAPE.LABEL_TIME AS LABEL_TIME," - - "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," - "TAPE.LAST_READ_TIME AS LAST_READ_TIME," - - "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," - "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," - - "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," - "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," - - "TAPE.USER_COMMENT AS USER_COMMENT," - - "TAPE.TAPE_STATE AS TAPE_STATE," - "TAPE.STATE_REASON AS STATE_REASON," - "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," - "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," - - "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "TAPE " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " - "INNER JOIN LOGICAL_LIBRARY ON " - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " - "INNER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "WHERE " - "VID IN (:V1"; - - for(uint32_t i=2; i<=100; i++) { - sql << ",:V" << i; - } - - sql << ")"; - - return sql.str(); -} - -//------------------------------------------------------------------------------ -// executeGetTapesByVidStmtAndCollectResults -//------------------------------------------------------------------------------ -void RdbmsCatalogue::executeGetTapesByVidStmtAndCollectResults(rdbms::Stmt &stmt, - common::dataStructures::VidToTapeMap &vidToTapeMap) const { - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::Tape tape; - - tape.vid = rset.columnString("VID"); - tape.mediaType = rset.columnString("MEDIA_TYPE"); - tape.vendor = rset.columnString("VENDOR"); - tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); - tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); - tape.vo = rset.columnString("VO"); - 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.full = rset.columnBool("IS_FULL"); - tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); - - tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), "[RdbmsCatalogue::executeGetTapesByVidsStmtAndCollectResults()]"); - - 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.readMountCount = rset.columnUint64("READ_MOUNT_COUNT"); - tape.writeMountCount = rset.columnUint64("WRITE_MOUNT_COUNT"); - auto optionalComment = rset.columnOptionalString("USER_COMMENT"); - tape.comment = optionalComment ? optionalComment.value() : ""; - - tape.setState(rset.columnString("TAPE_STATE")); - tape.stateReason = rset.columnOptionalString("STATE_REASON"); - tape.stateUpdateTime = rset.columnUint64("STATE_UPDATE_TIME"); - tape.stateModifiedBy = rset.columnString("STATE_MODIFIED_BY"); - - tape.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - tape.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - tape.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - tape.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - tape.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - tape.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - vidToTapeMap[tape.vid] = tape; - } -} - -//------------------------------------------------------------------------------ -// getVidToLogicalLibrary -//------------------------------------------------------------------------------ -std::map<std::string, std::string> RdbmsCatalogue::getVidToLogicalLibrary(const std::set<std::string> &vids) const { - try { - std::map<std::string, std::string> vidToLogicalLibrary; - - if(vids.empty()) return vidToLogicalLibrary; - - static const std::string sql = getSelectVidToLogicalLibraryBy100Sql(); - - auto conn = m_connPool.getConn(); - - auto stmt = conn.createStmt(sql); - uint64_t vidNb = 1; - - for(const auto &vid: vids) { - // Bind the current tape VID - std::ostringstream paramName; - paramName << ":V" << vidNb; - stmt.bindString(paramName.str(), vid); - - // If the 100th tape VID has not yet been reached - if(100 > vidNb) { - vidNb++; - } else { // The 100th VID has been reached - vidNb = 1; - - // Execute the query and collect the results - executeGetVidToLogicalLibraryBy100StmtAndCollectResults(stmt, vidToLogicalLibrary); - - // Create a new statement - stmt = conn.createStmt(sql); - } - } - - // If there is a statement under construction - if(1 != vidNb) { - // Bind the remaining parameters with last tape VID. This has no effect - // on the search results but makes the statement valid. - const std::string &lastVid = *vids.rbegin(); - while(100 >= vidNb) { - std::ostringstream paramName; - paramName << ":V" << vidNb; - stmt.bindString(paramName.str(), lastVid); - vidNb++; - } - - // Execute the query and collect the results - executeGetVidToLogicalLibraryBy100StmtAndCollectResults(stmt, vidToLogicalLibrary); - } - - if(vids.size() != vidToLogicalLibrary.size()) { - exception::Exception ex; - ex.getMessage() << "Not all tapes were found: expected=" << vids.size() << " actual=" << - vidToLogicalLibrary.size(); - throw ex; - } - - return vidToLogicalLibrary; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// getSelectVidToLogicalLibraryBy100Sql -//------------------------------------------------------------------------------ -std::string RdbmsCatalogue::getSelectVidToLogicalLibraryBy100Sql() const { - std::stringstream sql; - - sql << - "SELECT" "\n" - "TAPE.VID AS VID," "\n" - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME" "\n" - "FROM" "\n" - "TAPE" "\n" - "INNER JOIN LOGICAL_LIBRARY ON" "\n" - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID" "\n" - "WHERE" "\n" - "VID IN (:V1"; - - for(uint32_t i=2; i<=100; i++) { - sql << ",:V" << i; - } - - sql << ")"; - - return sql.str(); -} - -//------------------------------------------------------------------------------ -// executeGetVidToLogicalLibraryBy100StmtAndCollectResults -//------------------------------------------------------------------------------ -void RdbmsCatalogue::executeGetVidToLogicalLibraryBy100StmtAndCollectResults(rdbms::Stmt &stmt, -std::map<std::string, std::string> &vidToLogicalLibrary) const { - auto rset = stmt.executeQuery(); - while (rset.next()) { - vidToLogicalLibrary[rset.columnString("VID")] = rset.columnString("LOGICAL_LIBRARY_NAME"); - } -} - -//------------------------------------------------------------------------------ -// getNbFilesOnTape -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getNbFilesOnTape(const std::string& vid) const { - try { - auto conn = m_connPool.getConn(); - return getNbFilesOnTape(conn, vid); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -//getNbFilesOnTape -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getNbFilesOnTape(rdbms::Conn& conn, const std::string& vid) const { - try { - const char *const sql = - "SELECT COUNT(*) AS NB_FILES FROM TAPE_FILE " - "WHERE VID = :VID "; - - auto stmt = conn.createStmt(sql); - - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - rset.next(); - return rset.columnUint64("NB_FILES"); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -//deleteTapeFiles -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTapeFiles(rdbms::Conn& conn, const std::string& vid) const { - try { - const char * const sql = - "DELETE FROM TAPE_FILE WHERE VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - setTapeDirty(conn,vid); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -//setTapeDirty -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeDirty(rdbms::Conn& conn, const std::string& vid) const { - try { - const char * const sql = - "UPDATE TAPE SET DIRTY='1' WHERE VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -//setTapeDirty -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeDirty(rdbms::Conn& conn, const uint64_t & archiveFileId) const { - try { - const char * const sql = - "UPDATE TAPE SET DIRTY='1' " - "WHERE VID IN " - " (SELECT DISTINCT TAPE_FILE.VID AS VID FROM TAPE_FILE WHERE TAPE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID)"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -//resetTapeCounters -//------------------------------------------------------------------------------ -void RdbmsCatalogue::resetTapeCounters(rdbms::Conn& conn, const common::dataStructures::SecurityIdentity& admin, const std::string& vid) const { - try { - const time_t now = time(nullptr); - const char * const sql = - "UPDATE TAPE SET " - "DATA_IN_BYTES = 0," - "MASTER_DATA_IN_BYTES = 0," - "LAST_FSEQ = 0," - "NB_MASTER_FILES = 0," - "NB_COPY_NB_1 = 0," - "COPY_NB_1_IN_BYTES = 0," - "NB_COPY_NB_GT_1 = 0," - "COPY_NB_GT_1_IN_BYTES = 0," - "IS_FULL = '0'," - "IS_FROM_CASTOR = '0'," - "VERIFICATION_STATUS = :VERIFICATION_STATUS," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME," - "DIRTY = '0' " - "WHERE " - "VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VERIFICATION_STATUS", std::nullopt); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - } catch (exception::Exception &ex){ - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// reclaimTape -//------------------------------------------------------------------------------ -void RdbmsCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, cta::log::LogContext & lc) { - using namespace common::dataStructures; - try{ - log::TimingList tl; - utils::Timer t; - auto conn = m_connPool.getConn(); - - TapeSearchCriteria searchCriteria; - searchCriteria.vid = vid; - const auto tapes = getTapes(conn, searchCriteria); - tl.insertAndReset("getTapesTime", t); - - if (tapes.empty()) { - throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist"); - } else if (tapes.front().state != Tape::State::ACTIVE && tapes.front().state != Tape::State::DISABLED) { - throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not on ACTIVE or DISABLED state"); - } else if (!tapes.front().full) { - throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not FULL"); - } - - // The tape exists and is full, we can try to reclaim it - if (this->getNbFilesOnTape(conn, vid) == 0) { - tl.insertAndReset("getNbFilesOnTape", t); - // There is no files on the tape, we can reclaim it : delete the files and reset the counters - deleteFilesFromRecycleLog(conn, vid, lc); - tl.insertAndReset("deleteFileFromRecycleLogTime", t); - resetTapeCounters(conn, admin, vid); - tl.insertAndReset("resetTapeCountersTime", t); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid); - spc.add("host", admin.host); - spc.add("username", admin.username); - tl.addToLog(spc); - lc.log(log::INFO, "In RdbmsCatalogue::reclaimTape(), tape reclaimed."); - } else { - throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because there is at least one tape" - " file in the catalogue that is on the tape"); - } - } catch (exception::UserError& ue) { - throw; - } - catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// checkTapeForLabel -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkTapeForLabel(const std::string &vid) { - try{ - auto conn = m_connPool.getConn(); - - TapeSearchCriteria searchCriteria; - searchCriteria.vid = vid; - const auto tapes = getTapes(conn, searchCriteria); - - if(tapes.empty()) { - throw exception::UserError(std::string("Cannot label tape ") + vid + - " because it does not exist"); - } - //The tape exists checks any files on it - const uint64_t nbFilesOnTape = getNbFilesOnTape(conn, vid); - if( 0 != nbFilesOnTape) { - throw exception::UserError(std::string("Cannot label tape ") + vid + - " because it has " + - std::to_string(nbFilesOnTape) + - " file(s)"); - } - } catch (exception::UserError& ue) { - throw; - } - catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapeLogFromRset -//------------------------------------------------------------------------------ -std::optional<common::dataStructures::TapeLog> RdbmsCatalogue::getTapeLogFromRset(const rdbms::Rset &rset, - const std::string &driveColName, const std::string &timeColName) const { - try { - const std::optional<std::string> drive = rset.columnOptionalString(driveColName); - const std::optional<uint64_t> time = rset.columnOptionalUint64(timeColName); - - if(!drive && !time) { - return std::nullopt; - } - - if(drive && !time) { - throw exception::Exception(std::string("Database column ") + driveColName + " contains " + drive.value() + - " but column " + timeColName + " is nullptr"); - } - - if(time && !drive) { - throw exception::Exception(std::string("Database column ") + timeColName + " contains " + - std::to_string(time.value()) + " but column " + driveColName + " is nullptr"); - } - - common::dataStructures::TapeLog tapeLog; - tapeLog.drive = drive.value(); - tapeLog.time = time.value(); - - return tapeLog; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeMediaType -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &mediaType) { - try { - auto conn = m_connPool.getConn(); - if(!mediaTypeExists(conn, mediaType)){ - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the media type " + mediaType + " does not exist"); - } - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "MEDIA_TYPE_ID = (SELECT MEDIA_TYPE_ID FROM MEDIA_TYPE WHERE MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE)," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":MEDIA_TYPE", mediaType); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("mediaType", mediaType) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - mediaType"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeVendor -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &vendor) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "VENDOR = :VENDOR," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VENDOR", vendor); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("vendor", vendor) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - vendor"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeLogicalLibraryName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &logicalLibraryName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "LOGICAL_LIBRARY_ID = " - "(SELECT LOGICAL_LIBRARY_ID FROM LOGICAL_LIBRARY WHERE LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME)," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - if(!logicalLibraryExists(conn,logicalLibraryName)){ - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the logical library " + logicalLibraryName + " does not exist"); - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or logical library " + - logicalLibraryName + " does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("logicalLibraryName", logicalLibraryName) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - logicalLibraryName"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeTapePoolName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &tapePoolName) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "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 " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - if(!tapePoolExists(conn,tapePoolName)){ - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the tape pool " + tapePoolName + " does not exist"); - } - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", tapePoolName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or tape pool " + - tapePoolName + " does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("tapePoolName", tapePoolName) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - tapePoolName"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeEncryptionKeyName -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &encryptionKeyName) { - try { - std::optional<std::string> optionalEncryptionKeyName; - if(!encryptionKeyName.empty()) { - optionalEncryptionKeyName = encryptionKeyName; - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "ENCRYPTION_KEY_NAME = :ENCRYPTION_KEY_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":ENCRYPTION_KEY_NAME", optionalEncryptionKeyName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("encryptionKeyName", optionalEncryptionKeyName ? optionalEncryptionKeyName.value() : "NULL") - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - encryptionKeyName"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyTapeVerificationStatus -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string &verificationStatus) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "VERIFICATION_STATUS = :VERIFICATION_STATUS," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - if (verificationStatus.empty()) { - stmt.bindString(":VERIFICATION_STATUS", std::nullopt); - } else { - stmt.bindString(":VERIFICATION_STATUS", verificationStatus); - } - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("verificationStatus", verificationStatus) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - verificationStatus"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// modifyTapeState -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, const common::dataStructures::Tape::State & state, const std::optional<common::dataStructures::Tape::State> & prev_state, const std::optional<std::string> & stateReason){ - try { - using namespace common::dataStructures; - const time_t now = time(nullptr); - - const std::optional<std::string> stateReasonCopy = stateReason && cta::utils::trimString(stateReason.value()).empty() ? std::nullopt : stateReason; - checkCommentOrReasonMaxLength(stateReasonCopy); - - std::string stateStr; - try { - stateStr = cta::common::dataStructures::Tape::stateToString(state); - } catch(cta::exception::Exception & ex){ - std::string errorMsg = "The state provided in parameter (" + std::to_string(state) + ") is not known or has not been initialized existing states are:" + common::dataStructures::Tape::getAllPossibleStates(); - throw UserSpecifiedANonExistentTapeState(errorMsg); - } - - std::string prevStateStr; - if (prev_state.has_value()) { - try { - prevStateStr = cta::common::dataStructures::Tape::stateToString(prev_state.value()); - } catch (cta::exception::Exception &ex) { - std::string errorMsg = "The previous state provided in parameter (" + std::to_string(prev_state.value()) + ") is not known or has not been initialized existing states are:" + common::dataStructures::Tape::getAllPossibleStates(); - throw UserSpecifiedANonExistentTapeState(errorMsg); - } - } - - //Check the reason is set for all the status except the ACTIVE one, this is the only state that allows the reason to be set to null. - if(state != Tape::State::ACTIVE){ - if(!stateReasonCopy){ - throw UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive(std::string("Cannot modify the state of the tape ") + vid + " to " + stateStr + " because the reason has not been provided."); - } - } - - std::string sql = - "UPDATE TAPE SET " - "TAPE_STATE = :TAPE_STATE," - "STATE_REASON = :STATE_REASON," - "STATE_UPDATE_TIME = :STATE_UPDATE_TIME," - "STATE_MODIFIED_BY = :STATE_MODIFIED_BY " - "WHERE " - "VID = :VID"; - - if (prev_state.has_value()) { - sql += " AND TAPE_STATE = :PREV_TAPE_STATE"; - } - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - stmt.bindString(":TAPE_STATE", stateStr); - stmt.bindString(":STATE_REASON", stateReasonCopy); - stmt.bindUint64(":STATE_UPDATE_TIME", now); - stmt.bindString(":STATE_MODIFIED_BY",generateTapeStateModifiedBy(admin)); - stmt.bindString(":VID",vid); - if (prev_state.has_value()) { - stmt.bindString(":PREV_TAPE_STATE",prevStateStr); - } - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentTape(std::string("Cannot modify the state of the tape ") + vid + " because it does not exist or because a recent state change has been detected"); - } - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::string RdbmsCatalogue::generateTapeStateModifiedBy(const common::dataStructures::SecurityIdentity & admin){ - return admin.username + "@" + admin.host; -} - -//------------------------------------------------------------------------------ -// tapeMountedForArchive -//------------------------------------------------------------------------------ -void RdbmsCatalogue::tapeMountedForArchive(const std::string &vid, const std::string &drive) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "LAST_WRITE_DRIVE = :LAST_WRITE_DRIVE," - "LAST_WRITE_TIME = :LAST_WRITE_TIME, " - "WRITE_MOUNT_COUNT = WRITE_MOUNT_COUNT + 1 " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":LAST_WRITE_DRIVE", drive); - stmt.bindUint64(":LAST_WRITE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("lastWriteDrive", drive) - .add("lastWriteTime", now); - lc.log(log::INFO, "Catalogue - system modified tape - mountedForArchive"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapeMountedForRetrieve -//------------------------------------------------------------------------------ -void RdbmsCatalogue::tapeMountedForRetrieve(const std::string &vid, const std::string &drive) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "LAST_READ_DRIVE = :LAST_READ_DRIVE," - "LAST_READ_TIME = :LAST_READ_TIME, " - "READ_MOUNT_COUNT = READ_MOUNT_COUNT + 1 " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":LAST_READ_DRIVE", drive); - stmt.bindUint64(":LAST_READ_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("lastReadDrive", drive) - .add("lastReadTime", now); - lc.log(log::INFO, "Catalogue - system modified tape - mountedForRetrieve"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeFull -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, - const bool fullValue) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "IS_FULL = :IS_FULL," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindBool(":IS_FULL", fullValue); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("isFull", fullValue ? 1 : 0) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - isFull"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeDirty -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, - const bool dirtyValue) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "DIRTY = :DIRTY," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindBool(":DIRTY", dirtyValue); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("dirty", dirtyValue ? 1 : 0) - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - dirty"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// noSpaceLeftOnTape -//------------------------------------------------------------------------------ -void RdbmsCatalogue::noSpaceLeftOnTape(const std::string &vid) { - try { - const char *const sql = - "UPDATE TAPE SET " - "IS_FULL = '1' " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::Exception(std::string("Tape ") + vid + " does not exist"); - } - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("isFull", 1) - .add("method", "noSpaceLeftOnTape"); - lc.log(log::INFO, "Catalogue - system modified tape - isFull"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeIsFromCastorInUnitTests -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeIsFromCastorInUnitTests(const std::string &vid) { - try { - const char *const sql = - "UPDATE TAPE SET " - "IS_FROM_CASTOR = '1' " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::Exception(std::string("Tape ") + vid + " does not exist"); - } - - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("isFromCastor", 1) - .add("method", "setTapeIsFromCastorInUnitTests"); - lc.log(log::INFO, "Catalogue - system modified tape - isFromCastor"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeDisabled -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string & reason) { - - try { - modifyTapeState(admin,vid,common::dataStructures::Tape::DISABLED,std::nullopt,reason); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeRepackingDisabled -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::string & reason) { - - try { - modifyTapeState(admin,vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,reason); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::setTapeDirty(const std::string& vid) { - try { - auto conn = m_connPool.getConn(); - setTapeDirty(conn,vid); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// modifyTapeComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &vid, const std::optional<std::string> &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("vid", vid) - .add("userComment", comment ? comment.value() : "") - .add("lastUpdateUserName", admin.username) - .add("lastUpdateHostName", admin.host) - .add("lastUpdateTime", now); - lc.log(log::INFO, "Catalogue - user modified tape - userComment"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesterActivityMountRulePolicy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_ACTIVITY_MOUNT_RULE SET " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME AND " - "ACTIVITY_REGEX = :ACTIVITY_REGEX"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":ACTIVITY_REGEX", activityRegex); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester activity mount rule ") + instanceName + ":" + - requesterName + "for activities matching " + activityRegex + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesterActivityMountRuleComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_ACTIVITY_MOUNT_RULE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME AND " - "ACTIVITY_REGEX = :ACTIVITY_REGEX"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":ACTIVITY_REGEX", activityRegex); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester activity mount rule ") + instanceName + ":" + - requesterName + "for activities matching " + activityRegex + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesterMountRulePolicy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_MOUNT_RULE SET " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" + - requesterName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesteMountRuleComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterName, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_MOUNT_RULE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" + - requesterName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesterGroupMountRulePolicy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_GROUP_MOUNT_RULE SET " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" + - requesterGroupName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyRequesterGroupMountRuleComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE REQUESTER_GROUP_MOUNT_RULE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", instanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" + - requesterGroupName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createMountPolicy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createMountPolicy(const common::dataStructures::SecurityIdentity &admin, const CreateMountPolicyAttributes & mountPolicy) { - std::string name = mountPolicy.name; - try { - checkCommentOrReasonMaxLength(mountPolicy.comment); - auto conn = m_connPool.getConn(); - if (mountPolicyExists(conn, name)) { - throw exception::UserError(std::string("Cannot create mount policy ") + name + - " because a mount policy with the same name already exists"); - } - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO MOUNT_POLICY(" - "MOUNT_POLICY_NAME," - - "ARCHIVE_PRIORITY," - "ARCHIVE_MIN_REQUEST_AGE," - - "RETRIEVE_PRIORITY," - "RETRIEVE_MIN_REQUEST_AGE," - - "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(" - ":MOUNT_POLICY_NAME," - - ":ARCHIVE_PRIORITY," - ":ARCHIVE_MIN_REQUEST_AGE," - - ":RETRIEVE_PRIORITY," - ":RETRIEVE_MIN_REQUEST_AGE," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":MOUNT_POLICY_NAME", name); - - stmt.bindUint64(":ARCHIVE_PRIORITY", mountPolicy.archivePriority); - stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", mountPolicy.minArchiveRequestAge); - - stmt.bindUint64(":RETRIEVE_PRIORITY", mountPolicy.retrievePriority); - stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", mountPolicy.minRetrieveRequestAge); - - stmt.bindString(":USER_COMMENT", mountPolicy.comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// createRequesterActivityMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createRequesterActivityMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &activityRegex, - const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - auto conn = m_connPool.getConn(); - if(requesterActivityMountRuleExists(conn, diskInstanceName, requesterName, activityRegex)) { - throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + - " because that requester-activity mount rule already exists"); - } - if(!mountPolicyExists(conn, mountPolicyName)) { - throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + - " because mount-policy " + mountPolicyName + " does not exist"); - } - if(!diskInstanceExists(conn, diskInstanceName)) { - throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + - " because disk-instance " + diskInstanceName + " does not exist"); - } - - const uint64_t now = time(nullptr); - const char *const sql = - "INSERT INTO REQUESTER_ACTIVITY_MOUNT_RULE(" - "DISK_INSTANCE_NAME," - "REQUESTER_NAME," - "MOUNT_POLICY_NAME," - "ACTIVITY_REGEX," - - "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(" - ":DISK_INSTANCE_NAME," - ":REQUESTER_NAME," - ":MOUNT_POLICY_NAME," - ":ACTIVITY_REGEX," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); - stmt.bindString(":ACTIVITY_REGEX", activityRegex); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_userMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// getRequesterMountRules -//------------------------------------------------------------------------------ -std::list<common::dataStructures::RequesterActivityMountRule> RdbmsCatalogue::getRequesterActivityMountRules() const { - try { - std::list<common::dataStructures::RequesterActivityMountRule> rules; - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "REQUESTER_NAME AS REQUESTER_NAME," - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "ACTIVITY_REGEX AS ACTIVITY_REGEX," - - "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 " - "FROM " - "REQUESTER_ACTIVITY_MOUNT_RULE " - "ORDER BY " - "DISK_INSTANCE_NAME, REQUESTER_NAME, ACTIVITY_REGEX, MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while(rset.next()) { - common::dataStructures::RequesterActivityMountRule rule; - - rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - rule.name = rset.columnString("REQUESTER_NAME"); - rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); - rule.activityRegex = rset.columnString("ACTIVITY_REGEX"); - rule.comment = rset.columnString("USER_COMMENT"); - rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - rules.push_back(rule); - } - - return rules; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteRequesterActivityMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) { - try { - const char *const sql = - "DELETE FROM " - "REQUESTER_ACTIVITY_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME AND " - "ACTIVITY_REGEX = :ACTIVITY_REGEX"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":ACTIVITY_REGEX", activityRegex); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete mount rule for requester ") + diskInstanceName + ":" + requesterName + - " and activity regex " + activityRegex + " because the rule does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_userMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// createRequesterMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createRequesterMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const auto user = User(diskInstanceName, requesterName); - auto conn = m_connPool.getConn(); - const auto mountPolicy = getRequesterMountPolicy(conn, user); - if(mountPolicy) { - throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + - " because the requester is already assigned to mount-policy " + mountPolicy->name); - } - if(!mountPolicyExists(conn, mountPolicyName)) { - throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + " because mount-policy " + mountPolicyName + - " does not exist"); - } - if(!diskInstanceExists(conn, diskInstanceName)) { - throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + - " to requester " + diskInstanceName + ":" + requesterName + " because disk-instance " + diskInstanceName + - " does not exist"); - } - - const uint64_t now = time(nullptr); - const char *const sql = - "INSERT INTO REQUESTER_MOUNT_RULE(" - "DISK_INSTANCE_NAME," - "REQUESTER_NAME," - "MOUNT_POLICY_NAME," - - "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(" - ":DISK_INSTANCE_NAME," - ":REQUESTER_NAME," - ":MOUNT_POLICY_NAME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_userMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// getRequesterMountRules -//------------------------------------------------------------------------------ -std::list<common::dataStructures::RequesterMountRule> RdbmsCatalogue::getRequesterMountRules() const { - try { - std::list<common::dataStructures::RequesterMountRule> rules; - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "REQUESTER_NAME AS REQUESTER_NAME," - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "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 " - "FROM " - "REQUESTER_MOUNT_RULE " - "ORDER BY " - "DISK_INSTANCE_NAME, REQUESTER_NAME, MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while(rset.next()) { - common::dataStructures::RequesterMountRule rule; - - rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - rule.name = rset.columnString("REQUESTER_NAME"); - rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); - rule.comment = rset.columnString("USER_COMMENT"); - rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - rules.push_back(rule); - } - - return rules; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteRequesterMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) { - try { - const char *const sql = - "DELETE FROM " - "REQUESTER_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete mount rule for requester ") + diskInstanceName + ":" + requesterName + - " because the rule does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_userMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// createRequesterGroupMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createRequesterGroupMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstanceName, - const std::string &requesterGroupName, - const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - auto conn = m_connPool.getConn(); - { - const auto group = Group(diskInstanceName, requesterGroupName); - const auto mountPolicy = getRequesterGroupMountPolicy(conn, group); - if (mountPolicy) { - throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + - " to requester-group " + diskInstanceName + ":" + requesterGroupName + - " because a rule already exists assigning the requester-group to mount-policy " + - mountPolicy->name); - } - } - if(!mountPolicyExists(conn, mountPolicyName)) { - throw exception::UserError(std::string("Cannot assign mount-policy ") + mountPolicyName + " to requester-group " + - diskInstanceName + ":" + requesterGroupName + " because mount-policy " + mountPolicyName + " does not exist"); - } - if(!diskInstanceExists(conn, diskInstanceName)) { - throw exception::UserError(std::string("Cannot assign mount-policy ") + mountPolicyName + " to requester-group " + - diskInstanceName + ":" + requesterGroupName + " because disk-instance " + diskInstanceName + " does not exist"); - } - - const uint64_t now = time(nullptr); - const char *const sql = - "INSERT INTO REQUESTER_GROUP_MOUNT_RULE(" - "DISK_INSTANCE_NAME," - "REQUESTER_GROUP_NAME," - "MOUNT_POLICY_NAME," - - "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(" - ":DISK_INSTANCE_NAME," - ":REQUESTER_GROUP_NAME," - ":MOUNT_POLICY_NAME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// getCachedRequesterGroupMountPolicy -//------------------------------------------------------------------------------ -ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy> > RdbmsCatalogue::getCachedRequesterGroupMountPolicy(const Group &group) - const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getRequesterGroupMountPolicy(conn, group); - }; - return m_groupMountPolicyCache.getCachedValue(group, getNonCachedValue); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getRequesterGroupMountPolicy -//------------------------------------------------------------------------------ -std::optional<common::dataStructures::MountPolicy> RdbmsCatalogue::getRequesterGroupMountPolicy( - rdbms::Conn &conn, const Group &group) const { - try { - const char *const sql = - "SELECT " - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "MOUNT_POLICY " - "INNER JOIN " - "REQUESTER_GROUP_MOUNT_RULE " - "ON " - "MOUNT_POLICY.MOUNT_POLICY_NAME = REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", group.diskInstanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", group.groupName); - auto rset = stmt.executeQuery(); - if(rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - - policy.comment = rset.columnString("USER_COMMENT"); - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - return policy; - } else { - return std::nullopt; - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getRequesterGroupMountRules -//------------------------------------------------------------------------------ -std::list<common::dataStructures::RequesterGroupMountRule> RdbmsCatalogue::getRequesterGroupMountRules() const { - try { - std::list<common::dataStructures::RequesterGroupMountRule> rules; - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "REQUESTER_GROUP_NAME AS REQUESTER_GROUP_NAME," - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "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 " - "FROM " - "REQUESTER_GROUP_MOUNT_RULE " - "ORDER BY " - "DISK_INSTANCE_NAME, REQUESTER_GROUP_NAME, MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while(rset.next()) { - common::dataStructures::RequesterGroupMountRule rule; - - rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - rule.name = rset.columnString("REQUESTER_GROUP_NAME"); - rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); - - rule.comment = rset.columnString("USER_COMMENT"); - rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - rules.push_back(rule); - } - - return rules; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteRequesterGroupMountRule -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteRequesterGroupMountRule(const std::string &diskInstanceName, - const std::string &requesterGroupName) { - try { - const char *const sql = - "DELETE FROM " - "REQUESTER_GROUP_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete the mount rule for requester group ") + diskInstanceName + ":" + - requesterGroupName + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// mountPolicyExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName) const { - try { - const char *const sql = - "SELECT " - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME " - "FROM " - "MOUNT_POLICY " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// requesterMountRuleExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, - const std::string &requesterName) const { - try { - const char *const sql = - "SELECT " - "REQUESTER_NAME AS REQUESTER_NAME " - "FROM " - "REQUESTER_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getCachedRequesterMountPolicy -//------------------------------------------------------------------------------ -ValueAndTimeBasedCacheInfo <std::optional <common::dataStructures::MountPolicy> > RdbmsCatalogue::getCachedRequesterMountPolicy(const User &user) const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getRequesterMountPolicy(conn, user); - }; - return m_userMountPolicyCache.getCachedValue(user, getNonCachedValue); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getRequesterMountPolicy -//------------------------------------------------------------------------------ -std::optional<common::dataStructures::MountPolicy> RdbmsCatalogue::getRequesterMountPolicy(rdbms::Conn &conn, - const User &user) const { - try { - const char *const sql = - "SELECT " - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "MOUNT_POLICY " - "INNER JOIN " - "REQUESTER_MOUNT_RULE " - "ON " - "MOUNT_POLICY.MOUNT_POLICY_NAME = REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", user.diskInstanceName); - stmt.bindString(":REQUESTER_NAME", user.username); - auto rset = stmt.executeQuery(); - if(rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - - policy.comment = rset.columnString("USER_COMMENT"); - - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - common::dataStructures::EntryLog updateLog; - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - return policy; - } else { - return std::nullopt; - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// requesterActivityMountRuleExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::requesterActivityMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " - "REQUESTER_NAME AS REQUESTER_NAME, " - "ACTIVITY_REGEX AS ACTIVITY_REGEX " - "FROM " - "REQUESTER_ACTIVITY_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_NAME = :REQUESTER_NAME AND " - "ACTIVITY_REGEX = :ACTIVITY_REGEX"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":ACTIVITY_REGEX", activityRegex); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// requesterGroupMountRuleExists -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, - const std::string &requesterGroupName) const { - try { - const char *const sql = - "SELECT " - "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " - "REQUESTER_GROUP_NAME AS REQUESTER_GROUP_NAME " - "FROM " - "REQUESTER_GROUP_MOUNT_RULE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteMountPolicy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteMountPolicy(const std::string &name) { - try { - const char *const sql = "DELETE FROM MOUNT_POLICY WHERE MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot delete mount policy ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// getMountPolicies -//------------------------------------------------------------------------------ -std::list<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicies() const { - try { - auto conn = m_connPool.getConn(); - return getMountPolicies(conn); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMountPolicies -//------------------------------------------------------------------------------ -std::list<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicies(rdbms::Conn & conn) const { -try { - std::list<common::dataStructures::MountPolicy> policies; - const char *const sql = - "SELECT " - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - - "RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - - "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 " - "FROM " - "MOUNT_POLICY " - "ORDER BY " - "MOUNT_POLICY_NAME"; - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - - policy.comment = rset.columnString("USER_COMMENT"); - - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - policies.push_back(policy); - } - return policies; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMountPolicy -//------------------------------------------------------------------------------ -std::optional<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicy(const std::string &mountPolicyName) const { - try { - auto conn = m_connPool.getConn(); - return getMountPolicy(conn, mountPolicyName); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMountPolicy -//------------------------------------------------------------------------------ -std::optional<common::dataStructures::MountPolicy> RdbmsCatalogue::getMountPolicy(rdbms::Conn &conn, const std::string &mountPolicyName) const { - try { - const char *const sql = - "SELECT " - "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - - "ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - - "RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - - "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 " - "FROM " - "MOUNT_POLICY " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); - auto rset = stmt.executeQuery(); - if (rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - - policy.comment = rset.columnString("USER_COMMENT"); - - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - return policy; - } - return std::nullopt; - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getCachedMountPolicies -//------------------------------------------------------------------------------ -std::list<common::dataStructures::MountPolicy> RdbmsCatalogue::getCachedMountPolicies() const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getMountPolicies(conn); - }; - return m_allMountPoliciesCache.getCachedValue("all",getNonCachedValue).value; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// modifyMountPolicyArchivePriority -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t archivePriority) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MOUNT_POLICY SET " - "ARCHIVE_PRIORITY = :ARCHIVE_PRIORITY," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_PRIORITY", archivePriority); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// modifyMountPolicyArchiveMinRequestAge -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t minArchiveRequestAge) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MOUNT_POLICY SET " - "ARCHIVE_MIN_REQUEST_AGE = :ARCHIVE_MIN_REQUEST_AGE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// modifyMountPolicyRetrievePriority -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t retrievePriority) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MOUNT_POLICY SET " - "RETRIEVE_PRIORITY = :RETRIEVE_PRIORITY," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":RETRIEVE_PRIORITY", retrievePriority); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// modifyMountPolicyRetrieveMinRequestAge -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t minRetrieveRequestAge) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MOUNT_POLICY SET " - "RETRIEVE_MIN_REQUEST_AGE = :RETRIEVE_MIN_REQUEST_AGE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - -//------------------------------------------------------------------------------ -// modifyMountPolicyComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE MOUNT_POLICY SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":MOUNT_POLICY_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - - m_groupMountPolicyCache.invalidate(); - m_userMountPolicyCache.invalidate(); - m_allMountPoliciesCache.invalidate(); -} - - -//------------------------------------------------------------------------------ -// createDiskSystem -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createDiskSystem( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &diskInstanceName, - const std::string &diskInstanceSpaceName, - const std::string &fileRegexp, - const uint64_t targetedFreeSpace, - const time_t sleepTime, - const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot create disk system because the name is an empty string"); - } - if(fileRegexp.empty()) { - throw UserSpecifiedAnEmptyStringFileRegexp("Cannot create disk system because the file regexp is an empty string"); - } - if(diskInstanceName.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create disk system because the disk instance name is an empty string"); - } - if(diskInstanceSpaceName.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot create disk system because the disk instance space name is an empty string"); - } - if(0 == targetedFreeSpace) { - throw UserSpecifiedAZeroTargetedFreeSpace("Cannot create disk system because the targeted free space is zero"); - } - if (0 == sleepTime) { - throw UserSpecifiedAZeroSleepTime("Cannot create disk system because the sleep time is zero"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create disk system because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - auto conn = m_connPool.getConn(); - if(diskSystemExists(conn, name)) { - throw exception::UserError(std::string("Cannot create disk system ") + name + - " because a disk system with the same name identifier already exists"); - } - - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO DISK_SYSTEM(" - "DISK_SYSTEM_NAME," - "DISK_INSTANCE_NAME," - "DISK_INSTANCE_SPACE_NAME," - "FILE_REGEXP," - "TARGETED_FREE_SPACE," - "SLEEP_TIME," - - "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(" - ":DISK_SYSTEM_NAME," - ":DISK_INSTANCE_NAME," - ":DISK_INSTANCE_SPACE_NAME," - ":FILE_REGEXP," - ":TARGETED_FREE_SPACE," - ":SLEEP_TIME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", diskInstanceSpaceName); - stmt.bindString(":FILE_REGEXP", fileRegexp); - stmt.bindUint64(":TARGETED_FREE_SPACE", targetedFreeSpace); - stmt.bindUint64(":SLEEP_TIME", sleepTime); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteDiskSystem -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteDiskSystem(const std::string &name) { - try { - const char *const delete_sql = - "DELETE " - "FROM " - "DISK_SYSTEM " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - // The delete statement will effect no rows and will not raise an error if - // either the tape does not exist or if it still has tape files - if(0 == stmt.getNbAffectedRows()) { - if(diskSystemExists(conn, name)) { - throw UserSpecifiedANonEmptyDiskSystemAfterDelete(std::string("Cannot delete disk system ") + name + " for unknown reason"); - } else { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot delete disk system ") + name + " because it does not exist"); - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getAllDiskSystems -//------------------------------------------------------------------------------ -disk::DiskSystemList RdbmsCatalogue::getAllDiskSystems() const { - try { - disk::DiskSystemList diskSystemList; - const std::string sql = - "SELECT " - "DISK_SYSTEM.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," - "DISK_SYSTEM.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "DISK_SYSTEM.DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME," - "DISK_SYSTEM.FILE_REGEXP AS FILE_REGEXP," - "DISK_SYSTEM.TARGETED_FREE_SPACE AS TARGETED_FREE_SPACE," - "DISK_SYSTEM.SLEEP_TIME AS SLEEP_TIME," - - "DISK_SYSTEM.USER_COMMENT AS USER_COMMENT," - - "DISK_SYSTEM.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "DISK_SYSTEM.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "DISK_SYSTEM.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "DISK_SYSTEM.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "DISK_SYSTEM.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "DISK_SYSTEM.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," - - "DISK_INSTANCE_SPACE.FREE_SPACE_QUERY_URL AS FREE_SPACE_QUERY_URL," - "DISK_INSTANCE_SPACE.REFRESH_INTERVAL AS REFRESH_INTERVAL," - "DISK_INSTANCE_SPACE.LAST_REFRESH_TIME AS LAST_REFRESH_TIME," - "DISK_INSTANCE_SPACE.FREE_SPACE AS FREE_SPACE " - "FROM " - "DISK_SYSTEM " - "INNER JOIN DISK_INSTANCE_SPACE ON " - "DISK_SYSTEM.DISK_INSTANCE_NAME = DISK_INSTANCE_SPACE.DISK_INSTANCE_NAME " - "AND " - "DISK_SYSTEM.DISK_INSTANCE_SPACE_NAME = DISK_INSTANCE_SPACE.DISK_INSTANCE_SPACE_NAME" - ; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - auto rset = stmt.executeQuery(); - while (rset.next()) { - disk::DiskSystem diskSystem; - diskSystem.name = rset.columnString("DISK_SYSTEM_NAME"); - diskSystem.fileRegexp = rset.columnString("FILE_REGEXP"); - diskSystem.targetedFreeSpace = rset.columnUint64("TARGETED_FREE_SPACE"); - diskSystem.sleepTime = rset.columnUint64("SLEEP_TIME"); - diskSystem.comment = rset.columnString("USER_COMMENT"); - diskSystem.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - diskSystem.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - diskSystem.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - diskSystem.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - diskSystem.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - diskSystem.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - diskSystem.diskInstanceSpace.freeSpaceQueryURL = rset.columnString("FREE_SPACE_QUERY_URL"); - diskSystem.diskInstanceSpace.refreshInterval = rset.columnUint64("REFRESH_INTERVAL"); - diskSystem.diskInstanceSpace.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - diskSystem.diskInstanceSpace.name = rset.columnString("DISK_INSTANCE_SPACE_NAME"); - diskSystem.diskInstanceSpace.lastRefreshTime = rset.columnUint64("LAST_REFRESH_TIME"); - diskSystem.diskInstanceSpace.freeSpace = rset.columnUint64("FREE_SPACE"); - diskSystemList.push_back(diskSystem); - } - return diskSystemList; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &fileRegexp) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(fileRegexp.empty()) { - throw UserSpecifiedAnEmptyStringFileRegexp("Cannot modify disk system " - "because the new fileRegexp is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "FILE_REGEXP = :FILE_REGEXP," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":FILE_REGEXP", fileRegexp); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t targetedFreeSpace) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(0 == targetedFreeSpace) { - throw UserSpecifiedAZeroTargetedFreeSpace("Cannot modify disk system " - "because the new targeted free space has zero value"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "TARGETED_FREE_SPACE = :TARGETED_FREE_SPACE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":TARGETED_FREE_SPACE", targetedFreeSpace); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot modify disk system " - "because the new comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceName) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(diskInstanceName.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot modify disk system " - "because the new comment is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceSpaceName) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(diskInstanceSpaceName.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot modify disk system " - "because the new comment is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", diskInstanceSpaceName); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - - -//------------------------------------------------------------------------------ -// modifyDiskSystemSleepTime -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, const std::string& name, - const uint64_t sleepTime) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" - " because the disk system name is an empty string"); - } - if(sleepTime == 0) { - throw UserSpecifiedAZeroSleepTime("Cannot modify disk system " - "because the new sleep time is zero"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_SYSTEM SET " - "SLEEP_TIME = :SLEEP_TIME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":SLEEP_TIME", sleepTime); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_SYSTEM_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createDiskInstance -//------------------------------------------------------------------------------ -void RdbmsCatalogue::createDiskInstance( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create disk system because the name is an empty string"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create disk system because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - auto conn = m_connPool.getConn(); - if(diskInstanceExists(conn, name)) { - throw exception::UserError(std::string("Cannot create disk instance ") + name + - " because a disk instance with the same name identifier already exists"); - } - - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO DISK_INSTANCE(" - "DISK_INSTANCE_NAME," - - "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(" - ":DISK_INSTANCE_NAME," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_INSTANCE_NAME", name); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getAllDiskInstances -//------------------------------------------------------------------------------ -std::list<common::dataStructures::DiskInstance> RdbmsCatalogue::getAllDiskInstances() const { - try { - std::list<common::dataStructures::DiskInstance> diskInstanceList; - std::string sql = - "SELECT " - "DISK_INSTANCE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - - "DISK_INSTANCE.USER_COMMENT AS USER_COMMENT," - - "DISK_INSTANCE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "DISK_INSTANCE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "DISK_INSTANCE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "DISK_INSTANCE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "DISK_INSTANCE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "DISK_INSTANCE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "DISK_INSTANCE"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::DiskInstance diskInstance; - diskInstance.name = rset.columnString("DISK_INSTANCE_NAME"); - diskInstance.comment = rset.columnString("USER_COMMENT"); - diskInstance.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - diskInstance.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - diskInstance.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - diskInstance.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - diskInstance.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - diskInstance.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - diskInstanceList.push_back(diskInstance); - } - return diskInstanceList; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteDiskInstance -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteDiskInstance(const std::string &name) { - try { - const char *const delete_sql = - "DELETE " - "FROM " - "DISK_INSTANCE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DISK_INSTANCE_NAME", name); - stmt.executeNonQuery(); - - // The delete statement will effect no rows and will not raise an error if - // either the tape does not exist or if it still has tape files - if(0 == stmt.getNbAffectedRows()) { - if(diskInstanceExists(conn, name)) { - throw UserSpecifiedANonEmptyDiskInstanceAfterDelete(std::string("Cannot delete disk instance ") + name + " for unknown reason"); - } else { - throw UserSpecifiedANonExistentDiskInstance(std::string("Cannot delete disk instance ") + name + " because it does not exist"); - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyDiskInstanceComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) { - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot modify disk instance" - " because the disk instance name is an empty string"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot modify disk instance " - "because the new comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_INSTANCE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskInstance(std::string("Cannot modify disk instance ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} -//------------------------------------------------------------------------------ -// createDiskInstanceSpace -//------------------------------------------------------------------------------ - void RdbmsCatalogue::createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL, - const uint64_t refreshInterval, const std::string &comment) { - - try { - if(name.empty()) { - throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot create disk instance space because the name is an empty string"); - } - if(freeSpaceQueryURL.empty()) { - throw UserSpecifiedAnEmptyStringFreeSpaceQueryURL("Cannot create disk instance space because the free space query URL is an empty string"); - } - if(0 == refreshInterval) { - throw UserSpecifiedAZeroRefreshInterval("Cannot create disk instance space because the refresh interval is zero"); - } - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot create disk instance space because the comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - - auto conn = m_connPool.getConn(); - if(!diskInstanceExists(conn, diskInstance)) { - throw exception::UserError(std::string("Cannot create disk instance space ") + name + - " for disk instance " + diskInstance + - " because the disk instance does not exist"); - } - - if (diskInstanceSpaceExists(conn, name, diskInstance)) { - throw exception::UserError(std::string("Cannot create disk instance space ") + name + - " for disk instance " + diskInstance + - " because a disk instance space with the same name and disk instance already exists"); - } - - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO DISK_INSTANCE_SPACE(" - "DISK_INSTANCE_NAME," - "DISK_INSTANCE_SPACE_NAME," - "FREE_SPACE_QUERY_URL," - "REFRESH_INTERVAL," - "LAST_REFRESH_TIME," - "FREE_SPACE," - - "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(" - ":DISK_INSTANCE_NAME," - ":DISK_INSTANCE_SPACE_NAME," - ":FREE_SPACE_QUERY_URL," - ":REFRESH_INTERVAL," - ":LAST_REFRESH_TIME," - ":FREE_SPACE," - - ":USER_COMMENT," - - ":CREATION_LOG_USER_NAME," - ":CREATION_LOG_HOST_NAME," - ":CREATION_LOG_TIME," - - ":LAST_UPDATE_USER_NAME," - ":LAST_UPDATE_HOST_NAME," - ":LAST_UPDATE_TIME)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.bindString(":FREE_SPACE_QUERY_URL", freeSpaceQueryURL); - stmt.bindUint64(":REFRESH_INTERVAL", refreshInterval); - stmt.bindUint64(":LAST_REFRESH_TIME", 0); - stmt.bindUint64(":FREE_SPACE", 0); - - stmt.bindString(":USER_COMMENT", comment); - - stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); - stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); - stmt.bindUint64(":CREATION_LOG_TIME", now); - - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getAllDiskInstanceSpaces -//------------------------------------------------------------------------------ -std::list<common::dataStructures::DiskInstanceSpace> RdbmsCatalogue::getAllDiskInstanceSpaces() const { - try { - std::list<common::dataStructures::DiskInstanceSpace> diskInstanceSpaceList; - std::string sql = - "SELECT " - "DISK_INSTANCE_SPACE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "DISK_INSTANCE_SPACE.DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME," - "DISK_INSTANCE_SPACE.FREE_SPACE_QUERY_URL AS FREE_SPACE_QUERY_URL," - "DISK_INSTANCE_SPACE.REFRESH_INTERVAL AS REFRESH_INTERVAL," - "DISK_INSTANCE_SPACE.LAST_REFRESH_TIME AS LAST_REFRESH_TIME," - "DISK_INSTANCE_SPACE.FREE_SPACE AS FREE_SPACE," - - "DISK_INSTANCE_SPACE.USER_COMMENT AS USER_COMMENT," - - "DISK_INSTANCE_SPACE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "DISK_INSTANCE_SPACE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "DISK_INSTANCE_SPACE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - - "DISK_INSTANCE_SPACE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "DISK_INSTANCE_SPACE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "DISK_INSTANCE_SPACE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "DISK_INSTANCE_SPACE"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - auto rset = stmt.executeQuery(); - while (rset.next()) { - common::dataStructures::DiskInstanceSpace diskInstanceSpace; - diskInstanceSpace.name = rset.columnString("DISK_INSTANCE_SPACE_NAME"); - diskInstanceSpace.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - diskInstanceSpace.freeSpaceQueryURL = rset.columnString("FREE_SPACE_QUERY_URL"); - diskInstanceSpace.refreshInterval = rset.columnUint64("REFRESH_INTERVAL"); - diskInstanceSpace.freeSpace = rset.columnUint64("FREE_SPACE"); - diskInstanceSpace.lastRefreshTime = rset.columnUint64("LAST_REFRESH_TIME"); - diskInstanceSpace.comment = rset.columnString("USER_COMMENT"); - diskInstanceSpace.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - diskInstanceSpace.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - diskInstanceSpace.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - diskInstanceSpace.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - diskInstanceSpace.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - diskInstanceSpace.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - diskInstanceSpaceList.push_back(diskInstanceSpace); - } - return diskInstanceSpaceList; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteDiskInstanceSpace -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) { - try { - const char *const delete_sql = - "DELETE " - "FROM " - "DISK_INSTANCE_SPACE " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.executeNonQuery(); - - // The delete statement will effect no rows and will not raise an error if - // either the tape does not exist or if it still has tape files - if(0 == stmt.getNbAffectedRows()) { - if(diskInstanceSpaceExists(conn, name, diskInstance)) { - throw UserSpecifiedANonEmptyDiskInstanceSpaceAfterDelete(std::string("Cannot delete disk instance space") + name + " for unknown reason"); - } else { - throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot delete disk instance space ") + name + " because it does not exist"); - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyDiskInstanceSpaceQueryURL -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) { - try { - if(freeSpaceQueryURL.empty()) { - throw UserSpecifiedAnEmptyStringFreeSpaceQueryURL("Cannot modify disk instance space " - "because the new freeSpaceQueryURL is an empty string"); - } - - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_INSTANCE_SPACE SET " - "FREE_SPACE_QUERY_URL = :FREE_SPACE_QUERY_URL," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":FREE_SPACE_QUERY_URL", freeSpaceQueryURL); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyDiskInstanceSpaceComment -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &comment) { - try { - if(comment.empty()) { - throw UserSpecifiedAnEmptyStringComment("Cannot modify disk instance space " - "because the new comment is an empty string"); - } - checkCommentOrReasonMaxLength(comment); - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_INSTANCE_SPACE SET " - "USER_COMMENT = :USER_COMMENT," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":USER_COMMENT", comment); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// modifyDiskInstanceSpaceRefreshInterval -//------------------------------------------------------------------------------ -void RdbmsCatalogue::modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) { - try { - if(0 == refreshInterval) { - throw UserSpecifiedAZeroRefreshInterval("Cannot modify disk instance space " - "because the new refreshInterval is zero"); - } - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_INSTANCE_SPACE SET " - "REFRESH_INTERVAL = :REFRESH_INTERVAL," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":REFRESH_INTERVAL", refreshInterval); - stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); - stmt.bindUint64(":LAST_UPDATE_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyDiskInstanceSpaceFreeSpace(const std::string &name, const std::string &diskInstance, const uint64_t freeSpace) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE DISK_INSTANCE_SPACE SET " - "FREE_SPACE = :FREE_SPACE," - "LAST_REFRESH_TIME = :LAST_REFRESH_TIME " - "WHERE " - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "AND " - "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":FREE_SPACE", freeSpace); - stmt.bindUint64(":LAST_REFRESH_TIME", now); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// insertArchiveFile -//------------------------------------------------------------------------------ -void RdbmsCatalogue::insertArchiveFile(rdbms::Conn &conn, const ArchiveFileRowWithoutTimestamps &row) { - try { - if(!storageClassExists(conn, row.storageClassName)) { - throw exception::UserError(std::string("Storage class ") + row.diskInstance + ":" + row.storageClassName + - " does not exist"); - } - - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO ARCHIVE_FILE(" - "ARCHIVE_FILE_ID," - "DISK_INSTANCE_NAME," - "DISK_FILE_ID," - "DISK_FILE_UID," - "DISK_FILE_GID," - "SIZE_IN_BYTES," - "CHECKSUM_BLOB," - "CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - "CREATION_TIME," - "RECONCILIATION_TIME)" - "SELECT " - ":ARCHIVE_FILE_ID," - ":DISK_INSTANCE_NAME," - ":DISK_FILE_ID," - ":DISK_FILE_UID," - ":DISK_FILE_GID," - ":SIZE_IN_BYTES," - ":CHECKSUM_BLOB," - ":CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - ":CREATION_TIME," - ":RECONCILIATION_TIME " - "FROM " - "STORAGE_CLASS " - "WHERE " - "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - - stmt.bindUint64(":ARCHIVE_FILE_ID", row.archiveFileId); - stmt.bindString(":DISK_INSTANCE_NAME", row.diskInstance); - stmt.bindString(":DISK_FILE_ID", row.diskFileId); - stmt.bindUint64(":DISK_FILE_UID", row.diskFileOwnerUid); - stmt.bindUint64(":DISK_FILE_GID", row.diskFileGid); - stmt.bindUint64(":SIZE_IN_BYTES", row.size); - stmt.bindBlob (":CHECKSUM_BLOB", row.checksumBlob.serialize()); - // Keep transition ADLER32 checksum up-to-date if it exists - uint32_t adler32; - try { - std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(row.checksumBlob.at(checksum::ADLER32)); - adler32 = strtoul(adler32hex.c_str(), 0, 16); - } catch(exception::ChecksumTypeMismatch &ex) { - adler32 = 0; - } - stmt.bindUint64(":CHECKSUM_ADLER32", adler32); - stmt.bindString(":STORAGE_CLASS_NAME", row.storageClassName); - stmt.bindUint64(":CREATION_TIME", now); - stmt.bindUint64(":RECONCILIATION_TIME", now); - - stmt.executeNonQuery(); - } catch (exception::UserError &) { - throw; - } catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + " failed: archiveFileId=" + std::to_string(row.archiveFileId) + - ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// checkTapeFileSearchCriteria -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkTapeFileSearchCriteria(const TapeFileSearchCriteria &searchCriteria) const { - auto conn = m_connPool.getConn(); - checkTapeFileSearchCriteria(conn, searchCriteria); - -} - -//------------------------------------------------------------------------------ -// checkTapeFileSearchCriteria -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkTapeFileSearchCriteria(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const { - if(searchCriteria.archiveFileId) { - if(!archiveFileIdExists(conn, searchCriteria.archiveFileId.value())) { - throw exception::UserError(std::string("Archive file with ID ") + - std::to_string(searchCriteria.archiveFileId.value()) + " does not exist"); - } - } - - if(searchCriteria.diskFileIds && !searchCriteria.diskInstance) { - throw exception::UserError(std::string("Disk file IDs are ambiguous without disk instance name")); - } - - if (searchCriteria.fSeq && !searchCriteria.vid) { - throw exception::UserError(std::string("fSeq makes no sense without vid")); - } - - if(searchCriteria.vid) { - if(!tapeExists(conn, searchCriteria.vid.value())) { - throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist"); - } - } -} - -//------------------------------------------------------------------------------ -// getArchiveFilesItor -//------------------------------------------------------------------------------ -Catalogue::ArchiveFileItor RdbmsCatalogue::getArchiveFilesItor(const TapeFileSearchCriteria &searchCriteria) const { - - checkTapeFileSearchCriteria(searchCriteria); - - // If this is the listing of the contents of a tape - if (!searchCriteria.archiveFileId && !searchCriteria.diskInstance && !searchCriteria.diskFileIds && - !searchCriteria.fSeq && searchCriteria.vid) { - return getTapeContentsItor(searchCriteria.vid.value()); - } - - try { - // Create a connection to populate the temporary table (specialised by database type) - auto conn = m_archiveFileListingConnPool.getConn(); - 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); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFilesItor -//------------------------------------------------------------------------------ -Catalogue::ArchiveFileItor RdbmsCatalogue::getArchiveFilesItor(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const { - - checkTapeFileSearchCriteria(conn, searchCriteria); - - // If this is the listing of the contents of a tape - if (!searchCriteria.archiveFileId && !searchCriteria.diskInstance && !searchCriteria.diskFileIds && - searchCriteria.vid) { - return getTapeContentsItor(searchCriteria.vid.value()); - } - - try { - auto archiveListingConn = m_archiveFileListingConnPool.getConn(); - const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(archiveListingConn, searchCriteria.diskFileIds); - // Pass ownership of the connection to the Iterator object - auto impl = new RdbmsCatalogueGetArchiveFilesItor(m_log, std::move(archiveListingConn), searchCriteria, tempDiskFxidsTableName); - return ArchiveFileItor(impl); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapeContentsItor -//------------------------------------------------------------------------------ -Catalogue::ArchiveFileItor RdbmsCatalogue::getTapeContentsItor(const std::string &vid) - const { - try { - // Create a connection to populate the temporary table (specialised by database type) - auto impl = new RdbmsCatalogueTapeContentsItor(m_log, m_connPool, vid); - return ArchiveFileItor(impl); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// checkRecycleTapeFileSearchCriteria -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkRecycleTapeFileSearchCriteria(cta::rdbms::Conn &conn, const RecycleTapeFileSearchCriteria & searchCriteria) const { - if(searchCriteria.vid) { - if(!tapeExists(conn, searchCriteria.vid.value())) { - throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist"); - } - } -} - -Catalogue::FileRecycleLogItor RdbmsCatalogue::getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const { - try { - 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; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreArchiveFileInRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::restoreArchiveFileInRecycleLog(rdbms::Conn &conn, - const cta::common::dataStructures::FileRecycleLog &fileRecycleLog, const std::string &newFid, log::LogContext & lc) { - cta::catalogue::ArchiveFileRowWithoutTimestamps row; - row.diskFileId = newFid; - row.archiveFileId = fileRecycleLog.archiveFileId; - row.checksumBlob = fileRecycleLog.checksumBlob; - row.diskFileOwnerUid = fileRecycleLog.diskFileUid; - row.diskFileGid = fileRecycleLog.diskFileGid; - row.diskInstance = fileRecycleLog.diskInstanceName; - row.size = fileRecycleLog.sizeInBytes; - row.storageClassName = fileRecycleLog.storageClassName; - insertArchiveFile(conn, row); -} - -//------------------------------------------------------------------------------ -// restoreFilesInRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, const std::string &newFid) { - try { - auto fileRecycleLogitor = getFileRecycleLogItor(searchCriteria); - auto conn = m_connPool.getConn(); - log::LogContext lc(m_log); - restoreEntryInRecycleLog(conn, fileRecycleLogitor, newFid, lc); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getFilesForRepack -//------------------------------------------------------------------------------ -std::list<common::dataStructures::ArchiveFile> RdbmsCatalogue::getFilesForRepack( - const std::string &vid, - const uint64_t startFSeq, - const uint64_t maxNbFiles) const { - try { - std::string sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID " - "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 " - "ORDER BY FSEQ"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.bindUint64(":START_FSEQ", startFSeq); - auto rset = stmt.executeQuery(); - - std::list<common::dataStructures::ArchiveFile> archiveFiles; - while(rset.next()) { - common::dataStructures::ArchiveFile archiveFile; - - archiveFile.archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - archiveFile.diskFileId = rset.columnString("DISK_FILE_ID"); - archiveFile.diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); - archiveFile.diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); - archiveFile.fileSize = rset.columnUint64("SIZE_IN_BYTES"); - archiveFile.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - archiveFile.storageClass = rset.columnString("STORAGE_CLASS_NAME"); - archiveFile.creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile.reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = rset.columnString("VID"); - tapeFile.fSeq = rset.columnUint64("FSEQ"); - tapeFile.blockId = rset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = rset.columnUint64("COPY_NB"); - tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile.checksumBlob; // Duplicated for convenience - - archiveFile.tapeFiles.push_back(tapeFile); - - archiveFiles.push_back(archiveFile); - - if(maxNbFiles == archiveFiles.size()) break; - } - return archiveFiles; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileItorForRepack -//------------------------------------------------------------------------------ -Catalogue::ArchiveFileItor RdbmsCatalogue::getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const { - try { - auto impl = new RdbmsCatalogueGetArchiveFilesForRepackItor(m_log, m_archiveFileListingConnPool, vid, startFSeq); - return ArchiveFileItor(impl); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapeFileSummary -// -// NOTE: As "archivefile ls" has been deprecated, there is no longer a way for -// operators to request a tape file summary. (Use "tape ls" instead). -// This method is used exclusively by the unit tests. -//------------------------------------------------------------------------------ -common::dataStructures::ArchiveFileSummary RdbmsCatalogue::getTapeFileSummary( - const TapeFileSearchCriteria &searchCriteria) const -{ - try { - auto conn = m_connPool.getConn(); - - std::string sql = - "SELECT " - "COALESCE(SUM(ARCHIVE_FILE.SIZE_IN_BYTES), 0) AS TOTAL_BYTES," - "COUNT(ARCHIVE_FILE.ARCHIVE_FILE_ID) AS TOTAL_FILES " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; - - const bool thereIsAtLeastOneSearchCriteria = - searchCriteria.archiveFileId || - searchCriteria.diskInstance || - searchCriteria.vid || - searchCriteria.diskFileIds; - - if(thereIsAtLeastOneSearchCriteria) { - sql += " WHERE "; - } - - bool addedAWhereConstraint = false; - - if(searchCriteria.archiveFileId) { - sql += " ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - addedAWhereConstraint = true; - } - if(searchCriteria.diskInstance) { - if(addedAWhereConstraint) sql += " AND "; - sql += "ARCHIVE_FILE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; - addedAWhereConstraint = true; - } - if(searchCriteria.vid) { - if(addedAWhereConstraint) sql += " AND "; - sql += "TAPE_FILE.VID = :VID"; - addedAWhereConstraint = true; - } - if(searchCriteria.diskFileIds) { - const auto tempDiskFxidsTableName = createAndPopulateTempTableFxid(conn, searchCriteria.diskFileIds); - - if(addedAWhereConstraint) sql += " AND "; - sql += "ARCHIVE_FILE.DISK_FILE_ID IN (SELECT DISK_FILE_ID FROM " + tempDiskFxidsTableName + ")"; - addedAWhereConstraint = true; - } - - auto stmt = conn.createStmt(sql); - if(searchCriteria.archiveFileId) { - stmt.bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value()); - } - if(searchCriteria.diskInstance) { - stmt.bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value()); - } - if(searchCriteria.vid) { - stmt.bindString(":VID", searchCriteria.vid.value()); - } - auto rset = stmt.executeQuery(); - - if(!rset.next()) { - throw exception::Exception("SELECT COUNT statement did not return a row"); - } - - common::dataStructures::ArchiveFileSummary summary; - summary.totalBytes = rset.columnUint64("TOTAL_BYTES"); - summary.totalFiles = rset.columnUint64("TOTAL_FILES"); - return summary; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileForDeletion -//------------------------------------------------------------------------------ -common::dataStructures::ArchiveFile RdbmsCatalogue::getArchiveFileForDeletion(const TapeFileSearchCriteria &criteria) const { - if (!criteria.diskFileIds && !criteria.archiveFileId) { - throw exception::UserError("To delete a file copy either the diskFileId+diskInstanceName or archiveFileId must be specified"); - } - if (criteria.diskFileIds && !criteria.diskInstance) { - throw exception::UserError("DiskFileId makes no sense without disk instance"); - } - if (!criteria.vid) { - throw exception::UserError("Vid must be specified"); - } - - auto vid = criteria.vid.value(); - TapeFileSearchCriteria searchCriteria = criteria; - searchCriteria.vid = std::nullopt; //unset vid, we want to get all copies of the archive file so we can check that it is not a one copy file - auto itor = getArchiveFilesItor(searchCriteria); - - // itor should have at most one archive file since we always search on unique attributes - if (!itor.hasMore()) { - if (criteria.archiveFileId) { - throw exception::UserError(std::string("Cannot delete a copy of the file with archiveFileId ") + - std::to_string(criteria.archiveFileId.value()) + - " because the file does not exist"); - } else { - throw exception::UserError(std::string("Cannot delete a copy of the file with eosFxid ") + - criteria.diskFileIds.value().front() + " and diskInstance " + - criteria.diskInstance.value() + " because the file does not exist"); - } - } - - cta::common::dataStructures::ArchiveFile af = itor.next(); - - if (af.tapeFiles.size() == 1) { - if (criteria.archiveFileId) { - throw exception::UserError(std::string("Cannot delete a copy of the file with archiveFileId ") + - std::to_string(criteria.archiveFileId.value()) + - " because it is the only copy"); - } else { - throw exception::UserError(std::string("Cannot delete a copy of the file with eosFxid ") + - criteria.diskFileIds.value().front() + " and diskInstance " + - criteria.diskInstance.value() + " because it is the only copy"); - } - } - af.tapeFiles.removeAllVidsExcept(vid); // assume there is only one copy per vid, this should return a list with at most one item - if (af.tapeFiles.empty()) { - if (criteria.archiveFileId) { - throw exception::UserError(std::string("No copy of the file with archiveFileId ") + - std::to_string(criteria.archiveFileId.value()) + - " on vid " + vid); - } else { - throw exception::UserError(std::string("No copy of the file with eosFxid ") + - criteria.diskFileIds.value().front() + " and diskInstance " + - criteria.diskInstance.value() + " on vid " + vid); - } - } - if (af.tapeFiles.size() > 1){ - if (criteria.archiveFileId) { - throw exception::UserError(std::string("Error: More than one copy of the file with archiveFileId ") + - std::to_string(criteria.archiveFileId.value()) + - " on vid " + vid); - } else { - throw exception::UserError(std::string("Error: More than one copy of the file with eosFxid ") + - criteria.diskFileIds.value().front() + " and diskInstance " + - criteria.diskInstance.value() + " on vid " + vid); - } - } - return af; -} - - -//------------------------------------------------------------------------------ -// deleteTapeFileCopy -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) { - - log::LogContext lc(m_log); - auto conn = m_connPool.getConn(); - copyTapeFileToFileRecyleLogAndDelete(conn, file, reason, lc); -} - - -//------------------------------------------------------------------------------ -// getArchiveFileById -//------------------------------------------------------------------------------ -common::dataStructures::ArchiveFile RdbmsCatalogue::getArchiveFileById(const uint64_t id) const { - try { - auto conn = m_connPool.getConn(); - const auto archiveFile = getArchiveFileById(conn, id); - - // Throw an exception if the archive file does not exist - if(nullptr == archiveFile.get()) { - exception::Exception ex; - ex.getMessage() << "No such archive file with ID " << id; - throw (ex); - } - - return *archiveFile; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileById -//------------------------------------------------------------------------------ -std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileById(rdbms::Conn &conn, - const uint64_t id) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " - "ORDER BY " - "TAPE_FILE.CREATION_TIME ASC"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", id); - auto rset = stmt.executeQuery(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - while (rset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file - if(!rset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = rset.columnString("VID"); - tapeFile.fSeq = rset.columnUint64("FSEQ"); - tapeFile.blockId = rset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = rset.columnUint64("COPY_NB"); - tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - return archiveFile; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// tapeLabelled -//------------------------------------------------------------------------------ -void RdbmsCatalogue::tapeLabelled(const std::string &vid, const std::string &drive) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "LABEL_DRIVE = :LABEL_DRIVE," - "LABEL_TIME = :LABEL_TIME " - "WHERE " - "VID = :VID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":LABEL_DRIVE", drive); - stmt.bindUint64(":LABEL_TIME", now); - stmt.bindString(":VID", vid); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// checkAndGetNextArchiveFileId -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::checkAndGetNextArchiveFileId(const std::string &diskInstanceName, - const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { - try { - const auto storageClass = StorageClass(storageClassName); - const auto copyToPoolMap = getCachedTapeCopyToPoolMap(storageClass); - const auto expectedNbRoutes = getCachedExpectedNbArchiveRoutes(storageClass); - - // Check that the number of archive routes is correct - if(copyToPoolMap.empty()) { - exception::UserError ue; - ue.getMessage() << "Storage class " << storageClassName << " has no archive routes"; - throw ue; - } - if(copyToPoolMap.size() != expectedNbRoutes) { - exception::UserError ue; - ue.getMessage() << "Storage class " << storageClassName << " does not have the" - " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" << - copyToPoolMap.size(); - throw ue; - } - - const auto userMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, user.name)); - const auto userMountPolicy = userMountPolicyAndCacheInfo.value; - // Only consider the requester's group if there is no user mount policy - if(!userMountPolicy) { - const auto groupMountPolicyAndCacheInfo = getCachedRequesterGroupMountPolicy(Group(diskInstanceName, user.group)); - const auto groupMountPolicy = groupMountPolicyAndCacheInfo.value; - - if(!groupMountPolicy) { - - const auto defaultUserMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, "default")); - const auto defaultUserMountPolicy = defaultUserMountPolicyAndCacheInfo.value; - - if(!defaultUserMountPolicy) { - exception::UserErrorWithCacheInfo ue(userMountPolicyAndCacheInfo.cacheInfo); - ue.getMessage() << "Failed to check and get next archive file ID: No mount rules: storageClass=" << - storageClassName << " requester=" << diskInstanceName << ":" << user.name << ":" << user.group; - throw ue; - } - } - } - - // Now that we have found both the archive routes and the mount policy it's - // safe to consume an archive file identifier - { - auto conn = m_connPool.getConn(); - return getNextArchiveFileId(conn); - } - } catch(exception::UserErrorWithCacheInfo &ue) { - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("cacheInfo", ue.cacheInfo) - .add("userError", ue.getMessage().str()); - lc.log(log::INFO, "Catalogue::checkAndGetNextArchiveFileId caught a UserErrorWithCacheInfo"); - throw; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileQueueCriteria -//------------------------------------------------------------------------------ -common::dataStructures::ArchiveFileQueueCriteria RdbmsCatalogue::getArchiveFileQueueCriteria( - const std::string &diskInstanceName, - const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { - try { - const StorageClass storageClass = StorageClass(storageClassName); - const common::dataStructures::TapeCopyToPoolMap copyToPoolMap = getCachedTapeCopyToPoolMap(storageClass); - const uint64_t expectedNbRoutes = getCachedExpectedNbArchiveRoutes(storageClass); - - // Check that the number of archive routes is correct - if(copyToPoolMap.empty()) { - exception::UserError ue; - ue.getMessage() << "Storage class " << diskInstanceName << ": " << storageClassName << " has no archive routes"; - throw ue; - } - if(copyToPoolMap.size() != expectedNbRoutes) { - exception::UserError ue; - ue.getMessage() << "Storage class " << diskInstanceName << ": " << storageClassName << " does not have the" - " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" << - copyToPoolMap.size(); - throw ue; - } - - // Get the mount policy - user mount policies overrule group ones - const auto userMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, user.name)); - const auto userMountPolicy = userMountPolicyAndCacheInfo.value; - - if(userMountPolicy) { - return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *userMountPolicy); - } else { - const auto groupMountPolicyAndCacheInfo = getCachedRequesterGroupMountPolicy(Group(diskInstanceName, user.group)); - const auto groupMountPolicy = groupMountPolicyAndCacheInfo.value; - - if(groupMountPolicy) { - return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *groupMountPolicy); - } else { - const auto defaultUserMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, "default")); - const auto defaultUserMountPolicy = defaultUserMountPolicyAndCacheInfo.value; - - if(defaultUserMountPolicy) { - return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *defaultUserMountPolicy); - } else { - exception::UserErrorWithCacheInfo ue(defaultUserMountPolicyAndCacheInfo.cacheInfo); - ue.getMessage() << "Failed to get archive file queue criteria: No mount rules: storageClass=" << - storageClassName << " requester=" << diskInstanceName << ":" << user.name << ":" << user.group; - throw ue; - } - } - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getCachedTapeCopyToPoolMap -//------------------------------------------------------------------------------ -common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getCachedTapeCopyToPoolMap(const StorageClass &storageClass) - const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getTapeCopyToPoolMap(conn, storageClass); - }; - return m_tapeCopyToPoolCache.getCachedValue(storageClass, getNonCachedValue).value; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapeCopyToPoolMap -//------------------------------------------------------------------------------ -common::dataStructures::TapeCopyToPoolMap RdbmsCatalogue::getTapeCopyToPoolMap(rdbms::Conn &conn, - const StorageClass &storageClass) const { - try { - common::dataStructures::TapeCopyToPoolMap copyToPoolMap; - const char *const sql = - "SELECT " - "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," - "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.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClass.storageClassName); - auto rset = stmt.executeQuery(); - while (rset.next()) { - const uint32_t copyNb = rset.columnUint64("COPY_NB"); - const std::string tapePoolName = rset.columnString("TAPE_POOL_NAME"); - copyToPoolMap[copyNb] = tapePoolName; - } - - return copyToPoolMap; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getCachedExpectedNbArchiveRoutes -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getCachedExpectedNbArchiveRoutes(const StorageClass &storageClass) const { - try { - auto getNonCachedValue = [&] { - auto conn = m_connPool.getConn(); - return getExpectedNbArchiveRoutes(conn, storageClass); - }; - return m_expectedNbArchiveRoutesCache.getCachedValue(storageClass, getNonCachedValue).value; - } catch (exception::LostDatabaseConnection &le) { - throw exception::LostDatabaseConnection(std::string(__FUNCTION__) + " failed: " + le.getMessage().str()); - } catch(exception::UserError &) { - throw; - } catch (exception::Exception &ex) { - throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); - } -} - - -//------------------------------------------------------------------------------ -// getExpectedNbArchiveRoutes -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getExpectedNbArchiveRoutes(rdbms::Conn &conn, const StorageClass &storageClass) const { - try { - const char *const sql = - "SELECT " - "COUNT(*) AS NB_ROUTES " - "FROM " - "ARCHIVE_ROUTE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "WHERE " - "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":STORAGE_CLASS_NAME", storageClass.storageClassName); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set of SELECT COUNT(*) is empty"); - } - return rset.columnUint64("NB_ROUTES"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// updateTape -//------------------------------------------------------------------------------ -void RdbmsCatalogue::updateTape( - rdbms::Conn &conn, - const std::string &vid, - const uint64_t lastFSeq, - const uint64_t compressedBytesWritten, - const uint64_t filesWritten, - const std::string &tapeDrive) { - try { - const time_t now = time(nullptr); - const char *const sql = - "UPDATE TAPE SET " - "LAST_FSEQ = :LAST_FSEQ," - "DATA_IN_BYTES = DATA_IN_BYTES + :DATA_IN_BYTES," - "MASTER_DATA_IN_BYTES = MASTER_DATA_IN_BYTES + :MASTER_DATA_IN_BYTES," - "NB_MASTER_FILES = NB_MASTER_FILES + :MASTER_FILES," - "LAST_WRITE_DRIVE = :LAST_WRITE_DRIVE," - "LAST_WRITE_TIME = :LAST_WRITE_TIME " - "WHERE " - "VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.bindUint64(":LAST_FSEQ", lastFSeq); - stmt.bindUint64(":DATA_IN_BYTES", compressedBytesWritten); - stmt.bindUint64(":MASTER_FILES", filesWritten); - stmt.bindUint64(":MASTER_DATA_IN_BYTES", compressedBytesWritten); - stmt.bindString(":LAST_WRITE_DRIVE", tapeDrive); - stmt.bindUint64(":LAST_WRITE_TIME", now); - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// prepareToRetrieveFile -//------------------------------------------------------------------------------ -common::dataStructures::RetrieveFileQueueCriteria RdbmsCatalogue::prepareToRetrieveFile( - const std::string &diskInstanceName, - const uint64_t archiveFileId, - const common::dataStructures::RequesterIdentity &user, - const std::optional<std::string>& activity, - log::LogContext &lc, - const std::optional<std::string> &mountPolicyName) { - try { - cta::utils::Timer t; - common::dataStructures::RetrieveFileQueueCriteria criteria; - { - auto conn = m_connPool.getConn(); - const auto getConnTime = t.secs(utils::Timer::resetCounter); - auto archiveFile = getArchiveFileToRetrieveByArchiveFileId(conn, archiveFileId); - const auto getArchiveFileTime = t.secs(utils::Timer::resetCounter); - if(nullptr == archiveFile.get()) { - exception::UserError ex; - auto tapeFileStateList = getTapeFileStateListForArchiveFileId(conn, archiveFileId); - if (tapeFileStateList.empty()) { - ex.getMessage() << "File with archive file ID " << archiveFileId << " does not exist in CTA namespace"; - throw ex; - } - const auto nonBrokenState = std::find_if(std::begin(tapeFileStateList), std::end(tapeFileStateList), - [](std::pair<std::string, std::string> state) { - return (state.second != "BROKEN") - && (state.second != "BROKEN_PENDING") - && (state.second != "EXPORTED") - && (state.second != "EXPORTED_PENDING"); - }); - - if (nonBrokenState != std::end(tapeFileStateList)) { - ex.getMessage() << "WARNING: File with archive file ID " << archiveFileId << - " exits in CTA namespace but is temporarily unavailable on " << nonBrokenState->second << " tape " << nonBrokenState->first; - throw ex; - } - const auto brokenState = tapeFileStateList.front(); - //All tape files are on broken tapes, just generate an error about the first - ex.getMessage() << "ERROR: File with archive file ID " << archiveFileId << - " exits in CTA namespace but is permanently unavailable on " << brokenState.second << " tape " << brokenState.first; - throw ex; - } - if (mountPolicyName) { - std::optional<common::dataStructures::MountPolicy> mountPolicy = getMountPolicy(conn, mountPolicyName.value()); - if (mountPolicy) { - criteria.archiveFile = *archiveFile; - criteria.mountPolicy = mountPolicy.value(); - return criteria; - } else { - log::ScopedParamContainer spc(lc); - spc.add("mountPolicyName", mountPolicyName.value()) - .add("archiveFileId", archiveFileId); - lc.log(log::WARNING, "Catalogue::prepareToRetrieve Could not find specified mount policy, falling back to querying mount rules"); - } - } - - if(diskInstanceName != archiveFile->diskInstance) { - exception::UserError ue; - ue.getMessage() << "Cannot retrieve file because the disk instance of the request does not match that of the" - " archived file: archiveFileId=" << archiveFileId << - " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << archiveFile->diskInstance; - throw ue; - } - - t.reset(); - RequesterAndGroupMountPolicies mountPolicies; - if (activity) { - mountPolicies = getMountPolicies(conn, diskInstanceName, user.name, user.group, activity.value()); - } else { - mountPolicies = getMountPolicies(conn, diskInstanceName, user.name, user.group); - } - - const auto getMountPoliciesTime = t.secs(utils::Timer::resetCounter); - - log::ScopedParamContainer spc(lc); - spc.add("getConnTime", getConnTime) - .add("getArchiveFileTime", getArchiveFileTime) - .add("getMountPoliciesTime", getMountPoliciesTime); - lc.log(log::INFO, "Catalogue::prepareToRetrieve internal timings"); - - // Requester activity mount policies overrule requester mount policies - // Requester mount policies overrule requester group mount policies - common::dataStructures::MountPolicy mountPolicy; - if (!mountPolicies.requesterActivityMountPolicies.empty()) { - //More than one may match the activity, so choose the one with highest retrieve priority - mountPolicy = *std::max_element(mountPolicies.requesterActivityMountPolicies.begin(), - mountPolicies.requesterActivityMountPolicies.end(), - [](const common::dataStructures::MountPolicy &p1, common::dataStructures::MountPolicy &p2) { - return p1.retrievePriority < p2.retrievePriority; - }); - } else if(!mountPolicies.requesterMountPolicies.empty()) { - mountPolicy = mountPolicies.requesterMountPolicies.front(); - } else if(!mountPolicies.requesterGroupMountPolicies.empty()) { - mountPolicy = mountPolicies.requesterGroupMountPolicies.front(); - } else { - mountPolicies = getMountPolicies(conn, diskInstanceName, "default", user.group); - - if(!mountPolicies.requesterMountPolicies.empty()) { - mountPolicy = mountPolicies.requesterMountPolicies.front(); - } else { - exception::UserError ue; - ue.getMessage() - << "Cannot retrieve file because there are no mount rules for the requester, activity or their group:" - << " archiveFileId=" << archiveFileId << " requester=" << diskInstanceName << ":" << user.name << ":" - << user.group; - if (activity) { - ue.getMessage() << " activity=" << activity.value(); - } - throw ue; - } - } - criteria.archiveFile = *archiveFile; - criteria.mountPolicy = mountPolicy; - } - return criteria; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMountPolicies -//------------------------------------------------------------------------------ -RequesterAndGroupMountPolicies RdbmsCatalogue::getMountPolicies( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &requesterGroupName, - const std::string &activity) const { - try { - const char *const sql = - "SELECT " - "'ACTIVITY' AS RULE_TYPE," - "REQUESTER_ACTIVITY_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," - "REQUESTER_ACTIVITY_MOUNT_RULE.ACTIVITY_REGEX AS ACTIVITY_REGEX," - - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "REQUESTER_ACTIVITY_MOUNT_RULE " - "INNER JOIN " - "MOUNT_POLICY " - "ON " - "REQUESTER_ACTIVITY_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_ACTIVITY_MOUNT_RULE.DISK_INSTANCE_NAME = :ACTIVITY_DISK_INSTANCE_NAME AND " - "REQUESTER_ACTIVITY_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_ACTIVITY_NAME " - "UNION " - "SELECT " - "'REQUESTER' AS RULE_TYPE," - "REQUESTER_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," - "'' AS ACTIVITY_REGEX," - - - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "REQUESTER_MOUNT_RULE " - "INNER JOIN " - "MOUNT_POLICY " - "ON " - "REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :REQUESTER_DISK_INSTANCE_NAME AND " - "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME " - "UNION " - "SELECT " - "'REQUESTER_GROUP' AS RULE_TYPE," - "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME AS ASSIGNEE," - "'' AS ACTIVITY_REGEX," - - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "REQUESTER_GROUP_MOUNT_RULE " - "INNER JOIN " - "MOUNT_POLICY " - "ON " - "REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :GROUP_DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":ACTIVITY_DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_ACTIVITY_NAME", requesterName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - auto rset = stmt.executeQuery(); - - RequesterAndGroupMountPolicies policies; - while(rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - policy.comment = rset.columnString("USER_COMMENT"); - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - if(rset.columnString("RULE_TYPE") == "ACTIVITY") { - auto activityRegexString = rset.columnString("ACTIVITY_REGEX"); - cta::utils::Regex activityRegex(activityRegexString); - if (activityRegex.has_match(activity)) { - policies.requesterActivityMountPolicies.push_back(policy); - } - } else if(rset.columnString("RULE_TYPE") == "REQUESTER") { - policies.requesterMountPolicies.push_back(policy); - } else { - policies.requesterGroupMountPolicies.push_back(policy); - } - } - - return policies; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMountPolicies -//------------------------------------------------------------------------------ -RequesterAndGroupMountPolicies RdbmsCatalogue::getMountPolicies( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &requesterGroupName) const { - try { - const char *const sql = - "SELECT " - "'REQUESTER' AS RULE_TYPE," - "REQUESTER_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," - - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "REQUESTER_MOUNT_RULE " - "INNER JOIN " - "MOUNT_POLICY " - "ON " - "REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :REQUESTER_DISK_INSTANCE_NAME AND " - "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME " - "UNION " - "SELECT " - "'REQUESTER_GROUP' AS RULE_TYPE," - "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME AS ASSIGNEE," - - "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," - "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," - "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," - "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," - "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," - "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " - "FROM " - "REQUESTER_GROUP_MOUNT_RULE " - "INNER JOIN " - "MOUNT_POLICY " - "ON " - "REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " - "WHERE " - "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :GROUP_DISK_INSTANCE_NAME AND " - "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":REQUESTER_NAME", requesterName); - stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); - auto rset = stmt.executeQuery(); - - RequesterAndGroupMountPolicies policies; - while(rset.next()) { - common::dataStructures::MountPolicy policy; - - policy.name = rset.columnString("MOUNT_POLICY_NAME"); - policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); - policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); - policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); - policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); - policy.comment = rset.columnString("USER_COMMENT"); - policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); - policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); - policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); - policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); - policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); - policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); - - if(rset.columnString("RULE_TYPE") == "REQUESTER") { - policies.requesterMountPolicies.push_back(policy); - } else { - policies.requesterGroupMountPolicies.push_back(policy); - } - } - - return policies; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// isAdmin -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::isAdmin(const common::dataStructures::SecurityIdentity &admin) const { - try { - return isCachedAdmin(admin); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// isCachedAdmin -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::isCachedAdmin(const common::dataStructures::SecurityIdentity &admin) - const { - try { - auto getNonCachedValue = [&] { - return isNonCachedAdmin(admin); - }; - return m_isAdminCache.getCachedValue(admin, getNonCachedValue).value; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// isNonCachedAdmin -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::isNonCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const { - try { - const char *const sql = - "SELECT " - "ADMIN_USER_NAME AS ADMIN_USER_NAME " - "FROM " - "ADMIN_USER " - "WHERE " - "ADMIN_USER_NAME = :ADMIN_USER_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":ADMIN_USER_NAME", admin.username); - auto rset = stmt.executeQuery(); - return rset.next(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapesForWriting -//------------------------------------------------------------------------------ -std::list<TapeForWriting> RdbmsCatalogue::getTapesForWriting(const std::string &logicalLibraryName) const { - try { - std::list<TapeForWriting> tapes; - const char *const sql = - "SELECT " - "TAPE.VID AS VID," - "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," - "TAPE.VENDOR AS VENDOR," - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," - "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," - "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," - "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," - "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," - "TAPE.LAST_FSEQ AS LAST_FSEQ," - "TAPE.LABEL_FORMAT AS LABEL_FORMAT " - "FROM " - "TAPE " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " - "INNER JOIN LOGICAL_LIBRARY ON " - "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " - "INNER JOIN MEDIA_TYPE ON " - "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " - "INNER JOIN VIRTUAL_ORGANIZATION ON " - "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " - "WHERE " -// "TAPE.LABEL_DRIVE IS NOT NULL AND " // Set when the tape has been labelled -// "TAPE.LABEL_TIME IS NOT NULL AND " // Set when the tape has been labelled - "TAPE.TAPE_STATE = :TAPE_STATE AND " - "TAPE.IS_FULL = '0' AND " - "TAPE.IS_FROM_CASTOR = '0' AND " - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME " - "ORDER BY TAPE.DATA_IN_BYTES DESC"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); - stmt.bindString(":TAPE_STATE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); - auto rset = stmt.executeQuery(); - while (rset.next()) { - TapeForWriting tape; - tape.vid = rset.columnString("VID"); - tape.mediaType = rset.columnString("MEDIA_TYPE"); - tape.vendor = rset.columnString("VENDOR"); - tape.tapePool = rset.columnString("TAPE_POOL_NAME"); - tape.vo = rset.columnString("VO"); - tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); - tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); - tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); - tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), "[RdbmsCatalogue::getTapesForWriting()]"); - - tapes.push_back(tape); - } - return tapes; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -common::dataStructures::Label::Format RdbmsCatalogue::getTapeLabelFormat(const std::string& vid) const { - try { - const char *const sql = - "SELECT " - "TAPE.LABEL_FORMAT AS LABEL_FORMAT " - "FROM " - "TAPE " - "WHERE " - "VID = :VID"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - if(rset.next()) { - return common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), "[RdbmsCatalogue::getTapeLabelFormat()]"); - } else { - throw exception::Exception(std::string("No such tape with vid=") + vid); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// insertTapeFile -//------------------------------------------------------------------------------ -void RdbmsCatalogue::insertTapeFile( - rdbms::Conn &conn, - const common::dataStructures::TapeFile &tapeFile, - const uint64_t archiveFileId) { - rdbms::AutoRollback autoRollback(conn); - try{ - - std::list<InsertFileRecycleLog> insertedFilesRecycleLog = insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn,tapeFile,archiveFileId); - { - const time_t now = time(nullptr); - const char *const sql = - "INSERT INTO TAPE_FILE(" - "VID," - "FSEQ," - "BLOCK_ID," - "LOGICAL_SIZE_IN_BYTES," - "COPY_NB," - "CREATION_TIME," - "ARCHIVE_FILE_ID)" - "VALUES(" - ":VID," - ":FSEQ," - ":BLOCK_ID," - ":LOGICAL_SIZE_IN_BYTES," - ":COPY_NB," - ":CREATION_TIME," - ":ARCHIVE_FILE_ID)"; - auto stmt = conn.createStmt(sql); - - stmt.bindString(":VID", tapeFile.vid); - stmt.bindUint64(":FSEQ", tapeFile.fSeq); - stmt.bindUint64(":BLOCK_ID", tapeFile.blockId); - stmt.bindUint64(":LOGICAL_SIZE_IN_BYTES", tapeFile.fileSize); - stmt.bindUint64(":COPY_NB", tapeFile.copyNb); - stmt.bindUint64(":CREATION_TIME", now); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - { - for(auto& fileRecycleLog: insertedFilesRecycleLog){ - const char *const sql = - "DELETE FROM " - "TAPE_FILE " - "WHERE " - "VID=:VID AND " - "FSEQ=:FSEQ"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID",fileRecycleLog.vid); - stmt.bindUint64(":FSEQ",fileRecycleLog.fSeq); - stmt.executeNonQuery(); - } - } - conn.commit(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// setTapeLastFseq -//------------------------------------------------------------------------------ -void RdbmsCatalogue::setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq) { - try { - threading::MutexLocker locker(m_mutex); - - const uint64_t currentValue = getTapeLastFSeq(conn, vid); - if(lastFSeq != currentValue + 1) { - exception::Exception ex; - ex.getMessage() << "The last FSeq MUST be incremented by exactly one: currentValue=" << currentValue << - ",nextValue=" << lastFSeq; - throw ex; - } - const char *const sql = - "UPDATE TAPE SET " - "LAST_FSEQ = :LAST_FSEQ " - "WHERE " - "VID=:VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - stmt.bindUint64(":LAST_FSEQ", lastFSeq); - stmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapeLastFSeq -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const { - try { - const char *const sql = - "SELECT " - "LAST_FSEQ AS LAST_FSEQ " - "FROM " - "TAPE " - "WHERE " - "VID = :VID"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - if(rset.next()) { - return rset.columnUint64("LAST_FSEQ"); - } else { - throw exception::Exception(std::string("No such tape with vid=") + vid); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileRowByArchiveId -//------------------------------------------------------------------------------ -std::unique_ptr<ArchiveFileRow> RdbmsCatalogue::getArchiveFileRowById(rdbms::Conn &conn, const uint64_t id) const { - try { - const char *const sql = - "SELECT" "\n" - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," "\n" - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," "\n" - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," "\n" - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," "\n" - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," "\n" - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," "\n" - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," "\n" - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," "\n" - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," "\n" - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," "\n" - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME" "\n" - "FROM" "\n" - "ARCHIVE_FILE" "\n" - "INNER JOIN STORAGE_CLASS ON" "\n" - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID" "\n" - "WHERE" "\n" - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", id); - auto rset = stmt.executeQuery(); - - std::unique_ptr<ArchiveFileRow> row; - if (rset.next()) { - row = std::make_unique<ArchiveFileRow>(); - - row->archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - row->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - row->diskFileId = rset.columnString("DISK_FILE_ID"); - row->diskFileOwnerUid = rset.columnUint64("DISK_FILE_UID"); - row->diskFileGid = rset.columnUint64("DISK_FILE_GID"); - row->size = rset.columnUint64("SIZE_IN_BYTES"); - row->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - row->storageClassName = rset.columnString("STORAGE_CLASS_NAME"); - row->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - row->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - } - - return row; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileToRetrieveByArchiveFileId -//------------------------------------------------------------------------------ -std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileToRetrieveByArchiveFileId( - rdbms::Conn &conn, const uint64_t archiveFileId) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID AND " - "TAPE.TAPE_STATE IN ('ACTIVE', 'DISABLED') " - "ORDER BY " - "TAPE_FILE.CREATION_TIME ASC"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - auto rset = stmt.executeQuery(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - while (rset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file we add it to the archiveFile's list of tape files - if(!rset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = rset.columnString("VID"); - tapeFile.fSeq = rset.columnUint64("FSEQ"); - tapeFile.blockId = rset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = rset.columnUint64("COPY_NB"); - tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - //If there are no tape files that belong to the archive file, then return a nullptr. - if(archiveFile.get() != nullptr && archiveFile->tapeFiles.empty()){ - archiveFile.reset(nullptr); - } - - return archiveFile; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileToRetrieveByArchiveFileId -//------------------------------------------------------------------------------ -const std::list<std::pair<std::string, std::string>> RdbmsCatalogue::getTapeFileStateListForArchiveFileId( - rdbms::Conn &conn, const uint64_t archiveFileId) const { - try { - const char *const sql = - "SELECT " - "TAPE_FILE.VID AS VID," - "TAPE.TAPE_STATE AS STATE " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID "; - - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - auto rset = stmt.executeQuery(); - std::list<std::pair<std::string, std::string>> ret; - while (rset.next()) { - const auto &vid = rset.columnString("VID"); - const auto &state = rset.columnString("STATE"); - ret.push_back(std::pair<std::string, std::string>(vid, state)); - } - return ret; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileByDiskFileId -//------------------------------------------------------------------------------ -std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileByDiskFileId( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &diskFileId) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "WHERE " - "ARCHIVE_FILE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "ARCHIVE_FILE.DISK_FILE_ID = :DISK_FILE_ID " - "ORDER BY " - "TAPE_FILE.CREATION_TIME ASC"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":DISK_FILE_ID", diskFileId); - auto rset = stmt.executeQuery(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - while (rset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file - if(!rset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = rset.columnString("VID"); - tapeFile.fSeq = rset.columnUint64("FSEQ"); - tapeFile.blockId = rset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = rset.columnUint64("COPY_NB"); - tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - return archiveFile; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getArchiveFileToRetrieveByDiskFileId -//------------------------------------------------------------------------------ -std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsCatalogue::getArchiveFileToRetrieveByDiskFileId( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &diskFileId) const { - try { - const char *const sql = - "SELECT " - "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " - "FROM " - "ARCHIVE_FILE " - "INNER JOIN STORAGE_CLASS ON " - "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " - "INNER JOIN TAPE_FILE ON " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " - "INNER JOIN TAPE ON " - "TAPE_FILE.VID = TAPE.VID " - "WHERE " - "ARCHIVE_FILE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " - "ARCHIVE_FILE.DISK_FILE_ID = :DISK_FILE_ID AND " - "TAPE.TAPE_STATE = :TAPE_STATE " - "ORDER BY " - "TAPE_FILE.CREATION_TIME ASC"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); - stmt.bindString(":DISK_FILE_ID", diskFileId); - stmt.bindString(":TAPE_STATE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); - auto rset = stmt.executeQuery(); - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; - while (rset.next()) { - if(nullptr == archiveFile.get()) { - archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); - - archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); - archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); - archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); - archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); - archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); - archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); - archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); - archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); - archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); - archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); - } - - // If there is a tape file - if(!rset.columnIsNull("VID")) { - // Add the tape file to the archive file's in-memory structure - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = rset.columnString("VID"); - tapeFile.fSeq = rset.columnUint64("FSEQ"); - tapeFile.blockId = rset.columnUint64("BLOCK_ID"); - tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); - tapeFile.copyNb = rset.columnUint64("COPY_NB"); - tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience - - archiveFile->tapeFiles.push_back(tapeFile); - } - } - - return archiveFile; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// ping -//------------------------------------------------------------------------------ -void RdbmsCatalogue::ping() { - try { - verifySchemaVersion(); - } catch (WrongSchemaVersionException &){ - throw; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// verifySchemaVersion -//------------------------------------------------------------------------------ -void RdbmsCatalogue::verifySchemaVersion() { - try { - SchemaVersion schemaVersion = getSchemaVersion(); - auto schemaVersionMajorMinor = schemaVersion.getSchemaVersion<SchemaVersion::MajorMinor>(); - if(schemaVersionMajorMinor.first != (uint64_t) CTA_CATALOGUE_SCHEMA_VERSION_MAJOR){ - std::ostringstream exceptionMsg; - exceptionMsg << "Catalogue schema MAJOR version differ : Database schema version is " << schemaVersionMajorMinor.first << "." << schemaVersionMajorMinor.second << ", CTA schema version is "<< CTA_CATALOGUE_SCHEMA_VERSION_MAJOR << "." << CTA_CATALOGUE_SCHEMA_VERSION_MINOR; - throw WrongSchemaVersionException(exceptionMsg.str()); - } - if(schemaVersion.getStatus<SchemaVersion::Status>() == SchemaVersion::Status::UPGRADING){ - std::ostringstream exceptionMsg; - exceptionMsg << "Catalogue schema is in status "+schemaVersion.getStatus<std::string>()+", next schema version is "<<schemaVersion.getSchemaVersionNext<std::string>(); - } - } catch (exception::UserError &ex) { - throw; - } catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getSchemaVersion -//------------------------------------------------------------------------------ -SchemaVersion RdbmsCatalogue::getSchemaVersion() const { - try { - std::map<std::string, uint64_t> schemaVersion; - const char *const sql = - "SELECT " - "CTA_CATALOGUE.SCHEMA_VERSION_MAJOR AS SCHEMA_VERSION_MAJOR," - "CTA_CATALOGUE.SCHEMA_VERSION_MINOR AS SCHEMA_VERSION_MINOR," - "CTA_CATALOGUE.NEXT_SCHEMA_VERSION_MAJOR AS NEXT_SCHEMA_VERSION_MAJOR," - "CTA_CATALOGUE.NEXT_SCHEMA_VERSION_MINOR AS NEXT_SCHEMA_VERSION_MINOR," - "CTA_CATALOGUE.STATUS AS STATUS " - "FROM " - "CTA_CATALOGUE"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - - if(rset.next()) { - SchemaVersion::Builder schemaVersionBuilder; - schemaVersionBuilder.schemaVersionMajor(rset.columnUint64("SCHEMA_VERSION_MAJOR")) - .schemaVersionMinor(rset.columnUint64("SCHEMA_VERSION_MINOR")) - .status(rset.columnString("STATUS")); - auto schemaVersionMajorNext = rset.columnOptionalUint64("NEXT_SCHEMA_VERSION_MAJOR"); - auto schemaVersionMinorNext = rset.columnOptionalUint64("NEXT_SCHEMA_VERSION_MINOR"); - if(schemaVersionMajorNext && schemaVersionMinorNext){ - schemaVersionBuilder.nextSchemaVersionMajor(schemaVersionMajorNext.value()) - .nextSchemaVersionMinor(schemaVersionMinorNext.value()); - } - return schemaVersionBuilder.build(); - } else { - throw exception::Exception("CTA_CATALOGUE does not contain any row"); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTableNames -//------------------------------------------------------------------------------ -std::list<std::string> RdbmsCatalogue::getTableNames() const { - auto conn = m_connPool.getConn(); - return conn.getTableNames(); -} - -//------------------------------------------------------------------------------ -// checkTapeFileWrittenFieldsAreSet -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkTapeFileWrittenFieldsAreSet(const std::string &callingFunc, const TapeFileWritten &event) - const { - try { - if(event.diskInstance.empty()) throw exception::Exception("diskInstance is an empty string"); - if(event.diskFileId.empty()) throw exception::Exception("diskFileId is an empty string"); - if(0 == event.diskFileOwnerUid) throw exception::Exception("diskFileOwnerUid is 0"); - if(0 == event.size) throw exception::Exception("size is 0"); - if(event.checksumBlob.length() == 0) throw exception::Exception("checksumBlob is an empty string"); - if(event.storageClassName.empty()) throw exception::Exception("storageClassName is an empty string"); - if(event.vid.empty()) throw exception::Exception("vid is an empty string"); - if(0 == event.fSeq) throw exception::Exception("fSeq is 0"); - if(0 == event.blockId && event.fSeq != 1) throw exception::Exception("blockId is 0 and fSeq is not 1"); - if(0 == event.copyNb) throw exception::Exception("copyNb is 0"); - if(event.tapeDrive.empty()) throw exception::Exception("tapeDrive is an empty string"); - } catch (exception::Exception &ex) { - throw exception::Exception(callingFunc + " failed: TapeFileWrittenEvent is invalid: " + ex.getMessage().str()); - } -} - -//------------------------------------------------------------------------------ -// checkDeleteRequestConsistency -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkDeleteRequestConsistency(const cta::common::dataStructures::DeleteArchiveRequest deleteRequest, const cta::common::dataStructures::ArchiveFile& archiveFile) const { - if(deleteRequest.diskInstance != archiveFile.diskInstance){ - std::ostringstream msg; - msg << "Failed to move archive file with ID " << deleteRequest.archiveFileID << " to the recycle-bin because the disk instance of " - "the request does not match that of the archived file: archiveFileId=" << archiveFile.archiveFileID << " requestDiskInstance=" << deleteRequest.diskInstance << " archiveFileDiskInstance=" << - archiveFile.diskInstance; - throw cta::exception::Exception(msg.str()); - } - if(deleteRequest.diskFilePath.empty()){ - std::ostringstream msg; - msg << "Failed to move archive file with ID " << deleteRequest.archiveFileID << " to the recycle-bin because the disk file path has not been provided."; - throw cta::exception::Exception(msg.str()); - } -} - -//------------------------------------------------------------------------------ -// checkTapeItemWrittenFieldsAreSet -//------------------------------------------------------------------------------ -void RdbmsCatalogue::checkTapeItemWrittenFieldsAreSet(const std::string& callingFunc, const TapeItemWritten& event) const { - try { - if(event.vid.empty()) throw exception::Exception("vid is an empty string"); - if(0 == event.fSeq) throw exception::Exception("fSeq is 0"); - if(event.tapeDrive.empty()) throw exception::Exception("tapeDrive is an empty string"); - } catch (exception::Exception &ex) { - throw exception::Exception(callingFunc + " failed: TapeItemWrittenEvent is invalid: " + ex.getMessage().str()); - } -} - -//------------------------------------------------------------------------------ -// getNbTapesInPool -//------------------------------------------------------------------------------ -uint64_t RdbmsCatalogue::getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT " - "COUNT(*) AS NB_TAPES " - "FROM " - "TAPE " - "INNER JOIN TAPE_POOL ON " - "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " - "WHERE " - "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", name); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - throw exception::Exception("Result set of SELECT COUNT(*) is empty"); - } - return rset.columnUint64("NB_TAPES"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// isSetAndEmpty -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::isSetAndEmpty(const std::optional<std::string> &optionalStr) const { - return optionalStr && optionalStr->empty(); -} - -//------------------------------------------------------------------------------ -// isSetAndEmpty -//------------------------------------------------------------------------------ -bool RdbmsCatalogue::isSetAndEmpty(const std::optional<std::vector<std::string>> &optionalStrList) const { - return optionalStrList && optionalStrList->empty(); -} - -//------------------------------------------------------------------------------ -// getLogicalLibraryId -//------------------------------------------------------------------------------ -std::optional<uint64_t> RdbmsCatalogue::getLogicalLibraryId(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT" "\n" - "LOGICAL_LIBRARY_ID AS LOGICAL_LIBRARY_ID" "\n" - "FROM" "\n" - "LOGICAL_LIBRARY" "\n" - "WHERE" "\n" - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":LOGICAL_LIBRARY_NAME", name); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - return std::nullopt; - } - return rset.columnUint64("LOGICAL_LIBRARY_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getTapePoolId -//------------------------------------------------------------------------------ -std::optional<uint64_t> RdbmsCatalogue::getTapePoolId(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT" "\n" - "TAPE_POOL_ID AS TAPE_POOL_ID" "\n" - "FROM" "\n" - "TAPE_POOL" "\n" - "WHERE" "\n" - "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":TAPE_POOL_NAME", name); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - return std::nullopt; - } - return rset.columnUint64("TAPE_POOL_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getMediaTypeId -//------------------------------------------------------------------------------ -std::optional<uint64_t> RdbmsCatalogue::getMediaTypeId(rdbms::Conn &conn, const std::string &name) const { - try { - const char *const sql = - "SELECT" "\n" - "MEDIA_TYPE.MEDIA_TYPE_ID AS MEDIA_TYPE_ID" "\n" - "FROM" "\n" - "MEDIA_TYPE" "\n" - "WHERE" "\n" - "MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; - auto stmt = conn.createStmt(sql); - stmt.bindString(":MEDIA_TYPE_NAME", name); - auto rset = stmt.executeQuery(); - if(!rset.next()) { - return std::nullopt; - } - return rset.columnUint64("MEDIA_TYPE_ID"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// updateDiskFileId -//------------------------------------------------------------------------------ -void RdbmsCatalogue::updateDiskFileId(const uint64_t archiveFileId, const std::string &diskInstance, - const std::string &diskFileId) { - try { - const char *const sql = - "UPDATE ARCHIVE_FILE SET" "\n" - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME," "\n" - "DISK_FILE_ID = :DISK_FILE_ID" "\n" - "WHERE" "\n" - "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.bindString(":DISK_FILE_ID", diskFileId); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - std::ostringstream msg; - msg << "Cannot update the disk file ID of the archive file with archive file ID " << archiveFileId << - " because the archive file does not exist"; - throw exception::UserError(msg.str()); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// moveArchiveFileToRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, - log::LogContext & lc) { - if(!request.archiveFile){ - //The archive file does not exist in the catalogue, nothing to do with it - return; - } - cta::common::dataStructures::ArchiveFile archiveFile = request.archiveFile.value(); - utils::Timer t, totalTime; - log::TimingList tl; - try { - checkDeleteRequestConsistency(request,archiveFile); - tl.insertAndReset("checkDeleteRequestConsistency",t); - } catch(const cta::exception::Exception & ex){ - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(request.archiveFileID)) - .add("diskInstance", archiveFile.diskInstance) - .add("requestDiskInstance", request.diskInstance) - .add("diskFileId", archiveFile.diskFileId) - .add("diskFileInfo.owner_uid", archiveFile.diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile.diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile.fileSize)) - .add("creationTime", std::to_string(archiveFile.creationTime)) - .add("reconciliationTime", std::to_string(archiveFile.reconciliationTime)) - .add("diskFilePath",request.diskFilePath) - .add("errorMessage",ex.getMessageValue()) - .add("storageClass", archiveFile.storageClass); - archiveFile.checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile.tapeFiles.begin(); it!=archiveFile.tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize; - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::WARNING, "Failed to move archive file to the file-recycle-log."); - - exception::UserError ue; - ue.getMessage() << "Failed to move archive file with ID " << request.archiveFileID << " to the file-recycle-log. errorMessage=" << ex.getMessageValue(); - throw ue; - } - - try { - //All checks are good, we can move the file to the recycle-bin - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - copyArchiveFileToFileRecyleLogAndDelete(conn,request,lc); - tl.insertAndReset("copyArchiveFileToFileRecyleLogAndDeleteTime",t); - tl.insertAndReset("totalTime",totalTime); - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(request.archiveFileID)) - .add("diskInstance", archiveFile.diskInstance) - .add("requestDiskInstance", request.diskInstance) - .add("diskFileId", archiveFile.diskFileId) - .add("diskFileInfo.owner_uid", archiveFile.diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile.diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile.fileSize)) - .add("creationTime", std::to_string(archiveFile.creationTime)) - .add("reconciliationTime", std::to_string(archiveFile.reconciliationTime)) - .add("storageClass", archiveFile.storageClass); - archiveFile.checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile.tapeFiles.begin(); it!=archiveFile.tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize; - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - tl.addToLog(spc); - lc.log(log::INFO, "In RdbmsCatalogue::moveArchiveFileToRecycleLog(): ArchiveFile moved to the file-recycle-log."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyArchiveFileToFileRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::copyArchiveFileToFileRecycleLog(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest & request) { - try{ - if(!request.archiveFile){ - throw cta::exception::Exception("No archiveFile object has been set in the DeleteArchiveRequest object."); - } - const common::dataStructures::ArchiveFile & archiveFile = request.archiveFile.value(); - - for(auto &tapeFile: archiveFile.tapeFiles){ - //Create one file recycle log entry per tape file - InsertFileRecycleLog fileRecycleLog; - fileRecycleLog.vid = tapeFile.vid; - fileRecycleLog.fSeq = tapeFile.fSeq; - fileRecycleLog.blockId = tapeFile.blockId; - fileRecycleLog.copyNb = tapeFile.copyNb; - fileRecycleLog.tapeFileCreationTime = tapeFile.creationTime; - fileRecycleLog.archiveFileId = archiveFile.archiveFileID; - fileRecycleLog.diskFilePath = request.diskFilePath; - fileRecycleLog.reasonLog = InsertFileRecycleLog::getDeletionReasonLog(request.requester.name,request.diskInstance); - fileRecycleLog.recycleLogTime = time(nullptr); - insertFileInFileRecycleLog(conn,fileRecycleLog); - } - - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -//------------------------------------------------------------------------------ -// copyTapeFilesToFileRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::copyTapeFilesToFileRecycleLog(rdbms::Conn & conn, const common::dataStructures::ArchiveFile &archiveFile, const std::string &reason) { - try { - for(auto &tapeFile: archiveFile.tapeFiles) { - //Create one file recycle log entry per tape file - InsertFileRecycleLog fileRecycleLog; - fileRecycleLog.vid = tapeFile.vid; - fileRecycleLog.fSeq = tapeFile.fSeq; - fileRecycleLog.blockId = tapeFile.blockId; - fileRecycleLog.copyNb = tapeFile.copyNb; - fileRecycleLog.tapeFileCreationTime = tapeFile.creationTime; - fileRecycleLog.archiveFileId = archiveFile.archiveFileID; - fileRecycleLog.diskFilePath = archiveFile.diskFileInfo.path; - fileRecycleLog.reasonLog = "(Deleted using cta-admin tf rm) " + reason; - fileRecycleLog.recycleLogTime = time(nullptr); - insertFileInFileRecycleLog(conn,fileRecycleLog); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// insertFileInFileRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::insertFileInFileRecycleLog(rdbms::Conn& conn, const InsertFileRecycleLog& fileRecycleLog){ - try{ - checkCommentOrReasonMaxLength(fileRecycleLog.reasonLog); - uint64_t fileRecycleLogId = getNextFileRecyleLogId(conn); - const char *const sql = - "INSERT INTO FILE_RECYCLE_LOG(" - "FILE_RECYCLE_LOG_ID," - "VID," - "FSEQ," - "BLOCK_ID," - "COPY_NB," - "TAPE_FILE_CREATION_TIME," - "ARCHIVE_FILE_ID," - "DISK_INSTANCE_NAME," - "DISK_FILE_ID," - "DISK_FILE_ID_WHEN_DELETED," - "DISK_FILE_UID," - "DISK_FILE_GID," - "SIZE_IN_BYTES," - "CHECKSUM_BLOB," - "CHECKSUM_ADLER32," - "STORAGE_CLASS_ID," - "ARCHIVE_FILE_CREATION_TIME," - "RECONCILIATION_TIME," - "COLLOCATION_HINT," - "DISK_FILE_PATH," - "REASON_LOG," - "RECYCLE_LOG_TIME" - ") SELECT " - ":FILE_RECYCLE_LOG_ID," - ":VID," - ":FSEQ," - ":BLOCK_ID," - ":COPY_NB," - ":TAPE_FILE_CREATION_TIME," - ":ARCHIVE_FILE_ID," - "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," - "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID_2," - "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," - "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," - "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," - "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," - "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," - "ARCHIVE_FILE.STORAGE_CLASS_ID AS STORAGE_CLASS_ID," - "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," - "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," - "ARCHIVE_FILE.COLLOCATION_HINT AS COLLOCATION_HINT," - ":DISK_FILE_PATH," - ":REASON_LOG," - ":RECYCLE_LOG_TIME " - "FROM " - "ARCHIVE_FILE " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID_2"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":FILE_RECYCLE_LOG_ID",fileRecycleLogId); - stmt.bindString(":VID",fileRecycleLog.vid); - stmt.bindUint64(":FSEQ",fileRecycleLog.fSeq); - stmt.bindUint64(":BLOCK_ID",fileRecycleLog.blockId); - stmt.bindUint8(":COPY_NB",fileRecycleLog.copyNb); - stmt.bindUint64(":TAPE_FILE_CREATION_TIME",fileRecycleLog.tapeFileCreationTime); - stmt.bindString(":DISK_FILE_PATH",fileRecycleLog.diskFilePath); - stmt.bindUint64(":ARCHIVE_FILE_ID",fileRecycleLog.archiveFileId); - stmt.bindString(":REASON_LOG",fileRecycleLog.reasonLog); - stmt.bindUint64(":RECYCLE_LOG_TIME",fileRecycleLog.recycleLogTime); - stmt.bindUint64(":ARCHIVE_FILE_ID_2",fileRecycleLog.archiveFileId); - stmt.executeNonQuery(); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest& request){ - try { - //Delete the tape files after. - const char *const deleteTapeFilesSql = - "DELETE FROM " - "TAPE_FILE " - "WHERE TAPE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); - deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID",request.archiveFileID); - deleteTapeFilesStmt.executeNonQuery(); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::ArchiveFile& file){ - try { - for(auto &tapeFile: file.tapeFiles) { - - //Delete the tape file. - const char *const deleteTapeFilesSql = - "DELETE FROM " - "TAPE_FILE " - "WHERE " - "TAPE_FILE.VID = :VID AND " - "TAPE_FILE.FSEQ = :FSEQ"; - - auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); - deleteTapeFilesStmt.bindString(":VID", tapeFile.vid); - deleteTapeFilesStmt.bindUint64(":FSEQ", tapeFile.fSeq); - deleteTapeFilesStmt.executeNonQuery(); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - - -void RdbmsCatalogue::deleteArchiveFile(rdbms::Conn& conn, const common::dataStructures::DeleteArchiveRequest& request){ - try{ - const char *const deleteArchiveFileSql = - "DELETE FROM " - "ARCHIVE_FILE " - "WHERE ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto deleteArchiveFileStmt = conn.createStmt(deleteArchiveFileSql); - deleteArchiveFileStmt.bindUint64(":ARCHIVE_FILE_ID",request.archiveFileID); - deleteArchiveFileStmt.executeNonQuery(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteFileFromRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc) { - try { - auto conn = m_connPool.getConn(); - rdbms::AutoRollback autoRollback(conn); - deleteTapeFilesAndArchiveFileFromRecycleBin(conn,archiveFileId,lc); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFilesFromRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTapeFilesFromRecycleBin(cta::rdbms::Conn & conn, const uint64_t archiveFileId) { - try { - const char *const deleteTapeFilesSql = - "DELETE FROM " - "TAPE_FILE_RECYCLE_BIN " - "WHERE TAPE_FILE_RECYCLE_BIN.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); - deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID",archiveFileId); - deleteTapeFilesStmt.executeNonQuery(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFilesFromRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId) { - try { - const char *const deleteArchiveFileSql = - "DELETE FROM " - "ARCHIVE_FILE_RECYCLE_BIN " - "WHERE ARCHIVE_FILE_RECYCLE_BIN.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto deleteTapeFilesStmt = conn.createStmt(deleteArchiveFileSql); - deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID",archiveFileId); - deleteTapeFilesStmt.executeNonQuery(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFileCopyFromRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteTapeFileCopyFromRecycleBin(cta::rdbms::Conn & conn, const common::dataStructures::FileRecycleLog fileRecycleLog) { - try { - const char *const deleteTapeFilesSql = - "DELETE FROM " - "FILE_RECYCLE_LOG " - "WHERE FILE_RECYCLE_LOG.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID AND FILE_RECYCLE_LOG.VID = :VID AND " - "FILE_RECYCLE_LOG.FSEQ = :FSEQ AND FILE_RECYCLE_LOG.COPY_NB = :COPY_NB AND " - "FILE_RECYCLE_LOG.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; - - auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); - deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID", fileRecycleLog.archiveFileId); - deleteTapeFilesStmt.bindString(":VID", fileRecycleLog.vid); - deleteTapeFilesStmt.bindUint64(":FSEQ", fileRecycleLog.fSeq); - deleteTapeFilesStmt.bindUint64(":COPY_NB", fileRecycleLog.copyNb); - deleteTapeFilesStmt.bindString(":DISK_INSTANCE_NAME", fileRecycleLog.diskInstanceName); - deleteTapeFilesStmt.executeNonQuery(); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// insertOldCopiesOfFilesIfAnyOnFileRecycleLog -//------------------------------------------------------------------------------ -std::list<InsertFileRecycleLog> RdbmsCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn,const common::dataStructures::TapeFile & tapefile, const uint64_t archiveFileId){ - std::list<InsertFileRecycleLog> fileRecycleLogsToInsert; - try { - //First, get the file to insert on the FILE_RECYCLE_LOG table - { - const char *const sql = - "SELECT " - "TAPE_FILE.VID AS VID," - "TAPE_FILE.FSEQ AS FSEQ," - "TAPE_FILE.BLOCK_ID AS BLOCK_ID," - "TAPE_FILE.COPY_NB AS COPY_NB," - "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," - "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " - "FROM " - "TAPE_FILE " - "WHERE " - "TAPE_FILE.COPY_NB=:COPY_NB AND TAPE_FILE.ARCHIVE_FILE_ID=:ARCHIVE_FILE_ID AND (TAPE_FILE.VID<>:VID OR TAPE_FILE.FSEQ<>:FSEQ)"; - - auto stmt = conn.createStmt(sql); - stmt.bindUint8(":COPY_NB",tapefile.copyNb); - stmt.bindUint64(":ARCHIVE_FILE_ID",archiveFileId); - stmt.bindString(":VID",tapefile.vid); - stmt.bindUint64(":FSEQ",tapefile.fSeq); - - auto rset = stmt.executeQuery(); - while(rset.next()){ - cta::catalogue::InsertFileRecycleLog fileRecycleLog; - fileRecycleLog.vid = rset.columnString("VID"); - fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); - fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); - fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); - fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); - fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); - fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); - fileRecycleLog.recycleLogTime = time(nullptr); - fileRecycleLogsToInsert.push_back(fileRecycleLog); - } - } - { - for(auto & fileRecycleLog: fileRecycleLogsToInsert){ - insertFileInFileRecycleLog(conn,fileRecycleLog); - } - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } - return fileRecycleLogsToInsert; -} - -//------------------------------------------------------------------------------ -// deleteFilesFromRecycleBin -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteFilesFromRecycleBin(rdbms::Conn & conn, const std::string& vid, cta::log::LogContext & lc) { - try { - const char *const selectArchiveFileIdSql = - "SELECT " - "TAPE_FILE_RECYCLE_BIN.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " - "FROM " - "TAPE_FILE_RECYCLE_BIN " - "WHERE " - "TAPE_FILE_RECYCLE_BIN.VID = :VID"; - - auto selectFileStmt = conn.createStmt(selectArchiveFileIdSql); - selectFileStmt.bindString(":VID",vid); - auto rset = selectFileStmt.executeQuery(); - std::set<uint64_t> archiveFileIds; - while(rset.next()){ - archiveFileIds.insert(rset.columnUint64("ARCHIVE_FILE_ID")); - } - rdbms::AutoRollback rollback(conn); - for(auto archiveFileId: archiveFileIds){ - deleteTapeFilesAndArchiveFileFromRecycleBin(conn,archiveFileId,lc); - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteFilesFromRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) { - try { - auto conn = m_connPool.getConn(); - deleteFilesFromRecycleLog(conn,vid,lc); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteFilesFromRecycleLog -//------------------------------------------------------------------------------ -void RdbmsCatalogue::deleteFilesFromRecycleLog(rdbms::Conn & conn, const std::string& vid, log::LogContext& lc) { - try { - const char *const deleteFilesFromRecycleLogSql = - "DELETE FROM " - "FILE_RECYCLE_LOG " - "WHERE " - "VID=:VID"; - - cta::utils::Timer t; - log::TimingList tl; - auto selectFileStmt = conn.createStmt(deleteFilesFromRecycleLogSql); - selectFileStmt.bindString(":VID",vid); - selectFileStmt.executeNonQuery(); - uint64_t nbAffectedRows = selectFileStmt.getNbAffectedRows(); - if(nbAffectedRows){ - tl.insertAndReset("deleteFilesFromRecycleLogTime",t); - log::ScopedParamContainer spc(lc); - spc.add("vid",vid); - spc.add("nbFileRecycleLogDeleted",nbAffectedRows); - tl.addToLog(spc); - lc.log(cta::log::INFO,"In RdbmsCatalogue::deleteFilesFromRecycleLog(), file recycle log entries have been deleted."); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) { - try { - auto conn = m_connPool.getConn(); - const char *const sql = - "INSERT INTO DRIVE_STATE(" "\n" - "DRIVE_NAME," "\n" - "HOST," "\n" - "LOGICAL_LIBRARY," "\n" - "SESSION_ID," "\n" - - "BYTES_TRANSFERED_IN_SESSION," "\n" - "FILES_TRANSFERED_IN_SESSION," "\n" - - "SESSION_START_TIME," "\n" - "SESSION_ELAPSED_TIME," "\n" - "MOUNT_START_TIME," "\n" - "TRANSFER_START_TIME," "\n" - "UNLOAD_START_TIME," "\n" - "UNMOUNT_START_TIME," "\n" - "DRAINING_START_TIME," "\n" - "DOWN_OR_UP_START_TIME," "\n" - "PROBE_START_TIME," "\n" - "CLEANUP_START_TIME," "\n" - "START_START_TIME," "\n" - "SHUTDOWN_TIME," "\n" - - "MOUNT_TYPE," "\n" - "DRIVE_STATUS," "\n" - "DESIRED_UP," "\n" - "DESIRED_FORCE_DOWN," "\n" - "REASON_UP_DOWN," "\n" - - "CURRENT_VID," "\n" - "CTA_VERSION," "\n" - "CURRENT_PRIORITY," "\n" - "CURRENT_ACTIVITY," "\n" - "CURRENT_TAPE_POOL," "\n" - "NEXT_MOUNT_TYPE," "\n" - "NEXT_VID," "\n" - "NEXT_TAPE_POOL," "\n" - "NEXT_PRIORITY," "\n" - "NEXT_ACTIVITY," "\n" - - "DEV_FILE_NAME," "\n" - "RAW_LIBRARY_SLOT," "\n" - - "CURRENT_VO," "\n" - "NEXT_VO," "\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" - - "DISK_SYSTEM_NAME," "\n" - "RESERVED_BYTES," "\n" - "RESERVATION_SESSION_ID)" "\n" - "VALUES(" "\n" - ":DRIVE_NAME," "\n" - ":HOST," "\n" - ":LOGICAL_LIBRARY," "\n" - ":SESSION_ID," "\n" - - ":BYTES_TRANSFERED_IN_SESSION," "\n" - ":FILES_TRANSFERED_IN_SESSION," "\n" - - ":SESSION_START_TIME," "\n" - ":SESSION_ELAPSED_TIME," "\n" - ":MOUNT_START_TIME," "\n" - ":TRANSFER_START_TIME," "\n" - ":UNLOAD_START_TIME," "\n" - ":UNMOUNT_START_TIME," "\n" - ":DRAINING_START_TIME," "\n" - ":DOWN_OR_UP_START_TIME," "\n" - ":PROBE_START_TIME," "\n" - ":CLEANUP_START_TIME," "\n" - ":START_START_TIME," "\n" - ":SHUTDOWN_TIME," "\n" - - ":MOUNT_TYPE," "\n" - ":DRIVE_STATUS," "\n" - ":DESIRED_UP," "\n" - ":DESIRED_FORCE_DOWN," "\n" - ":REASON_UP_DOWN," "\n" - - ":CURRENT_VID," "\n" - ":CTA_VERSION," "\n" - ":CURRENT_PRIORITY," "\n" - ":CURRENT_ACTIVITY," "\n" - ":CURRENT_TAPE_POOL," "\n" - ":NEXT_MOUNT_TYPE," "\n" - ":NEXT_VID," "\n" - ":NEXT_TAPE_POOL," "\n" - ":NEXT_PRIORITY," "\n" - ":NEXT_ACTIVITY," "\n" - - ":DEV_FILE_NAME," "\n" - ":RAW_LIBRARY_SLOT," "\n" - - ":CURRENT_VO," "\n" - ":NEXT_VO," "\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" - - ":DISK_SYSTEM_NAME," "\n" - ":RESERVED_BYTES," "\n" - ":RESERVATION_SESSION_ID" "\n" - ")"; - - auto stmt = conn.createStmt(sql); - - settingSqlTapeDriveValues(&stmt, tapeDrive); - - stmt.executeNonQuery(); - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("driveName", tapeDrive.driveName) - .add("host", tapeDrive.host) - .add("logicalLibrary", tapeDrive.logicalLibrary) - .add("sessionId", tapeDrive.sessionId ? tapeDrive.sessionId.value() : 0) - - .add("bytesTransferedInSession", tapeDrive.bytesTransferedInSession - ? tapeDrive.bytesTransferedInSession.value() : 0) - .add("filesTransferedInSession", tapeDrive.filesTransferedInSession - ? tapeDrive.filesTransferedInSession.value() : 0) - - .add("sessionStartTime", tapeDrive.sessionStartTime ? tapeDrive.sessionStartTime.value() : 0) - .add("sessionElapsedTime", tapeDrive.sessionElapsedTime ? tapeDrive.sessionElapsedTime.value() : 0) - .add("mountStartTime", tapeDrive.mountStartTime ? tapeDrive.mountStartTime.value() : 0) - .add("transferStartTime", tapeDrive.transferStartTime - ? tapeDrive.transferStartTime.value() : 0) - .add("unloadStartTime", tapeDrive.unloadStartTime ? tapeDrive.unloadStartTime.value() : 0) - .add("unmountStartTime", tapeDrive.unmountStartTime ? tapeDrive.unmountStartTime.value() : 0) - .add("drainingStartTime", tapeDrive.drainingStartTime - ? tapeDrive.drainingStartTime.value() : 0) - .add("downOrUpStartTime", tapeDrive.downOrUpStartTime - ? tapeDrive.downOrUpStartTime.value() : 0) - .add("probeStartTime", tapeDrive.probeStartTime ? tapeDrive.probeStartTime.value() : 0) - .add("cleanupStartTime", tapeDrive.cleanupStartTime ? tapeDrive.cleanupStartTime.value() : 0) - .add("startStartTime", tapeDrive.startStartTime ? tapeDrive.startStartTime.value() : 0) - .add("shutdownTime", tapeDrive.shutdownTime ? tapeDrive.shutdownTime.value() : 0) - - .add("mountType", common::dataStructures::toString(tapeDrive.mountType)) - .add("driveStatus", common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus)) - - .add("desiredUp", tapeDrive.desiredUp ? 1 : 0) - .add("desiredForceDown", tapeDrive.desiredForceDown ? 1 : 0) - .add("reasonUpDown", tapeDrive.reasonUpDown ? tapeDrive.reasonUpDown.value() : "") - - .add("currentVo", tapeDrive.currentVo ? tapeDrive.currentVo.value() : "") - .add("nextVo", tapeDrive.nextVo ? tapeDrive.nextVo.value() : "") - .add("userComment", tapeDrive.userComment ? tapeDrive.userComment.value() : "") - - .add("creationLog_username", tapeDrive.creationLog - ? tapeDrive.creationLog.value().username : "") - .add("creationLog_host", tapeDrive.creationLog ? tapeDrive.creationLog.value().host : "") - .add("creationLog_time", tapeDrive.creationLog ? tapeDrive.creationLog.value().time : 0) - .add("lastModificationLog_username", tapeDrive.lastModificationLog - ? tapeDrive.lastModificationLog.value().username : "") - .add("lastModificationLog_username", tapeDrive.lastModificationLog - ? tapeDrive.lastModificationLog.value().host : "") - .add("lastModificationLog_username", tapeDrive.lastModificationLog - ? tapeDrive.lastModificationLog.value().time : 0) - - .add("diskSystemName", tapeDrive.diskSystemName ? tapeDrive.diskSystemName.value() : "") - .add("reservedBytes", tapeDrive.reservedBytes ? tapeDrive.reservedBytes.value() : 0) - .add("reservationSessionId", tapeDrive.reservationSessionId ? tapeDrive.reservationSessionId.value() : 0); - - lc.log(log::INFO, "Catalogue - created tape drive"); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::settingSqlTapeDriveValues(cta::rdbms::Stmt *stmt, - const common::dataStructures::TapeDrive &tapeDrive) const { - auto setOptionalString = [&stmt](const std::string& sqlField, const std::optional<std::string>& optionalField) { - if(optionalField && !optionalField.value().empty()) { - stmt->bindString(sqlField, optionalField.value()); - } else { - stmt->bindString(sqlField, std::nullopt); - } - }; - auto setOptionalTime = [&stmt](const std::string &sqlField, const std::optional<time_t>& optionalField) { - if(optionalField) { - stmt->bindUint64(sqlField, optionalField.value()); - } else { - stmt->bindUint64(sqlField, std::nullopt); - } - }; - - stmt->bindString(":DRIVE_NAME", tapeDrive.driveName); - stmt->bindString(":HOST", tapeDrive.host); - stmt->bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); - stmt->bindUint64(":SESSION_ID", tapeDrive.sessionId); - - stmt->bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession); - stmt->bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession); - - setOptionalTime(":SESSION_START_TIME", tapeDrive.sessionStartTime); - setOptionalTime(":SESSION_ELAPSED_TIME", tapeDrive.sessionElapsedTime); - setOptionalTime(":MOUNT_START_TIME", tapeDrive.mountStartTime); - setOptionalTime(":TRANSFER_START_TIME", tapeDrive.transferStartTime); - setOptionalTime(":UNLOAD_START_TIME", tapeDrive.unloadStartTime); - setOptionalTime(":UNMOUNT_START_TIME", tapeDrive.unmountStartTime); - setOptionalTime(":DRAINING_START_TIME", tapeDrive.drainingStartTime); - setOptionalTime(":DOWN_OR_UP_START_TIME", tapeDrive.downOrUpStartTime); - setOptionalTime(":PROBE_START_TIME", tapeDrive.probeStartTime); - setOptionalTime(":CLEANUP_START_TIME", tapeDrive.cleanupStartTime); - setOptionalTime(":START_START_TIME", tapeDrive.startStartTime); - setOptionalTime(":SHUTDOWN_TIME", tapeDrive.shutdownTime); - - stmt->bindString(":MOUNT_TYPE", common::dataStructures::toString(tapeDrive.mountType)); - stmt->bindString(":DRIVE_STATUS", common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus)); - - stmt->bindBool(":DESIRED_UP", tapeDrive.desiredUp); - stmt->bindBool(":DESIRED_FORCE_DOWN", tapeDrive.desiredForceDown); - setOptionalString(":REASON_UP_DOWN", tapeDrive.reasonUpDown); - - setOptionalString(":CURRENT_VID", tapeDrive.currentVid); - setOptionalString(":CTA_VERSION", tapeDrive.ctaVersion); - stmt->bindUint64(":CURRENT_PRIORITY", tapeDrive.currentPriority); - setOptionalString(":CURRENT_ACTIVITY", tapeDrive.currentActivity); - setOptionalString(":CURRENT_TAPE_POOL", tapeDrive.currentTapePool); - stmt->bindString(":NEXT_MOUNT_TYPE", common::dataStructures::toString(tapeDrive.nextMountType)); - setOptionalString(":NEXT_VID", tapeDrive.nextVid); - setOptionalString(":NEXT_TAPE_POOL", tapeDrive.nextTapePool); - stmt->bindUint64(":NEXT_PRIORITY", tapeDrive.nextPriority); - setOptionalString(":NEXT_ACTIVITY", tapeDrive.nextActivity); - - setOptionalString(":DEV_FILE_NAME", tapeDrive.devFileName); - setOptionalString(":RAW_LIBRARY_SLOT", tapeDrive.rawLibrarySlot); - - setOptionalString(":CURRENT_VO", tapeDrive.currentVo); - setOptionalString(":NEXT_VO", tapeDrive.nextVo); - setOptionalString(":USER_COMMENT", tapeDrive.userComment); - - auto setEntryLog = [stmt, setOptionalString, setOptionalTime](const std::string &field, - const std::optional<std::string> &username, const std::optional<std::string> &host, const std::optional<time_t> &time) { - setOptionalString(field + "_USER_NAME", username); - setOptionalString(field + "_HOST_NAME", host); - setOptionalTime(field + "_TIME", time); - }; - - if (tapeDrive.creationLog) { - setEntryLog(":CREATION_LOG", tapeDrive.creationLog.value().username, - tapeDrive.creationLog.value().host, tapeDrive.creationLog.value().time); - } else { - setEntryLog(":CREATION_LOG", std::nullopt, std::nullopt, std::nullopt); - } - - if (tapeDrive.lastModificationLog) { - setEntryLog(":LAST_UPDATE", tapeDrive.lastModificationLog.value().username, - tapeDrive.lastModificationLog.value().host, tapeDrive.lastModificationLog.value().time); - } else { - setEntryLog(":LAST_UPDATE", std::nullopt, std::nullopt, std::nullopt); - } - - setOptionalString(":DISK_SYSTEM_NAME", tapeDrive.diskSystemName); - stmt->bindUint64(":RESERVED_BYTES", tapeDrive.reservedBytes); - stmt->bindUint64(":RESERVATION_SESSION_ID", tapeDrive.reservationSessionId); - -} - -void RdbmsCatalogue::deleteTapeDrive(const std::string &tapeDriveName) { - try { - const char *const delete_sql = - "DELETE FROM " - "DRIVE_STATE " - "WHERE " - "DRIVE_NAME = :DELETE_DRIVE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DELETE_DRIVE_NAME", tapeDriveName); - stmt.executeNonQuery(); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::list<std::string> RdbmsCatalogue::getTapeDriveNames() const { - try { - std::list<std::string> tapeDriveNames; - const char *const sql = - "SELECT " - "DRIVE_NAME AS DRIVE_NAME " - "FROM " - "DRIVE_STATE "; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - - while (rset.next()) { - const std::string driveName = rset.columnString("DRIVE_NAME"); - tapeDriveNames.push_back(driveName); - } - return tapeDriveNames; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -common::dataStructures::TapeDrive RdbmsCatalogue::gettingSqlTapeDriveValues(cta::rdbms::Rset* rset) const { - common::dataStructures::TapeDrive tapeDrive; - auto getOptionalTime = [](const std::optional<uint64_t> &time) -> std::optional<time_t> { - if (!time) return std::nullopt; - return time.value(); - }; - tapeDrive.driveName = rset->columnString("DRIVE_NAME"); - tapeDrive.host = rset->columnString("HOST"); - tapeDrive.logicalLibrary = rset->columnString("LOGICAL_LIBRARY"); - tapeDrive.sessionId = rset->columnOptionalUint64("SESSION_ID"); - tapeDrive.logicalLibraryDisabled = rset->columnOptionalBool("IS_DISABLED") ? rset->columnOptionalBool("IS_DISABLED").value() : false; - - tapeDrive.bytesTransferedInSession = rset->columnOptionalUint64("BYTES_TRANSFERED_IN_SESSION"); - tapeDrive.filesTransferedInSession = rset->columnOptionalUint64("FILES_TRANSFERED_IN_SESSION"); - - tapeDrive.sessionStartTime = getOptionalTime(rset->columnOptionalUint64("SESSION_START_TIME")); - tapeDrive.sessionElapsedTime = getOptionalTime(rset->columnOptionalUint64("SESSION_ELAPSED_TIME")); - tapeDrive.mountStartTime = getOptionalTime(rset->columnOptionalUint64("MOUNT_START_TIME")); - tapeDrive.transferStartTime = getOptionalTime(rset->columnOptionalUint64("TRANSFER_START_TIME")); - tapeDrive.unloadStartTime = getOptionalTime(rset->columnOptionalUint64("UNLOAD_START_TIME")); - tapeDrive.unmountStartTime = getOptionalTime(rset->columnOptionalUint64("UNMOUNT_START_TIME")); - tapeDrive.drainingStartTime = getOptionalTime(rset->columnOptionalUint64("DRAINING_START_TIME")); - tapeDrive.downOrUpStartTime = getOptionalTime(rset->columnOptionalUint64("DOWN_OR_UP_START_TIME")); - tapeDrive.probeStartTime = getOptionalTime(rset->columnOptionalUint64("PROBE_START_TIME")); - tapeDrive.cleanupStartTime = getOptionalTime(rset->columnOptionalUint64("CLEANUP_START_TIME")); - tapeDrive.startStartTime = getOptionalTime(rset->columnOptionalUint64("START_START_TIME")); - tapeDrive.shutdownTime = getOptionalTime(rset->columnOptionalUint64("SHUTDOWN_TIME")); - - tapeDrive.mountType = common::dataStructures::strToMountType(rset->columnString("MOUNT_TYPE")); - tapeDrive.driveStatus = common::dataStructures::TapeDrive::stringToState(rset->columnString("DRIVE_STATUS")); - tapeDrive.desiredUp = rset->columnBool("DESIRED_UP"); - tapeDrive.desiredForceDown = rset->columnBool("DESIRED_FORCE_DOWN"); - tapeDrive.reasonUpDown = rset->columnOptionalString("REASON_UP_DOWN"); - - tapeDrive.currentVid = rset->columnOptionalString("CURRENT_VID"); - tapeDrive.ctaVersion = rset->columnOptionalString("CTA_VERSION"); - tapeDrive.currentPriority = rset->columnOptionalUint64("CURRENT_PRIORITY"); - tapeDrive.currentActivity = rset->columnOptionalString("CURRENT_ACTIVITY"); - tapeDrive.currentTapePool = rset->columnOptionalString("CURRENT_TAPE_POOL"); - tapeDrive.nextMountType = common::dataStructures::strToMountType(rset->columnString("NEXT_MOUNT_TYPE")); - tapeDrive.nextVid = rset->columnOptionalString("NEXT_VID"); - tapeDrive.nextTapePool = rset->columnOptionalString("NEXT_TAPE_POOL"); - tapeDrive.nextPriority = rset->columnOptionalUint64("NEXT_PRIORITY"); - tapeDrive.nextActivity = rset->columnOptionalString("NEXT_ACTIVITY"); - - tapeDrive.devFileName = rset->columnOptionalString("DEV_FILE_NAME"); - tapeDrive.rawLibrarySlot = rset->columnOptionalString("RAW_LIBRARY_SLOT"); - - tapeDrive.currentVo = rset->columnOptionalString("CURRENT_VO"); - tapeDrive.nextVo = rset->columnOptionalString("NEXT_VO"); - - tapeDrive.diskSystemName = rset->columnOptionalString("DISK_SYSTEM_NAME"); - tapeDrive.reservedBytes = rset->columnOptionalUint64("RESERVED_BYTES"); - tapeDrive.reservationSessionId = rset->columnOptionalUint64("RESERVATION_SESSION_ID"); - - tapeDrive.userComment = rset->columnOptionalString("USER_COMMENT"); - auto setOptionEntryLog = [&rset](const std::string &username, const std::string &host, - const std::string &time) -> std::optional<common::dataStructures::EntryLog> { - if (!rset->columnOptionalString(username)) { - return std::nullopt; - } else { - return common::dataStructures::EntryLog( - rset->columnString(username), - rset->columnString(host), - rset->columnUint64(time)); - } - }; - tapeDrive.creationLog = setOptionEntryLog("CREATION_LOG_USER_NAME", "CREATION_LOG_HOST_NAME", - "CREATION_LOG_TIME"); - tapeDrive.lastModificationLog = setOptionEntryLog("LAST_UPDATE_USER_NAME", "LAST_UPDATE_HOST_NAME", - "LAST_UPDATE_TIME"); - - // Log warning for operators that tape drive logical library does not exist (cta/CTA#1163) - if (!rset->columnOptionalBool("IS_DISABLED")) { - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("driveName", tapeDrive.driveName) - .add("logicalLibrary", tapeDrive.logicalLibrary); - lc.log(log::WARNING, "RdbmsCatalogue::gettingSqlTapeDriveValues(): Logical library for tape drive does not exist in the catalogue"); - } - return tapeDrive; -} - -std::list<common::dataStructures::TapeDrive> RdbmsCatalogue::getTapeDrives() const { - try { - std::list<common::dataStructures::TapeDrive> tapeDrives; - const char *const sql = - "SELECT " - "DRIVE_STATE.DRIVE_NAME AS DRIVE_NAME," - "DRIVE_STATE.HOST AS HOST," - "DRIVE_STATE.LOGICAL_LIBRARY AS LOGICAL_LIBRARY," - "DRIVE_STATE.SESSION_ID AS SESSION_ID," - - "DRIVE_STATE.BYTES_TRANSFERED_IN_SESSION AS BYTES_TRANSFERED_IN_SESSION," - "DRIVE_STATE.FILES_TRANSFERED_IN_SESSION AS FILES_TRANSFERED_IN_SESSION," - - "DRIVE_STATE.SESSION_START_TIME AS SESSION_START_TIME," - "DRIVE_STATE.SESSION_ELAPSED_TIME AS SESSION_ELAPSED_TIME," - "DRIVE_STATE.MOUNT_START_TIME AS MOUNT_START_TIME," - "DRIVE_STATE.TRANSFER_START_TIME AS TRANSFER_START_TIME," - "DRIVE_STATE.UNLOAD_START_TIME AS UNLOAD_START_TIME," - "DRIVE_STATE.UNMOUNT_START_TIME AS UNMOUNT_START_TIME," - "DRIVE_STATE.DRAINING_START_TIME AS DRAINING_START_TIME," - "DRIVE_STATE.DOWN_OR_UP_START_TIME AS DOWN_OR_UP_START_TIME," - "DRIVE_STATE.PROBE_START_TIME AS PROBE_START_TIME," - "DRIVE_STATE.CLEANUP_START_TIME AS CLEANUP_START_TIME," - "DRIVE_STATE.START_START_TIME AS START_START_TIME," - "DRIVE_STATE.SHUTDOWN_TIME AS SHUTDOWN_TIME," - - "DRIVE_STATE.MOUNT_TYPE AS MOUNT_TYPE," - "DRIVE_STATE.DRIVE_STATUS AS DRIVE_STATUS," - "DRIVE_STATE.DESIRED_UP AS DESIRED_UP," - "DRIVE_STATE.DESIRED_FORCE_DOWN AS DESIRED_FORCE_DOWN," - "DRIVE_STATE.REASON_UP_DOWN AS REASON_UP_DOWN," - - "DRIVE_STATE.CURRENT_VID AS CURRENT_VID," - "DRIVE_STATE.CTA_VERSION AS CTA_VERSION," - "DRIVE_STATE.CURRENT_PRIORITY AS CURRENT_PRIORITY," - "DRIVE_STATE.CURRENT_ACTIVITY AS CURRENT_ACTIVITY," - "DRIVE_STATE.CURRENT_TAPE_POOL AS CURRENT_TAPE_POOL," - "DRIVE_STATE.NEXT_MOUNT_TYPE AS NEXT_MOUNT_TYPE," - "DRIVE_STATE.NEXT_VID AS NEXT_VID," - "DRIVE_STATE.NEXT_TAPE_POOL AS NEXT_TAPE_POOL," - "DRIVE_STATE.NEXT_PRIORITY AS NEXT_PRIORITY," - "DRIVE_STATE.NEXT_ACTIVITY AS NEXT_ACTIVITY," - - "DRIVE_STATE.DEV_FILE_NAME AS DEV_FILE_NAME," - "DRIVE_STATE.RAW_LIBRARY_SLOT AS RAW_LIBRARY_SLOT," - - "DRIVE_STATE.CURRENT_VO AS CURRENT_VO," - "DRIVE_STATE.NEXT_VO AS NEXT_VO," - "DRIVE_STATE.USER_COMMENT AS USER_COMMENT," - - "DRIVE_STATE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "DRIVE_STATE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "DRIVE_STATE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "DRIVE_STATE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "DRIVE_STATE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "DRIVE_STATE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," - - "DRIVE_STATE.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," - "DRIVE_STATE.RESERVED_BYTES AS RESERVED_BYTES," - "DRIVE_STATE.RESERVATION_SESSION_ID AS RESERVATION_SESSION_ID," - "LOGICAL_LIBRARY.IS_DISABLED AS IS_DISABLED " - "FROM " - "DRIVE_STATE " - "LEFT JOIN " - "LOGICAL_LIBRARY " - "ON " - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = DRIVE_STATE.LOGICAL_LIBRARY " - "ORDER BY " - "DRIVE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - - while (rset.next()) { - auto tapeDrive = gettingSqlTapeDriveValues(&rset); - tapeDrives.push_back(tapeDrive); - } - return tapeDrives; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::optional<common::dataStructures::TapeDrive> RdbmsCatalogue::getTapeDrive(const std::string &tapeDriveName) const { - try { - const char *const sql = - "SELECT " - "DRIVE_STATE.DRIVE_NAME AS DRIVE_NAME," - "DRIVE_STATE.HOST AS HOST," - "DRIVE_STATE.LOGICAL_LIBRARY AS LOGICAL_LIBRARY," - "DRIVE_STATE.SESSION_ID AS SESSION_ID," - - "DRIVE_STATE.BYTES_TRANSFERED_IN_SESSION AS BYTES_TRANSFERED_IN_SESSION," - "DRIVE_STATE.FILES_TRANSFERED_IN_SESSION AS FILES_TRANSFERED_IN_SESSION," - - "DRIVE_STATE.SESSION_START_TIME AS SESSION_START_TIME," - "DRIVE_STATE.SESSION_ELAPSED_TIME AS SESSION_ELAPSED_TIME," - "DRIVE_STATE.MOUNT_START_TIME AS MOUNT_START_TIME," - "DRIVE_STATE.TRANSFER_START_TIME AS TRANSFER_START_TIME," - "DRIVE_STATE.UNLOAD_START_TIME AS UNLOAD_START_TIME," - "DRIVE_STATE.UNMOUNT_START_TIME AS UNMOUNT_START_TIME," - "DRIVE_STATE.DRAINING_START_TIME AS DRAINING_START_TIME," - "DRIVE_STATE.DOWN_OR_UP_START_TIME AS DOWN_OR_UP_START_TIME," - "DRIVE_STATE.PROBE_START_TIME AS PROBE_START_TIME," - "DRIVE_STATE.CLEANUP_START_TIME AS CLEANUP_START_TIME," - "DRIVE_STATE.START_START_TIME AS START_START_TIME," - "DRIVE_STATE.SHUTDOWN_TIME AS SHUTDOWN_TIME," - - "DRIVE_STATE.MOUNT_TYPE AS MOUNT_TYPE," - "DRIVE_STATE.DRIVE_STATUS AS DRIVE_STATUS," - "DRIVE_STATE.DESIRED_UP AS DESIRED_UP," - "DRIVE_STATE.DESIRED_FORCE_DOWN AS DESIRED_FORCE_DOWN," - "DRIVE_STATE.REASON_UP_DOWN AS REASON_UP_DOWN," - - "DRIVE_STATE.CURRENT_VID AS CURRENT_VID," - "DRIVE_STATE.CTA_VERSION AS CTA_VERSION," - "DRIVE_STATE.CURRENT_PRIORITY AS CURRENT_PRIORITY," - "DRIVE_STATE.CURRENT_ACTIVITY AS CURRENT_ACTIVITY," - "DRIVE_STATE.CURRENT_TAPE_POOL AS CURRENT_TAPE_POOL," - "DRIVE_STATE.NEXT_MOUNT_TYPE AS NEXT_MOUNT_TYPE," - "DRIVE_STATE.NEXT_VID AS NEXT_VID," - "DRIVE_STATE.NEXT_TAPE_POOL AS NEXT_TAPE_POOL," - "DRIVE_STATE.NEXT_PRIORITY AS NEXT_PRIORITY," - "DRIVE_STATE.NEXT_ACTIVITY AS NEXT_ACTIVITY," - - "DRIVE_STATE.DEV_FILE_NAME AS DEV_FILE_NAME," - "DRIVE_STATE.RAW_LIBRARY_SLOT AS RAW_LIBRARY_SLOT," - - "DRIVE_STATE.CURRENT_VO AS CURRENT_VO," - "DRIVE_STATE.NEXT_VO AS NEXT_VO," - "DRIVE_STATE.USER_COMMENT AS USER_COMMENT," - - "DRIVE_STATE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," - "DRIVE_STATE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," - "DRIVE_STATE.CREATION_LOG_TIME AS CREATION_LOG_TIME," - "DRIVE_STATE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," - "DRIVE_STATE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," - "DRIVE_STATE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," - - "DRIVE_STATE.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," - "DRIVE_STATE.RESERVED_BYTES AS RESERVED_BYTES," - "DRIVE_STATE.RESERVATION_SESSION_ID as RESERVATION_SESSION_ID," - "LOGICAL_LIBRARY.IS_DISABLED AS IS_DISABLED " - - "FROM " - "DRIVE_STATE " - "LEFT JOIN " - "LOGICAL_LIBRARY " - "ON " - "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = DRIVE_STATE.LOGICAL_LIBRARY " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DRIVE_NAME", tapeDriveName); - auto rset = stmt.executeQuery(); - - if (rset.next()) { - return gettingSqlTapeDriveValues(&rset);; - } - return std::nullopt; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::setDesiredTapeDriveState(const std::string& tapeDriveName, - const common::dataStructures::DesiredDriveState &desiredState) { - try { - checkCommentOrReasonMaxLength(desiredState.reason); - std::string sql = - "UPDATE DRIVE_STATE SET " - "DESIRED_UP = :DESIRED_UP," - "DESIRED_FORCE_DOWN = :DESIRED_FORCE_DOWN,"; - if(desiredState.reason) { - sql += "REASON_UP_DOWN = "; - sql += desiredState.reason.value().empty() ? "''," : ":REASON_UP_DOWN,"; - } - - // Remove last ',' character - sql.erase(sql.find_last_of(','), 1); - sql += " WHERE " - "DRIVE_NAME = :DRIVE_NAME"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql.c_str()); - - stmt.bindString(":DRIVE_NAME", tapeDriveName); - stmt.bindBool(":DESIRED_UP", desiredState.up); - stmt.bindBool(":DESIRED_FORCE_DOWN", desiredState.forceDown); - if(desiredState.reason && !desiredState.reason.value().empty()) { - stmt.bindString(":REASON_UP_DOWN", desiredState.reason.value()); - } - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify Tape Drive: ") + tapeDriveName + - " because it doesn't exist"); - } - } catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::setDesiredTapeDriveStateComment(const std::string& tapeDriveName, - const std::string &comment) { - try { - const char* const sql = - "UPDATE DRIVE_STATE " - "SET " - "USER_COMMENT = :USER_COMMENT " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - auto bindOptionalStringIfSet = [&stmt](const std::string& sqlField, - const std::optional<std::string>& optionalString) { - if (optionalString) { - if (optionalString.value().empty()) { - stmt.bindString(sqlField, std::nullopt); - } else { - stmt.bindString(sqlField, optionalString.value()); - } - } - }; - - stmt.bindString(":DRIVE_NAME", tapeDriveName); - bindOptionalStringIfSet(":USER_COMMENT", comment); - - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot modify Tape Drive: ") + tapeDriveName + - " because it doesn't exist"); - } - } catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::updateTapeDriveStatistics(const std::string& tapeDriveName, - const std::string& host, const std::string& logicalLibrary, - const common::dataStructures::TapeDriveStatistics& statistics) { - try { - const char *const sql = - "UPDATE DRIVE_STATE " - "SET " - "HOST = :HOST," - "LOGICAL_LIBRARY = :LOGICAL_LIBRARY," - "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," - "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," - "SESSION_ELAPSED_TIME = :REPORT_TIME-SESSION_START_TIME," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME AND DRIVE_STATUS = 'TRANSFERING'"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DRIVE_NAME", tapeDriveName); - stmt.bindString(":HOST", host); - stmt.bindString(":LOGICAL_LIBRARY", logicalLibrary); - stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", statistics.bytesTransferedInSession); - stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", statistics.filesTransferedInSession); - stmt.bindUint64(":REPORT_TIME", statistics.reportTime); - stmt.bindString(":LAST_UPDATE_USER_NAME", statistics.lastModificationLog.username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", statistics.lastModificationLog.host); - stmt.bindUint64(":LAST_UPDATE_TIME", statistics.lastModificationLog.time); - - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - log::LogContext lc(m_log); - lc.log(log::DEBUG, "RdbmsCatalogue::updateTapeDriveStatistics(): It didn't update statistics"); - } - } catch (exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) { - try { - const std::string driveStatusStr = common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus); - - // Case 1 : Drive status stays the same - std::string sql = - "UPDATE DRIVE_STATE SET " - "HOST = :HOST," - "LOGICAL_LIBRARY = :LOGICAL_LIBRARY,"; - - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Transferring) { - sql += - "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," - "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," - "SESSION_ELAPSED_TIME = CASE WHEN SESSION_START_TIME IS NULL THEN 0 ELSE :REPORT_TIME - SESSION_START_TIME END,"; - } - sql += - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME AND DRIVE_STATUS = :DRIVE_STATUS"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql.c_str()); - - stmt.bindString(":DRIVE_NAME", tapeDrive.driveName); - stmt.bindString(":HOST", tapeDrive.host); - stmt.bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); - stmt.bindString(":DRIVE_STATUS", driveStatusStr); - stmt.bindString(":LAST_UPDATE_USER_NAME", tapeDrive.lastModificationLog.value().username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", tapeDrive.lastModificationLog.value().host); - stmt.bindUint64(":LAST_UPDATE_TIME", tapeDrive.lastModificationLog.value().time); - - if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Transferring) { - stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession.value()); - stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession.value()); - stmt.bindUint64(":REPORT_TIME", tapeDrive.transferStartTime.value()); - } - stmt.executeNonQuery(); - - // If the update succeeded, we are done. Otherwise proceed to Case 2. - if(stmt.getNbAffectedRows() > 0) return; - - // Case 2 : Drive status is changing - sql = - "UPDATE DRIVE_STATE SET " - "HOST = :HOST," - "LOGICAL_LIBRARY = :LOGICAL_LIBRARY," - "SESSION_ID = :SESSION_ID," - "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," - "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," - "TRANSFER_START_TIME = :TRANSFER_START_TIME," - "SESSION_ELAPSED_TIME = :SESSION_ELAPSED_TIME," - "UNLOAD_START_TIME = :UNLOAD_START_TIME," - "UNMOUNT_START_TIME = :UNMOUNT_START_TIME," - "DRAINING_START_TIME = :DRAINING_START_TIME," - "DOWN_OR_UP_START_TIME = :DOWN_OR_UP_START_TIME," - "PROBE_START_TIME = :PROBE_START_TIME," - "CLEANUP_START_TIME = :CLEANUP_START_TIME," - "SHUTDOWN_TIME = :SHUTDOWN_TIME," - "MOUNT_TYPE = :MOUNT_TYPE," - "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," - "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," - "LAST_UPDATE_TIME = :LAST_UPDATE_TIME,"; - - if(tapeDrive.driveStatus != common::dataStructures::DriveStatus::Transferring) { - if(tapeDrive.driveStatus != common::dataStructures::DriveStatus::Mounting) { - sql += "SESSION_START_TIME = :SESSION_START_TIME,"; - } - sql += "MOUNT_START_TIME = :MOUNT_START_TIME,"; - } - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Starting) { - sql += "START_START_TIME = :START_START_TIME,"; - } - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Down) { - sql += "DESIRED_UP = :DESIRED_UP," - "DESIRED_FORCE_DOWN = :DESIRED_FORCE_DOWN,"; - } - // If the drive is a state incompatible with space reservation, make sure there is none: - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Up) { - sql += "DISK_SYSTEM_NAME = NULL,"; - sql += "RESERVED_BYTES = NULL,"; - sql += "RESERVATION_SESSION_ID = NULL,"; - sql += "DRIVE_STATUS = CASE WHEN DESIRED_UP = '0' THEN 'DOWN' ELSE 'UP' END,"; - } else { - sql += "DRIVE_STATUS = '" + driveStatusStr + "',"; - } - if(tapeDrive.reasonUpDown) { - sql += "REASON_UP_DOWN = :REASON_UP_DOWN,"; - } - if(tapeDrive.currentVid) { - sql += "CURRENT_VID = :CURRENT_VID,"; - } - if(tapeDrive.currentActivity) { - sql += "CURRENT_ACTIVITY = :CURRENT_ACTIVITY,"; - } - if(tapeDrive.currentTapePool) { - sql += "CURRENT_TAPE_POOL = :CURRENT_TAPE_POOL,"; - } - if(tapeDrive.currentVo) { - sql += "CURRENT_VO = :CURRENT_VO,"; - } - if(tapeDrive.userComment) { - sql += "USER_COMMENT = :USER_COMMENT,"; - } - // Remove last ',' character - sql.erase(sql.find_last_of(','), 1); - sql += - " WHERE " - "DRIVE_NAME = :DRIVE_NAME"; - - stmt.reset(); - stmt = conn.createStmt(sql.c_str()); - - auto setOptionalTime = [&stmt](const std::string& sqlField, const std::optional<time_t>& optionalField) { - if(optionalField) { - stmt.bindUint64(sqlField, optionalField.value()); - } else { - stmt.bindUint64(sqlField, std::nullopt); - } - }; - auto bindOptionalStringIfSet = [&stmt](const std::string& sqlField, const std::optional<std::string>& optionalString) { - if(optionalString) { - if(optionalString.value().empty()) { - stmt.bindString(sqlField, std::nullopt); - } else { - stmt.bindString(sqlField, optionalString.value()); - } - } - }; - - stmt.bindString(":HOST", tapeDrive.host); - stmt.bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); - stmt.bindUint64(":SESSION_ID", tapeDrive.sessionId); - stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession); - stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession); - setOptionalTime(":TRANSFER_START_TIME", tapeDrive.transferStartTime); - setOptionalTime(":SESSION_ELAPSED_TIME", tapeDrive.sessionElapsedTime); - setOptionalTime(":UNLOAD_START_TIME", tapeDrive.unloadStartTime); - setOptionalTime(":UNMOUNT_START_TIME", tapeDrive.unmountStartTime); - setOptionalTime(":DRAINING_START_TIME", tapeDrive.drainingStartTime); - setOptionalTime(":DOWN_OR_UP_START_TIME", tapeDrive.downOrUpStartTime); - setOptionalTime(":PROBE_START_TIME", tapeDrive.probeStartTime); - setOptionalTime(":CLEANUP_START_TIME", tapeDrive.cleanupStartTime); - setOptionalTime(":SHUTDOWN_TIME", tapeDrive.shutdownTime); - stmt.bindString(":MOUNT_TYPE", toString(tapeDrive.mountType)); - stmt.bindString(":LAST_UPDATE_USER_NAME", tapeDrive.lastModificationLog.value().username); - stmt.bindString(":LAST_UPDATE_HOST_NAME", tapeDrive.lastModificationLog.value().host); - stmt.bindUint64(":LAST_UPDATE_TIME", tapeDrive.lastModificationLog.value().time); - - if(tapeDrive.driveStatus != common::dataStructures::DriveStatus::Transferring) { - if(tapeDrive.driveStatus != common::dataStructures::DriveStatus::Mounting) { - setOptionalTime(":SESSION_START_TIME", tapeDrive.sessionStartTime); - } - setOptionalTime(":MOUNT_START_TIME", tapeDrive.mountStartTime); - } - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Starting) { - setOptionalTime(":START_START_TIME", tapeDrive.startStartTime); - } - if(tapeDrive.driveStatus == common::dataStructures::DriveStatus::Down) { - stmt.bindBool(":DESIRED_UP", tapeDrive.desiredUp); - stmt.bindBool(":DESIRED_FORCE_DOWN", tapeDrive.desiredForceDown); - } - bindOptionalStringIfSet(":REASON_UP_DOWN", tapeDrive.reasonUpDown); - bindOptionalStringIfSet(":CURRENT_VID", tapeDrive.currentVid); - bindOptionalStringIfSet(":CURRENT_ACTIVITY", tapeDrive.currentActivity); - bindOptionalStringIfSet(":CURRENT_TAPE_POOL", tapeDrive.currentTapePool); - bindOptionalStringIfSet(":CURRENT_VO", tapeDrive.currentVo); - bindOptionalStringIfSet(":USER_COMMENT", tapeDrive.userComment); - stmt.bindString(":DRIVE_NAME", tapeDrive.driveName); - - stmt.executeNonQuery(); - - if(0 == stmt.getNbAffectedRows()) { - throw exception::UserError(std::string("Cannot update status for drive ") + tapeDrive.driveName + ". Drive not found."); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) { - try { - auto conn = m_connPool.getConn(); - const char *const sql = - "INSERT INTO DRIVE_CONFIG(" "\n" - "DRIVE_NAME," "\n" - "CATEGORY," "\n" - "KEY_NAME," "\n" - "VALUE," "\n" - "SOURCE)" "\n" - "VALUES(" "\n" - ":DRIVE_NAME," "\n" - ":CATEGORY," "\n" - ":KEY_NAME," "\n" - ":VALUE," "\n" - ":SOURCE" "\n" - ")"; - - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DRIVE_NAME", tapeDriveName); - stmt.bindString(":CATEGORY", category); - stmt.bindString(":KEY_NAME", keyName); - if (value.empty()) { - stmt.bindString(":VALUE", std::string("NULL")); - } else { - stmt.bindString(":VALUE", value); - } - if (source.empty()){ - stmt.bindString(":SOURCE", std::string("NULL")); - } else { - stmt.bindString(":SOURCE", source); - } - - stmt.executeNonQuery(); - - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("driveName", tapeDriveName) - .add("category", category) - .add("keyName", keyName) - .add("value", value) - .add("source", source); - lc.log(log::INFO, "Catalogue - created drive configuration"); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::list<std::pair<std::string, std::string>> RdbmsCatalogue::getTapeDriveConfigNamesAndKeys() const { - try { - std::list<std::pair<std::string, std::string>> namesAndKeys; - const char *const sql = - "SELECT " - "DRIVE_NAME AS DRIVE_NAME," - "KEY_NAME AS KEY_NAME " - "FROM " - "DRIVE_CONFIG "; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - - while (rset.next()) { - const std::string driveName = rset.columnString("DRIVE_NAME"); - const std::string key = rset.columnString("KEY_NAME"); - namesAndKeys.push_back(std::make_pair(driveName, key)); - } - return namesAndKeys; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::list<cta::catalogue::Catalogue::DriveConfig> RdbmsCatalogue::getTapeDriveConfigs() const { - try { - const char *const sql = - "SELECT " - "DRIVE_NAME AS DRIVE_NAME," - "CATEGORY AS CATEGORY," - "KEY_NAME AS KEY_NAME," - "VALUE AS VALUE," - "SOURCE AS SOURCE " - "FROM " - "DRIVE_CONFIG "; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - auto rset = stmt.executeQuery(); - std::list<cta::catalogue::Catalogue::DriveConfig> drivesConfigs; - while (rset.next()) { - const std::string tapeDriveName = rset.columnString("DRIVE_NAME"); - const std::string category = rset.columnString("CATEGORY"); - const std::string keyName = rset.columnString("KEY_NAME"); - std::string value = rset.columnString("VALUE"); - std::string source = rset.columnString("SOURCE"); - if (value == "NULL") value.clear(); - if (source == "NULL") source.clear(); - cta::catalogue::Catalogue::DriveConfig driveConfig = {tapeDriveName, category, keyName, value, source}; - drivesConfigs.push_back(driveConfig); - } - return drivesConfigs; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -std::optional<std::tuple<std::string, std::string, std::string>> RdbmsCatalogue::getTapeDriveConfig( - const std::string &tapeDriveName, const std::string &keyName) const { - try { - const char *const sql = - "SELECT " - "DRIVE_NAME AS DRIVE_NAME," - "CATEGORY AS CATEGORY," - "KEY_NAME AS KEY_NAME," - "VALUE AS VALUE," - "SOURCE AS SOURCE " - "FROM " - "DRIVE_CONFIG " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME AND KEY_NAME = :KEY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DRIVE_NAME", tapeDriveName); - stmt.bindString(":KEY_NAME", keyName); - auto rset = stmt.executeQuery(); - if (rset.next()) { - const std::string category = rset.columnString("CATEGORY"); - std::string value = rset.columnString("VALUE"); - std::string source = rset.columnString("SOURCE"); - if (value == "NULL") value.clear(); - if (source == "NULL") source.clear(); - return std::make_tuple(category, value, source); - } - return std::nullopt; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) { - try { - const char *const sql = - "UPDATE DRIVE_CONFIG " - "SET " - "CATEGORY = :CATEGORY," - "VALUE = :VALUE," - "SOURCE = :SOURCE " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME AND KEY_NAME = :KEY_NAME"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - - stmt.bindString(":DRIVE_NAME", tapeDriveName); - stmt.bindString(":CATEGORY", category); - stmt.bindString(":KEY_NAME", keyName); - if (value.empty()) { - stmt.bindString(":VALUE", std::string("NULL")); - } else { - stmt.bindString(":VALUE", value); - } - if (source.empty()){ - stmt.bindString(":SOURCE", std::string("NULL")); - } else { - stmt.bindString(":SOURCE", source); - } - - stmt.executeNonQuery(); - - if (0 == stmt.getNbAffectedRows()) { - throw exception::Exception(std::string("Cannot modify Config Drive with name: ") + tapeDriveName + - " and key" + keyName + " because it doesn't exist"); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) { - try { - const char *const delete_sql = - "DELETE " - "FROM " - "DRIVE_CONFIG " - "WHERE " - "DRIVE_NAME = :DELETE_DRIVE_NAME AND KEY_NAME = :DELETE_KEY_NAME"; - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(delete_sql); - stmt.bindString(":DELETE_DRIVE_NAME", tapeDriveName); - stmt.bindString(":DELETE_KEY_NAME", keyName); - stmt.executeNonQuery(); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getDiskSpaceReservations -//------------------------------------------------------------------------------ -std::map<std::string, uint64_t> RdbmsCatalogue::getDiskSpaceReservations() const { - std::map<std::string, uint64_t> ret; - const auto tdNames = getTapeDriveNames(); - for (const auto& driveName : tdNames) { - const auto tdStatus = getTapeDrive(driveName); - if (tdStatus.value().diskSystemName) { - //no need to check key, operator[] initializes missing values at zero for scalar types - ret[tdStatus.value().diskSystemName.value()] += tdStatus.value().reservedBytes.value(); - } - } - return ret; -} - -//------------------------------------------------------------------------------ -// reserveDiskSpace -//------------------------------------------------------------------------------ -void RdbmsCatalogue::reserveDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { - if(diskSpaceReservation.empty()) return; - - try { - { - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::DEBUG, "In RetrieveMount::reserveDiskSpace(): reservation request."); - } - - // Normally the disk system name will not change. It can change in some rare circumstances, e.g. the tape server is - // assigned to a new VO. - // - // The disk system name is allowed to be updated when RESERVED_BYTES is zero (initial disk reservation, or previous - // disk reservations have been released). Otherwise, to update RESERVED_BYTES, the disk system name has to match. - const char* const sql = - "UPDATE DRIVE_STATE SET " - "RESERVED_BYTES = RESERVED_BYTES + :BYTES_TO_ADD " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME " - "AND DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME " - "AND RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID "; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DRIVE_NAME", driveName); - stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); - stmt.bindUint64(":BYTES_TO_ADD", diskSpaceReservation.begin()->second); - stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); - stmt.executeNonQuery(); - - // If the reservation does not match the <driveName, diskSystem> pair in the DRIVE_STATE table, - // log an error and drop the previous reservation - if(stmt.getNbAffectedRows() != 1) { - { - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::INFO, "In RetrieveMount::releaseDiskSpace(): creating reservation for new mount"); - } - const char* const sql_reset = - "UPDATE DRIVE_STATE SET " - "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME," - "RESERVED_BYTES = :BYTES_TO_ADD," - "RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME"; - stmt.reset(); - stmt = conn.createStmt(sql_reset); - stmt.bindString(":DRIVE_NAME", driveName); - stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); - stmt.bindUint64(":BYTES_TO_ADD", diskSpaceReservation.begin()->second); - stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); - stmt.executeNonQuery(); - if(stmt.getNbAffectedRows() != 1) { - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::ERR, "In RetrieveMount::releaseDiskSpace(): failed to create disk reservation for new mount."); - } - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// releaseDiskSpace -//------------------------------------------------------------------------------ -void RdbmsCatalogue::releaseDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { - if(diskSpaceReservation.empty()) return; - - try { - { - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::DEBUG, "In RetrieveMount::releaseDiskSpace(): reservation release request."); - } - - // If the amount being released exceeds the amount of the reservation, set the reservation to zero - const char* const sql = - "UPDATE DRIVE_STATE SET " - "RESERVED_BYTES = CASE WHEN RESERVED_BYTES > :BYTES_TO_SUBTRACT1 THEN RESERVED_BYTES-:BYTES_TO_SUBTRACT2 ELSE 0 END " - "WHERE " - "DRIVE_NAME = :DRIVE_NAME " - "AND DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME " - "AND RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":DRIVE_NAME", driveName); - stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); - stmt.bindUint64(":BYTES_TO_SUBTRACT1", diskSpaceReservation.begin()->second); - stmt.bindUint64(":BYTES_TO_SUBTRACT2", diskSpaceReservation.begin()->second); - stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); - stmt.executeNonQuery(); - if(stmt.getNbAffectedRows() != 1) { - // If the reservation does not match the <driveName, diskSystem> pair in the DRIVE_STATE table, log an error and carry on - log::ScopedParamContainer params(lc); - params.add("driveName", driveName) - .add("diskSystem", diskSpaceReservation.begin()->first) - .add("reservationBytes", diskSpaceReservation.begin()->second) - .add("mountId", mountId); - lc.log(log::ERR, "In RetrieveMount::releaseDiskSpace(): reservation release request failed, driveName, diskSystem and mountId do not match."); - } - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -void RdbmsCatalogue::checkCommentOrReasonMaxLength(const std::optional<std::string>& str) const { - const size_t MAX_CHAR_COMMENT = 1000; - if (!str.has_value()) return; - if (str.value().length() > MAX_CHAR_COMMENT) { - log::LogContext lc(m_log); - log::ScopedParamContainer spc(lc); - spc.add("Large_Message: ", str.value()); - lc.log(log::ERR, "The reason or comment has more characters than the maximun allowed."); - throw CommentOrReasonWithMoreSizeThanMaximunAllowed( - "The comment or reason string value has more than 1000 characters"); - } -} - -void RdbmsCatalogue::modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, const std::string &diskInstance) const { - const char *const sql = - "UPDATE ARCHIVE_FILE SET " - "DISK_FILE_ID = :FXID," - "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " - "WHERE " - "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; - - auto conn = m_connPool.getConn(); - auto stmt = conn.createStmt(sql); - stmt.bindString(":FXID", fxId); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveId); - stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); - stmt.executeNonQuery(); -} - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/RdbmsCatalogue.hpp b/catalogue/RdbmsCatalogue.hpp deleted file mode 100644 index b46e7f9c5c..0000000000 --- a/catalogue/RdbmsCatalogue.hpp +++ /dev/null @@ -1,2460 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include <memory> -#include <string> - -#include "catalogue/Catalogue.hpp" -#include "catalogue/InsertFileRecycleLog.hpp" -#include "catalogue/RequesterAndGroupMountPolicies.hpp" -#include "catalogue/TimeBasedCache.hpp" -#include "common/dataStructures/TapeCopyToPoolMap.hpp" -#include "common/threading/Mutex.hpp" -#include "rdbms/ConnPool.hpp" -#include "rdbms/Login.hpp" - -namespace cta { -namespace common { -namespace dataStructures { -class TapeFile; -} // namespace dataStructures -} // namespace common -} // namespace cta - -namespace cta { -namespace catalogue { - -class ArchiveFileRow; -class ArchiveFileRowWithoutTimestamps; -class RdbmsCatalogueGetArchiveFilesItor; -class RsetWrapper; - -/** - * CTA catalogue implemented using a relational database backend. - */ -class RdbmsCatalogue: public Catalogue { -protected: - - /** - * Protected constructor only to be called by sub-classes. - * - * @param log Object representing the API to the CTA logging system. - * @param login The database login details to be used to create new - * connections. - * @param nbConns The maximum number of concurrent connections to the - * underlying relational database for all operations accept listing archive - * files which can be relatively long operations. - * @param nbArchiveFileListingConns The maximum number of concurrent - * connections to the underlying relational database for the sole purpose of - * listing archive files. - */ - RdbmsCatalogue( - log::Logger &log, - const rdbms::Login &login, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns); - -public: - - /** - * Destructor. - */ - ~RdbmsCatalogue() override; - - ///////////////////////////////////////////////////////////////////// - // START OF METHODS DIRECTLY INVOLVED IN DATA TRANSFER AND SCHEDULING - ///////////////////////////////////////////////////////////////////// - - /** - * Notifies the catalogue that the specified tape was labelled. - * - * @param vid The volume identifier of the tape. - * @param drive The name of tape drive that was used to label the tape. - */ - void tapeLabelled(const std::string &vid, const std::string &drive) override; - - /** - * Checks the specified archival could take place and returns a new and - * unique archive file identifier that can be used by a new archive file - * within the catalogue. - * - * @param diskInstanceName The name of the disk instance to which the - * storage class belongs. - * @param storageClassName The name of the storage class of the file to be - * archived. The storage class name is only guaranteed to be unique within - * its disk instance. The storage class name will be used by the Catalogue - * to determine the destination tape pool for each tape copy. - * @param user The user for whom the file is to be archived. This will be - * used by the Catalogue to determine the mount policy to be used when - * archiving the file. - * @return The new archive file identifier. - * @throw UserErrorWithTimeBasedCacheInfo if there was a user error. - */ - uint64_t checkAndGetNextArchiveFileId( - const std::string &diskInstanceName, - const std::string &storageClassName, - const common::dataStructures::RequesterIdentity &user) override; - - /** - * Returns the information required to queue an archive request. - * - * @param diskInstanceName The name of the disk instance to which the - * storage class belongs. - * @param storageClassName The name of the storage class of the file to be - * archived. The storage class name is only guaranteed to be unique within - * its disk instance. The storage class name will be used by the Catalogue - * to determine the destination tape pool for each tape copy. - * @param user The user for whom the file is to be archived. This will be - * used by the Catalogue to determine the mount policy to be used when - * archiving the file. - * @return The information required to queue an archive request. - */ - common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria( - const std::string &diskInstanceName, - const std::string &storageClassName, - const common::dataStructures::RequesterIdentity &user) override; - - /** - * Returns the list of tapes that can be written to by a tape drive in the - * specified logical library, in other words tapes that are labelled, not - * disabled, not full, not read-only and are in the specified logical library. - * - * @param logicalLibraryName The name of the logical library. - * @return The list of tapes for writing. - */ - std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const override; - - common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const override; - - /** - * Notifies the CTA catalogue that the specified tape has been mounted in - * order to archive files. - * - * The purpose of this method is to keep track of which drive mounted a given - * tape for archiving files last. - * - * @param vid The volume identifier of the tape. - * @param drive The name of the drive where the tape was mounted. - */ - void tapeMountedForArchive(const std::string &vid, const std::string &drive) override; - - /** - * Prepares for a file retrieval by returning the information required to - * queue the associated retrieve request(s). - * - * @param diskInstanceName The name of the instance from where the retrieval - * request originated - * @param archiveFileId The unique identifier of the archived file that is - * to be retrieved. - * @param user The user for whom the file is to be retrieved. This will be - * used by the Catalogue to determine the mount policy to be used when - * retrieving the file. - * @param activity The activity under which the user wants to start the retrieve - * The call will fail if the activity is set and unknown. - * @param lc The log context. - * - * @return The information required to queue the associated retrieve request(s). - */ - common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile( - const std::string &diskInstanceName, - const uint64_t archiveFileId, - const common::dataStructures::RequesterIdentity &user, - const std::optional<std::string> & activity, - log::LogContext &lc, - const std::optional<std::string> &mountPolicyName = std::nullopt) override; - - /** - * Notifies the CTA catalogue that the specified tape has been mounted in - * order to retrieve files. - * - * The purpose of this method is to keep track of which drive mounted a given - * tape for retrieving files last. - * - * @param vid The volume identifier of the tape. - * @param drive The name of the drive where the tape was mounted. - */ - void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) override; - - /** - * This method notifies the CTA catalogue that there is no more free space on - * the specified tape. - * - * @param vid The volume identifier of the tape. - */ - void noSpaceLeftOnTape(const std::string &vid) override; - - /////////////////////////////////////////////////////////////////// - // END OF METHODS DIRECTLY INVOLVED IN DATA TRANSFER AND SCHEDULING - /////////////////////////////////////////////////////////////////// - - void createAdminUser(const common::dataStructures::SecurityIdentity &admin, const std::string &username, const std::string &comment) override; - void deleteAdminUser(const std::string &username) override; - std::list<common::dataStructures::AdminUser> getAdminUsers() const override; - void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, const std::string &username, const std::string &comment) override; - - /** - * Creates the specified Virtual Organization - * @param admin The administrator. - * @param vo the Virtual Organization - */ - void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo) override; - - /** - * Deletes the specified Virtual Organization - * @param voName the name of the VirtualOrganization to delete - */ - void deleteVirtualOrganization(const std::string &voName) override; - - /** - * Get all the Virtual Organizations from the Catalogue - * @return the list of all the Virtual Organizations - */ - std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const override; - - /** - * Get the virtual organization corresponding to the tapepool passed in parameter - * @param tapepoolName the name of the tapepool which we want the virtual organization - * @return the VirtualOrganization associated to the tapepool passed in parameter - */ - common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool(const std::string & tapepoolName) const override; - - /** - * Get the virtual organization corresponding to the tapepool passed in parameter - * @param conn the database connection - * @param tapepoolName the name of the tapepool which we want the virtual organization - * @return the VirtualOrganization associated to the tapepool passed in parameter - */ - common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool(rdbms::Conn & conn, const std::string & tapepoolName) const; - - /** - * Get, from the cache, the virtual organization corresponding to the tapepool passed in parameter - * @param tapepoolName the name of the tapepool which we want the virtual organization - * @return the VirtualOrganization associated to the tapepool passed in parameter - */ - common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool(const std::string & tapepoolName) const override; - - /** - * Modifies the name of the specified Virtual Organization. - * - * @param currentVoName The current name of the Virtual Organization. - * @param newVoName The new name of the Virtual Organization. - */ - void modifyVirtualOrganizationName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, const std::string &newVoName) override; - - /** - * Modifies the max number of allocated drives for read for the specified Virtual Organization - * - * @param voName the VO name - * @param readMaxDrives the new max number of allocated drives for read for the specified Virtual Organization - */ - void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) override; - - /** - * Modifies the max number of allocated drives for write for the specified Virtual Organization - * - * @param voName the VO name - * @param writeMaxDrives the new max number of allocated drives for write for the specified Virtual Organization - */ - void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) override; - - /** - * Modifies the max file size for the specified Virtual Organization - * - * @param voName the VO name - * @param maxFileSize the new max file size for the specified Virtual Organization - */ - - void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) override; - /** - * Modifies the comment of the specified Virtual Organization - * - * @param voName The name of the Virtual Organization. - * @param comment The new comment of the Virtual Organization. - */ - void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) override; - - /** - * Modifies the Disk Instance name of the specified Virtual Organization - * - * @param voName The name of the Virtual Organization. - * @param diskInstance The new Disk Instance name of the Virtual Organization. - */ - void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) override; - - /** - * Creates the specified storage class. - * - * @param admin The administrator. - * @param storageClass The storage class. - */ - void createStorageClass( - const common::dataStructures::SecurityIdentity &admin, - const common::dataStructures::StorageClass &storageClass) override; - - /** - * Deletes the specified storage class. - * - * @param stoargeClassName The name of the storage class which is only - * guaranteed to be unique within its disk isntance. - */ - void deleteStorageClass(const std::string &storageClassName) override; - - std::list<common::dataStructures::StorageClass> getStorageClasses() const override; - common::dataStructures::StorageClass getStorageClass(const std::string &name) const override; - - - void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbCopies) override; - void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override; - /** - * Modifies the name of the specified storage class. - * - * @param currentName The current name of the storage class. - * @param newName The new name of the storage class. - */ - void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; - - /** - * Creates a tape media type. - * - * @param mediaType The tape media type. - */ - void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) override; - - /** - * Deletes the specified tape media type. - * - * @param name The name of the tape media type. - */ - void deleteMediaType(const std::string &name) override; - - /** - * Returns all tape media types. - * - * @return All tape media types. - */ - std::list<MediaTypeWithLogs> getMediaTypes() const override; - - /** - * Return the media type associated to the tape corresponding to the - * vid passed in parameter - * - * @param vid the vid of the tape to return its media type - * @return the media type associated to the tape corresponding to the vid passed in parameter - */ - MediaType getMediaTypeByVid(const std::string & vid) const override; - - /** - * Modifies the name of the specified tape media type. - * - * @param currentName The current name of the tape media type. - * @param newName The new name of the tape media type. - */ - void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; - - /** - * Modifies the cartidge of the specified tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param cartridge The new cartidge. - */ - void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &cartridge) override; - - /** - * Modify the capacity in bytes of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param capacityInBytes The new capacity in bytes. - */ - void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) override; - - /** - * Modify the SCSI primary density code a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param primaryDensityCode The new SCSI primary density code. - */ - void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) override; - - /** - * Modify the SCSI secondary density code a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param secondaryDensityCode The new SCSI secondary density code. - */ - void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) override; - - /** - * Modify the number of tape wraps of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param nbWraps The new number of tape wraps. - */ - void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint32_t> &nbWraps) override; - - /** - * Modify the minimum longitudinal tape position of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param minLPos The new minimum longitudinal tape position. - */ - void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &minLPos) override; - - /** - * Modify the maximum longitudinal tape position of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param maxLPos The new maximum longitudinal tape position. - */ - void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::optional<std::uint64_t> &maxLPos) override; - - /** - * Modify the comment of a tape media type. - * - * @param admin The administrator. - * @param name The name of the tape media type. - * @param comment The new comment. - */ - void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - - void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, const std::optional<std::string> &supply, const std::string &comment) override; - void deleteTapePool(const std::string &name) override; - std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria) const override; - - std::list<TapePool> getTapePools(rdbms::Conn &conn, const TapePoolSearchCriteria &searchCriteria) const; - - /** - * @return The tape pool with the specified name. - * @param tapePoolName The name of the tape pool. - */ - std::optional<TapePool> getTapePool(const std::string &tapePoolName) const override; - - void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &vo) override; - void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbPartialTapes) override; - void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - 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 &storageClassName, - const uint32_t copyNb, - const std::string &tapePoolName, - const std::string &comment) override; - - - /** - * Deletes the specified archive route. - * - * @param storageClassName The name of the storage class which is unique - * @param copyNb The copy number of the tape file. - */ - void deleteArchiveRoute( - const std::string &storageClassName, - const uint32_t copyNb) override; - - std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const override; - - /** - * @return the archive routes of the given storage class and destination tape - * pool. - * - * Under normal circumstances this method should return either 0 or 1 route. - * For a given storage class there should be no more than one route to any - * given tape pool. - * - * @param storageClassName The name of the storage class which is unique - * @param tapePoolName The name of the tape pool. - */ - std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes( - const std::string &storageClassName, - const std::string &tapePoolName) const override; - - void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override; - void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) override; - - void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool isDisabled, const std::string &comment) override; - void deleteLogicalLibrary(const std::string &name) override; - std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const override; - - /** - * Modifies the name of the specified logical library. - * - * @param admin The administrator. - * @param currentName The current name of the logical library. - * @param newName The new name of the logical library. - */ - void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) override; - - void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &disabledReason) override; - virtual void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) override; - - /** - * Creates a tape which is assumed to have isFromCastor disabled. - * - * @param admin The administrator. - * @param tape The attributes of the tape to be created. - */ - void createTape( - const common::dataStructures::SecurityIdentity &admin, - const CreateTapeAttributes & tape) override; - - void deleteTape(const std::string &vid) override; - - /** - * Returns the list of tapes that meet the specified search criteria. - * - * @param searchCriteria The search criteria. - * @return The list of tapes. - */ - std::list<common::dataStructures::Tape> getTapes(const TapeSearchCriteria &searchCriteria) const override; - - /** - * Returns the tape with the specified volume identifier. - * - * This method will throw an exception if it cannot find the specified tape. - * - * @param vid The tape volume identifier (VIDs). - * @return Map from tape volume identifier to tape. - */ - common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const override; - - /** - * Returns the tapes with the specified volume identifiers. - * - * This method will throw an exception if it cannot find ALL of the specified - * tapes. - * - * @param vids The tape volume identifiers (VIDs). - * @return Map from tape volume identifier to tape. - */ - common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const override; - - /** - * Returns map from VID to logical library name for specified set of VIDs. - * - * @param vids The tape volume identifiers (VIDs). - * @return map from VID to logical library name. - */ - std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const override; - - /** - * Reclaims the specified tape. - * - * This method will throw an exception if the specified tape does not exist. - * - * This method will throw an exception if the specified tape is not FULL. - * - * This method will throw an exception if there is still at least one tape - * file recorded in the catalogue as being on the specified tape. - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be reclaimed. - * @param lc the logContext - */ - void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, cta::log::LogContext & lc) override; - - /** - * Checks the specified tape for the tape label command. - * - * This method checks if the tape is safe to be labeled and will throw an - * exception if the specified tape does not ready to be labeled. - * - * @param vid The volume identifier of the tape to be checked. - */ - void checkTapeForLabel(const std::string &vid) override; - - /** - * Returns the number of any files contained in the tape identified by its vid - * @param vid the vid in which we will count the number of files - * @return the number of files on the tape - */ - uint64_t getNbFilesOnTape(const std::string &vid) const override; - - /** - * Returns the number of any files contained in the tape identified by its vid - * @param conn the database connection - * @param vid the vid in which we will count the number of files - * @return the number of files on the tape - */ - uint64_t getNbFilesOnTape(rdbms::Conn &conn, const std::string &vid) const; - - /** - * Delete all the tape files of the VID passed in parameter - * @param conn the database connection - * @param vid the vid in which we want to remove all the tape files - */ - void deleteTapeFiles(rdbms::Conn &conn, const std::string& vid) const; - - /** - * Set the DIRTY flag to true - * @param conn the database connection - * @param vid the vid in which we want to set it as dirty - */ - void setTapeDirty(rdbms::Conn &conn, const std::string &vid) const; - - /** - * Reset the counters of a tape - * @param conn the database connection - * @param admin the administrator - * @param vid the vid to reset the counters - */ - void resetTapeCounters(rdbms::Conn &conn, const common::dataStructures::SecurityIdentity &admin ,const std::string& vid) const; - void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &mediaType) override; - void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &vendor) override; - void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &logicalLibraryName) override; - void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &tapePoolName) override; - void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &encryptionKeyName) override; - void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string &verificationStatus) override; - void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, const common::dataStructures::Tape::State & state, const std::optional<common::dataStructures::Tape::State> & prev_state, const std::optional<std::string> & stateReason) override; - static std::string generateTapeStateModifiedBy(const common::dataStructures::SecurityIdentity & admin); - /** - * Sets the full status of the specified tape. - * - * Please note that this method is to be called by the CTA front-end in - * response to a command from the CTA command-line interface (CLI). - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be marked as full. - * @param fullValue Set to true if the tape is full. - */ - void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const bool fullValue) override; - - /** - * Sets the dirty status of the specified tape. - * - * Please note that this method is to be called by the CTA front-end in - * response to a command from the CTA command-line interface (CLI). - * - * @param admin The administrator. - * @param vid The volume identifier of the tape to be marked as full. - * @param dirtyValue Set to true if the tape is dirty. - */ - void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const bool dirtyValue) override; - - /** - * This method notifies the CTA catalogue to set the specified tape is from CASTOR. - * This method only for unitTests and MUST never be called in CTA!!! - * - * @param vid The volume identifier of the tape. - */ - void setTapeIsFromCastorInUnitTests(const std::string &vid) override; - - void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string & reason) override; - void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::string & reason) override; - void setTapeDirty(const std::string & vid) override; - void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, const std::optional<std::string> &comment) override; - - void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) override; - void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, const std::string &comment) override; - void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) override; - void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterName, const std::string &comment) override; - void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) override; - void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) override; - - void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, const CreateMountPolicyAttributes & mountPolicy) override; - - /** - * Returns the list of all existing mount policies. - * - * @return the list of all existing mount policies. - */ - std::list<common::dataStructures::MountPolicy> getMountPolicies() const override; - - /** - * Returns the mount policy with the specified name. - * - * @return the specified mount policy - */ - std::optional<common::dataStructures::MountPolicy> getMountPolicy(const std::string &mountPolicyName) const override; - - /** - * Returns the mount policy with the specified name. - * - * @return the specified mount policy - */ - std::optional<common::dataStructures::MountPolicy> getMountPolicy(rdbms::Conn &conn, const std::string &mountPolicyName) const; - - /** - * Returns the list of all existing mount policies. - * - * @param conn the database connection - * @return the list of all existing mount policies. - */ - std::list<common::dataStructures::MountPolicy> getMountPolicies(rdbms::Conn & conn) const; - - /** - * Returns the cached list of all existing mount policies. - * - * @return the list of all existing mount policies. - */ - std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const override; - - /** - * Deletes the specified mount policy. - * - * @param name The name of the mount policy. - */ - void deleteMountPolicy(const std::string &name) override; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester+matching activities. - * - * Please note that requester-activity mount-rules overrule requester - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstance The name of the disk instance to which the requester - * belongs. - * @param activityRegex The regex to match request activities - * @param requesterName The name of the requester which is only guarantted to - * be unique within its disk instance. - * @param comment Comment. - */ - void createRequesterActivityMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstance, - const std::string &requesterName, - const std::string &activityRegex, - const std::string &comment) override; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester + activity. - * - * @return the rules that specify which mount policy is be used for which - * requester + activity. - */ - std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const override; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester belongs. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - * @param activityRegex The regex to match request activities - */ - void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) override; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester. - * - * Please note that requester mount-rules overrule requester-group - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstance The name of the disk instance to which the requester - * belongs. - * @param requesterName The name of the requester which is only guarantted to - * be unique within its disk instance. - * @param comment Comment. - */ - void createRequesterMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstance, - const std::string &requesterName, - const std::string &comment) override; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester. - * - * @return the rules that specify which mount policy is be used for which - * requester. - */ - std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const override; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester belongs. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - */ - void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) override; - - /** - * Creates the rule that the specified mount policy will be used for the - * specified requester group. - * - * Please note that requester mount-rules overrule requester-group - * mount-rules. - * - * @param admin The administrator. - * @param mountPolicyName The name of the mount policy. - * @param diskInstanceName The name of the disk instance to which the - * requester group belongs. - * @param requesterGroupName The name of the requester group which is only - * guarantted to be unique within its disk instance. - * @param comment Comment. - */ - void createRequesterGroupMountRule( - const common::dataStructures::SecurityIdentity &admin, - const std::string &mountPolicyName, - const std::string &diskInstanceName, - const std::string &requesterGroupName, - const std::string &comment) override; - - /** - * Returns the rules that specify which mount policy is be used for which - * requester group. - * - * @return the rules that specify which mount policy is be used for which - * requester group. - */ - std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const override; - - /** - * Deletes the specified mount rule. - * - * @param diskInstanceName The name of the disk instance to which the - * requester group belongs. - * @param requesterGroupName The name of the requester group which is only - * guaranteed to be unique within its disk instance. - */ - void deleteRequesterGroupMountRule( - const std::string &diskInstanceName, - const std::string &requesterGroupName) override; - - void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t archivePriority) override; - void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minArchiveRequestAge) override; - void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t retrievePriority) override; - void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minRetrieveRequestAge) override; - void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) override; - - /** - * Returns all the disk systems within the CTA catalogue. - * - * @return The disk systems. - * requester group. - */ - disk::DiskSystemList getAllDiskSystems() const override; - - /** - * Creates a disk system. - * - * @param admin The administrator. - * @param name The name of the disk system. - * @param fileRegexp The regular expression allowing matching destination URLs - * for this disk system. - * @param freeSpaceQueryURL The query URL that describes a method to query the - * free space from the disk system. - * @param refreshInterval The refresh interval (seconds) defining how long do - * we use a free space value. - * @param targetedFreeSpace The targeted free space (margin) based on the free - * space update latency (inherent to the file system and induced by the refresh - * interval), and the expected external bandwidth from sources external to CTA. - * @param comment Comment. - */ - void createDiskSystem( - const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &diskInstanceName, - const std::string &diskInstanceSpaceName, - const std::string &fileRegexp, - const uint64_t targetedFreeSpace, - const time_t sleepTime, - const std::string &comment) override; - - /** - * Deletes a disk system. - * - * @param name The name of the disk system. - */ - void deleteDiskSystem(const std::string &name) override; - - void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &fileRegexp) override; - void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const uint64_t targetedFreeSpace) override; - void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) override; - void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, - const std::string& name, const uint64_t sleepTime) override; - void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceName) override; - void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstanceSpaceName) override; - - /** - * Creates the specified Disk Instance - * @param admin The administrator. - * @param name the name of the new disk instance - * @param comment the comment of the new disk instance - */ - void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &comment) override; - - /** - * Returns all the disk instances within the CTA catalogue. - * - * @return The disk instances in the CTA catalogue. - */ - std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const override; - - /** - * Deletes a disk instance. - * - * @param name The name of the disk instance. - */ - void deleteDiskInstance(const std::string &name) override; - - /** - * Changes the comment of the specified disk instance - * @param admin The administrator. - * @param name the name of the disk instance - * @param comment the new comment of the disk instance - */ - void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &comment) override; - - /** - * Deletes a disk instance space. - * - * @param name The name of the disk instance. - * @param diskInstance The disk instance of the disk instance space. - */ - void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) override; - - /** - * Creates the specified Disk Instance Space - * @param admin The administrator. - * @param name the name of the new disk instance space - * @param diskInstance the disk instance associated to the disk instance space - * @param freeSpaceQueryURL the URL to query to obtain the disk instance space free space - * @param refreshInterval the period to query for disk instance space free space - * @param comment the comment of the new disk instance space - */ - void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, - const std::string &diskInstance, - const std::string &freeSpaceQueryURL, - const uint64_t refreshInterval, - const std::string &comment) override; - - /** - * Returns all the disk instance spaces within the CTA catalogue. - * - * @return The disk instance spaces in the CTA catalogue. - */ - std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const override; - - void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &comment) override; - void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) override; - void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, - const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) override; - void modifyDiskInstanceSpaceFreeSpace(const std::string &name, const std::string &diskInstance, const uint64_t freeSpace) override; - - /** - * Throws a UserError exception if the specified searchCriteria is not valid - * due to a user error. - * - * @param searchCriteria The search criteria. - */ - void checkTapeFileSearchCriteria(const TapeFileSearchCriteria &searchCriteria) const; - - /** - * 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 checkTapeFileSearchCriteria(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const; - - /** - * Returns the specified archive files. Please note that the list of files - * is ordered by archive file ID. - * - * @param searchCriteria The search criteria. - * @return The archive files. - */ - ArchiveFileItor getArchiveFilesItor(const TapeFileSearchCriteria &searchCriteria) const override; - - - /** - * Returns the specified archive files. Please note that the list of files - * is ordered by archive file ID. - * - * @param conn The database connection. - * @param searchCriteria The search criteria. - * @return The archive files. - */ - ArchiveFileItor getArchiveFilesItor(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const; - - /** - * 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(cta::rdbms::Conn &conn, const RecycleTapeFileSearchCriteria & searchCriteria) const; - - /** - * Returns all the currently deleted files by looking at the FILE_RECYCLE_LOG table - * - * @param searchCriteria The search criteria - * @return The deleted archive files ordered by archive file ID. - */ - FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const override; - - /** - * Restores the deleted file in the Recycle log that match the criteria passed - * - * @param searchCriteria The search criteria - * @param newFid the new Fid of the archive file (if the archive file must be restored) - */ - void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, const std::string &newFid) override; - - /** - * Copy the fileRecycleLog to the ARCHIVE_FILE with a new eos fxid - * @param conn the database connection - * @param fileRecycleLog the fileRecycleLog we want to restore - * @param newFid the new eos file id of the archive file - * @param lc the log context - */ - void restoreArchiveFileInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLogItor, - const std::string &newFid, log::LogContext & lc); - - /** - * Returns the specified files in tape file sequence order. - * - * @param vid The volume identifier of the tape. - * @param startFSeq The file sequence number of the first file. Please note - * that there might not be a file with this exact file sequence number. - * @param maxNbFiles The maximum number of files to be returned. - * @return The specified files in tape file sequence order. - */ - std::list<common::dataStructures::ArchiveFile> getFilesForRepack( - const std::string &vid, - const uint64_t startFSeq, - const uint64_t maxNbFiles) const override; - - /** - * Returns all the tape copies (no matter their VIDs) of the archive files - * associated with the tape files on the specified tape in FSEQ order - * starting at the specified startFSeq. - * - * @param vid The volume identifier of the tape. - * @param startFSeq The file sequence number of the first file. Please note - * that there might not be a file with this exact file sequence number. - * @return The specified files in FSEQ order. - */ - ArchiveFileItor getArchiveFilesForRepackItor( - const std::string &vid, - const uint64_t startFSeq) const override; - - /** - * Returns a summary of the tape files that meet the specified search - * criteria. - * - * @param searchCriteria The search criteria. - * @return The summary. - */ - common::dataStructures::ArchiveFileSummary getTapeFileSummary( - const TapeFileSearchCriteria &searchCriteria) const override; - - /** - * Returns the specified archive file. If the search criteria result in more than one tape file being returned - * an exception is thrown. - * @param searchCriteria The search criteria. - * @return The archive file. - */ - common::dataStructures::ArchiveFile getArchiveFileForDeletion(const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; - - /** - * Deletes a tape file copy - * - * @param file The tape file to delete - * @param reason The reason for deleting the tape file copy - */ - void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) override; - - /** - * Returns the archive file with the specified unique identifier. - * - * This method assumes that the archive file being requested exists and will - * therefore throw an exception if it does not. - * - * Please note that an archive file with no associated tape files is - * considered not to exist by this method. - * - * @param id The unique identifier of the archive file. - * @return The archive file. - */ - common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override; - - /** - * Returns true if the specified user has administrator privileges. - * - * @param admin The administrator. - * @return True if the specified user has administrator privileges. - */ - bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const override; - - /** - * Checks that the most trivial query goes through. Returns true on success, - * false on failure. - * - * @return True if the query went through. - */ - void ping() override; - - /** - * Checks that the online database schema MAJOR version number matches the schema MAJOR version number defined in version.h - */ - void verifySchemaVersion() override; - - /** - * Returns the SchemaVersion object corresponding to the catalogue schema version: - * - SCHEMA_VERSION_MAJOR - * - SCHEMA_VERSION_MINOR - * - SCHEMA_VERSION_MAJOR_NEXT (future major version number of the schema in case of upgrade) - * - SCHEMA_VERSION_MINOR_NEXT (future minor version number of the schema in case of upgrade) - * - STATUS (UPGRADING or PRODUCTION) - * - * @return The SchemaVersion object corresponding to the catalogue schema version - */ - SchemaVersion getSchemaVersion() const override; - - /** - * Returns the names of all the tables in the database schema in alphabetical - * order. - * - * @return The names of all the tables in the database schema in alphabetical - * order. - */ - std::list<std::string> getTableNames() const; - -protected: - - /** - * Object representing the API to the CTA logging system. - */ - log::Logger &m_log; - - /** - * Mutex to be used to a take a global lock on the database. - */ - threading::Mutex m_mutex; - - /** - * The pool of connections to the underlying relational database to be used - * for all operations accept listing archive files which can be relatively - * long operations. - */ - mutable rdbms::ConnPool m_connPool; - - /** - * The pool of connections to the underlying relational database to be used - * for the sole purpose of listing archive files. - */ - mutable rdbms::ConnPool m_archiveFileListingConnPool; - - /** - * Returns true if the specified admin user exists. - * - * @param conn The database connection. - * @param adminUsername The name of the admin user. - * @return True if the admin user exists. - */ - bool adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const; - - /** - * Returns true if the specified vo exists. - * - * @param conn The database connection. - * @param voName The name of the vo - * @return True if the vo exists, false otherwise - */ - bool virtualOrganizationExists(rdbms::Conn &conn, const std::string &voName) const; - - /** - * Returns true if the specified media type exists. - * - * @param conn The database connection. - * @param name The name of the media type. - * @return True if the media type exists. - */ - bool mediaTypeExists(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns true if the specified storage class exists. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class. - * @return True if the storage class exists. - */ - bool storageClassExists(rdbms::Conn &conn, const std::string &storageClassName) const; - - /** - * Returns true if the specified tape pool exists. - * - * @param tapePoolName The name of the tape pool. - * @return True if the tape pool exists. - */ - bool tapePoolExists(const std::string &tapePoolName) const override; - - /** - * Returns true if the specified tape pool exists. - * - * @param conn The database connection. - * @param tapePoolName The name of the tape pool. - * @return True if the tape pool exists. - */ - bool tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) const; - - /** - * Returns true if the specified tape pool is used in an archive route. - * - * @param conn The database connection. - * @param tapePoolName The name of the tape pool. - * @return True if the tape pool is used in an archive route. - */ - bool tapePoolUsedInAnArchiveRoute(rdbms::Conn &conn, const std::string &tapePoolName) const; - - /** - * Returns true if the specified archive file identifier exists. - * - * @param conn The database connection. - * @param archiveFileId The archive file identifier. - * @return True if the archive file identifier exists. - */ - bool archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) const; - - /** - * @param newStorageClassName The name of the storage class - * @param archiveFileId Id for file found in ARCHIVE_FILE - */ - void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, const std::string& newStorageClassName) const override; - - /** - * Changes the fxid in for a archive file - * @param archiveId The archive file id - * @param fxId The eos fxid related to the archive file - * @param diskInstance Disk instace - */ - void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, const std::string &diskInstance) const override; -/** - * Returns true if the specified disk file identifier exists. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the disk - * file identifier belongs. - * @param diskFileId The disk file identifier. - * @return True if the disk file identifier exists. - */ - bool diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFileId) const; - - /** - * Returns true if the specified disk file user exists. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the disk file user belongs. - * @param diskFileOwnerUid The user ID of the disk file owner. - * @return True if the disk file user exists. - */ - bool diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName, uint32_t diskFileOwnerUid) const; - - /** - * Returns true if the specified disk file group exists. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the disk file group belongs. - * @param diskFileGid The group ID of the disk file. - * @return True if the disk file group exists. - */ - bool diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName, uint32_t diskFileGid) const; - - /** - * Returns true if the specified archive route exists. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class which is only - * guaranteed to be unique within its disk instance. - * @param copyNb The copy number of the tape file. - * @return True if the archive route exists. - */ - bool archiveRouteExists(rdbms::Conn &conn, const std::string &storageClassName, - const uint32_t copyNb) const; - - /** - * @return the archive routes of the given storage class and destination tape - * pool. - * - * Under normal circumstances this method should return either 0 or 1 route. - * For a given storage class there should be no more than one route to any - * given tape pool. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class which is only - * guaranteed to be unique within its disk instance. - * @param tapePoolName The name of the tape pool. - */ - std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(rdbms::Conn &conn, - const std::string &storageClassName, const std::string &tapePoolName) const; - - /** - * Returns true if the specified tape exists. - * - * @param vid The volume identifier of the tape. - * @return True if the tape exists. - */ - bool tapeExists(const std::string &vid) const override; - - /** - * Returns true if the specified tape exists. - * - * @param conn The database connection. - * @param vid The volume identifier of the tape. - * @return True if the tape exists. - */ - bool tapeExists(rdbms::Conn &conn, const std::string &vid) const; - - /** - * Returns true if the specified disk system exists. - * - * @param name The name identifier of the disk system. - * @return True if the tape exists. - */ - bool diskSystemExists(const std::string &name) const override; - - /** - * Returns true if the specified disk system exists. - * - * @param conn The database connection. - * @param name The name identifier of the disk system. - * @return True if the disk system exists. - */ - bool diskSystemExists(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns true if the specified disk instance exists. - * - * @param conn The database connection. - * @param name The name identifier of the disk instance. - * @return True if the disk instance exists. - */ - bool diskInstanceExists(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns true if the specified disk instance space exists. - * - * @param conn The database connection. - * @param name The name identifier of the disk instance space. - * @param diskInstance the disk instance associated to the disk instance space - * @return True if the disk instance exists. - */ - bool diskInstanceSpaceExists(rdbms::Conn &conn, const std::string &name, const std::string &diskInstance) const; - - - /** - * Returns the list of tapes that meet the specified search criteria. - * - * @param conn The database connection. - * @param searchCriteria The search criteria. - * @return The list of tapes. - */ - std::list<common::dataStructures::Tape> getTapes(rdbms::Conn &conn, const TapeSearchCriteria &searchCriteria) const; - - /** - * Returns true if the specified logical library exists. - * - * @param conn The database connection. - * @param logicalLibraryName The name of the logical library. - * @return True if the logical library exists. - */ - bool logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName) const; - - /** - * Returns true if the specified mount policy exists. - * - * @param conn The database connection. - * @param mountPolicyName The name of the mount policy - * @return True if the mount policy exists. - */ - bool mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName) const; - - /** - * Returns true if the specified requester mount-rule exists. - * - * @param diskInstanceName The name of the disk instance to which the - * requester belongs. - * @param requesterName The username of the requester which is only guaranteed - * to be unique within its disk instance. - * @return True if the requester mount-rule exists. - */ - bool requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, - const std::string &requesterName) const; - - /** - * A fully qualified user, in other words the name of the disk instance and - * the name of the group. - */ - struct User { - /** - * The name of the disk instance to which the user name belongs. - */ - std::string diskInstanceName; - - /** - * The name of the user which is only guaranteed to be unique within its - * disk instance. - */ - std::string username; - - /** - * Constructor. - * - * @param d The name of the disk instance to which the group name belongs. - * @param u The name of the group which is only guaranteed to be unique - * within its disk instance. - */ - User(const std::string &d, const std::string &u): diskInstanceName(d), username(u) { - } - - /** - * Less than operator. - * - * @param rhs The argument on the right hand side of the operator. - * @return True if this object is less than the argument on the right hand - * side of the operator. - */ - bool operator<(const User &rhs) const { - return diskInstanceName < rhs.diskInstanceName || username < rhs.username; - } - }; // struct User - - /** - * Returns a cached version of the specified requester mount-policy or std::nullopt - * if one does not exist. - * - * @param user The fully qualified user, in other words the name of the disk - * instance and the name of the group. - * @return The mount policy or std::nullopt if one does not exists. - * @throw UserErrorWithTimeBasedCacheInfo if there was a user error. - */ - ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy> > getCachedRequesterMountPolicy(const User &user) const; - - /** - * Returns true if the specified requester+activity mount-policy exists - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the - * requester and requester group belong. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - * @param activityRegex The regex to match request activities - * @return True if the requester-activity mount-rule exists - */ - bool requesterActivityMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) const; - - /** - * Returns the specified requester mount-policy or std::nullopt if one does not - * exist. - * - * @param conn The database connection. - * @param user The fully qualified user, in other words the name of the disk - * instance and the name of the group. - * @return The mount policy or std::nullopt if one does not exists. - */ - std::optional<common::dataStructures::MountPolicy> getRequesterMountPolicy(rdbms::Conn &conn, const User &user) const; - - /** - * Returns true if the specified requester-group mount-rule exists. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the - * requester group belongs. - * @param requesterGroupName The name of the requester group which is only - * guaranteed to be unique within its disk instance. - * @return True if the requester-group mount-rule exists. - */ - bool requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, - const std::string &requesterGroupName) const; - - /** - * A fully qualified user group, in other words the name of the disk instance - * and the name of the group. - */ - struct Group { - /** - * The name of the disk instance to which the group name belongs. - */ - std::string diskInstanceName; - - /** - * The name of the group which is only guaranteed to be unique within its - * disk instance. - */ - std::string groupName; - - /** - * Constructor. - * - * @param d The name of the disk instance to which the group name belongs. - * @param g The name of the group which is only guaranteed to be unique - * within its disk instance. - */ - Group(const std::string &d, const std::string &g): diskInstanceName(d), groupName(g) { - } - - /** - * Less than operator. - * - * @param rhs The argument on the right hand side of the operator. - * @return True if this object is less than the argument on the right hand - * side of the operator. - */ - bool operator<(const Group &rhs) const { - return diskInstanceName < rhs.diskInstanceName || groupName < rhs.groupName; - } - }; // struct Group - - /** - * Returns a cached version of the specified requester-group mount-policy or - * nullptr if one does not exist. - * - * This method updates the cache when necessary. - * - * @param group The fully qualified group, in other words the name of the disk - * instance and the name of the group. - * @return The cached mount policy or std::nullopt if one does not exists. - */ - ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy> > getCachedRequesterGroupMountPolicy(const Group &group) const; - - /** - * Returns the specified requester-group mount-policy or nullptr if one does - * not exist. - * - * @param conn The database connection. - * @param group The fully qualified group, in other words the name of the disk - * instance and the name of the group. - * @return The mount policy or std::nullopt if one does not exists. - */ - std::optional<common::dataStructures::MountPolicy> getRequesterGroupMountPolicy(rdbms::Conn &conn, const Group &group) - const; - - /** - * Returns the specified tape log information from the specified database - * result set. - * - * @param rset The result set. - * @param driveColName The name of the database column that contains the name - * of the tape drive. - * @param timeColNAme The name of the database column that contains the time - * stamp. - */ - std::optional<common::dataStructures::TapeLog> getTapeLogFromRset(const rdbms::Rset &rset, - const std::string &driveColName, const std::string &timeColName) const; - - /** - * An RdbmsCatalogue specific method that inserts the specified row into the - * ArchiveFile table. - * - * @param conn The database connection. - * @param row The row to be inserted. - */ - void insertArchiveFile(rdbms::Conn &conn, const ArchiveFileRowWithoutTimestamps &row); - - /** - * Creates the database schema. - */ - void createDbSchema(); - - /** - * A fully qualified storage class, in other words the name of the disk - * instance and the name of the storage class. - */ - struct StorageClass { - - /** - * The name of the storage class which is only guaranteed to be unique - */ - std::string storageClassName; - - /** - * Constructor. - * - * @param sN The name of the storage class which is only guaranteed to be - * unique within its disk instance. - */ - StorageClass(const std::string &s): storageClassName(s) { - } - - /** - * Less than operator. - * - * @param rhs The argument on the right hand side of the operator. - * @return True if this object is less than the argument on the right hand - * side of the operator. - */ - bool operator<(const StorageClass &rhs) const { - return storageClassName < rhs.storageClassName; - } - }; // struct StorageClass - - /** - * Returns a cached version of the expected number of archive routes for the - * specified storage class as specified by the call to the - * createStorageClass() method as opposed to the actual number entered so far - * using the createArchiveRoute() method. - * - * This method updates the cache when necessary. - * - * @param storageClass The fully qualified storage class, in other words the - * name of the disk instance and the name of the storage class. - * @return The expected number of archive routes. - */ - uint64_t getCachedExpectedNbArchiveRoutes(const StorageClass &storageClass) const; - - /** - * Returns the expected number of archive routes for the specified storage - * class as specified by the call to the createStorageClass() method as - * opposed to the actual number entered so far using the createArchiveRoute() - * method. - * - * @param conn The database connection. - * @param storageClass The fully qualified storage class, in other words the - * name of the disk instance and the name of the storage class. - * @return The expected number of archive routes. - */ - uint64_t getExpectedNbArchiveRoutes(rdbms::Conn &conn, const StorageClass &storageClass) const; - - /** - * Inserts the specified tape file into the Tape table. - * - * @param conn The database connection. - * @param tapeFile The tape file. - * @param archiveFileId The identifier of the archive file of which the tape - * file is a copy. - */ - void insertTapeFile( - rdbms::Conn &conn, - const common::dataStructures::TapeFile &tapeFile, - const uint64_t archiveFileId); - - /** - * Sets the last FSeq of the specified tape to the specified value. - * - * @param conn The database connection. - * @param vid The volume identifier of the tape. - * @param lastFseq The new value of the last FSeq. - */ - void setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq); - - /** - * Returns the last FSeq of the specified tape. - * - * @param conn The database connection. - * @param vid The volume identifier of the tape. - * @return The last FSeq. - */ - uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const; - - /** - * Updates the specified tape with the specified information. - * - * @param conn The database connection. - * @param vid The volume identifier of the tape. - * @param lastFSeq The sequence number of the last tape file written to the - * tape. - * @param compressedBytesWritten The number of compressed bytes written to - * the tape. - * @param filesWritten The number of files written to tape - * @param tapeDrive The name of the tape drive that last wrote to the tape. - */ - void updateTape( - rdbms::Conn &conn, - const std::string &vid, - const uint64_t lastFSeq, - const uint64_t compressedBytesWritten, - const uint64_t filesWritten, - const std::string &tapeDrive); - - /** - * Returns the archive file with the specified unique identifier or nullptr if - * it does not exist. - * - * Please note that an archive file with no associated tape files is - * considered not to exist by this method. - * - * @param conn The database connection. - * @param id The unique identifier of the archive file. - * @return The archive file. - */ - std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileById(rdbms::Conn &conn, const uint64_t archiveFileId) const; - - /** - * Returns the specified archive file row. A nullptr pointer is returned if - * there is no corresponding row in the ARCHIVE_FILE table. - * - * @param conn The database connection. - * @param id The identifier of the archive file. - * @return The archive file row or nullptr. - */ - std::unique_ptr<ArchiveFileRow> getArchiveFileRowById(rdbms::Conn &conn, const uint64_t id) const; - - /** - * Returns the specified archive file. A nullptr pointer is returned if - * there are no corresponding rows in the TAPE_FILE table. Only looks at TAPE_FILE entries - * on Tapes with state 'ACTIVE' - * - * @param conn The database connection. - * @param archiveFileId The identifier of the archive file. - * @return The archive file or nullptr. - */ - std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileToRetrieveByArchiveFileId( - rdbms::Conn &conn, - const uint64_t archiveFileId) const; - - /** - * Returns the specified archive file. A nullptr pointer is returned if - * there are no corresponding rows in the TAPE_FILE table. - * - * @param conn The database connection. - * @param archiveFileId The identifier of the archive file. - * @return A list of tape file vid and corresponding tape state pairs - */ - const std::list<std::pair<std::string, std::string>> getTapeFileStateListForArchiveFileId( - rdbms::Conn &conn, - const uint64_t archiveFileId) const; - - /** - * Returns the specified archive file. A nullptr pointer is returned if - * there is no corresponding row in the ARCHIVE_FILE table. Please note that - * a non-nullptr is returned if there is a row in the ARCHIVE_FILE table and - * there are no rows in the TAPE_FILE table. - * - * Please note that this method performs a LEFT OUTER JOIN from the - * ARCHIVE_FILE table to the TAPE_FILE table. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance. - * @param diskFileId The identifier of the source disk file which is unique - * within it's host disk system. Two files from different disk systems may - * have the same identifier. The combination of diskInstanceName and - * diskFileId must be globally unique, in other words unique within the CTA - * catalogue. - * @return The archive file or nullptr. - * an empty list. - */ - std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileByDiskFileId( - rdbms::Conn &conn, - const std::string &diskInstance, - const std::string &diskFileId) const; - - /** - * Returns the specified archive file. A nullptr pointer is returned if - * there are no corresponding rows in the TAPE_FILE table. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance. - * @param diskFileId The identifier of the source disk file which is unique - * within it's host disk system. Two files from different disk systems may - * have the same identifier. The combination of diskInstanceName and - * diskFileId must be globally unique, in other words unique within the CTA - * catalogue. - * @return The archive file or nullptr. - * an empty list. - */ - std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileToRetrieveByDiskFileId( - rdbms::Conn &conn, - const std::string &diskInstance, - const std::string &diskFileId) const; - - /** - * Returns the mount policies for the specified requester and requester group. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the - * requester and requester group belong. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - * @param requesterGroupName The name of the requester group which is only - * guaranteed to be unique within its disk instance. - * @return The mount policies. - */ - RequesterAndGroupMountPolicies getMountPolicies( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &requesterGroupName) const; - - - /** - * Returns the mount policies for the specified requester, requester group and requester activity. - * - * @param conn The database connection. - * @param diskInstanceName The name of the disk instance to which the - * requester and requester group belong. - * @param requesterName The name of the requester which is only guaranteed to - * be unique within its disk instance. - * @param requesterGroupName The name of the requester group which is only - * guaranteed to be unique within its disk instance. - * @param activity The name of the activity to match the requester activity - * mount rules against - * @return The mount policies. - */ - RequesterAndGroupMountPolicies getMountPolicies( - rdbms::Conn &conn, - const std::string &diskInstanceName, - const std::string &requesterName, - const std::string &requesterGroupName, - const std::string &activity) const; - - - /** - * Creates a temporary table from the list of disk file IDs provided in the search criteria. - * - * @param conn The database connection. - * @param diskFileIds List of disk file IDs (fxid). - * @return Name of the temporary table - */ - virtual std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const = 0; - - /** - * Returns a unique archive ID that can be used by a new archive file 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 archive ID that can be used by a new archive file within - * the catalogue. - */ - virtual uint64_t getNextArchiveFileId(rdbms::Conn &conn) = 0; - - /** - * Returns a unique logical library ID that can be used by a new logical - * library 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 logical library ID that can be used by a new logical - * library storage class within the catalogue. - */ - virtual uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) = 0; - - /** - * Returns a unique virtual organization ID that can be used by a new Virtual Organization - * 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 virtual organization ID that can be used by a new Virtual Organization - * within the catalogue. - */ - virtual uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) = 0; - - /** - * Returns a unique media type ID that can be used by a new media type 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 media type ID that can be used by a new media type - * within the catalogue. - */ - virtual uint64_t getNextMediaTypeId(rdbms::Conn &conn) = 0; - - /** - * Returns a unique storage class ID that can be used by a new storage class - * 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 storage class ID that can be used by a new storage class - * within the catalogue. - */ - 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 unique file recycle log ID that can be used by a new entry of file recycle log 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 file recycle log ID that can be used by a new entry of file recycle log within - * the catalogue. - */ - virtual uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) = 0; - - /** - * Returns a cached version of the mapping from tape copy to tape pool for the - * specified storage class. - * - * This method updates the cache when necessary. - * - * @param storageClass The fully qualified storage class, in other words the - * name of the disk instance and the name of the storage class. - * @return The mapping from tape copy to tape pool for the specified storage - * class. - */ - common::dataStructures::TapeCopyToPoolMap getCachedTapeCopyToPoolMap(const StorageClass &storageClass) const; - - /** - * Returns the mapping from tape copy to tape pool for the specified storage - * class. - * - * @param conn The database connection. - * @param storageClass The fully qualified storage class, in other words the - * name of the disk instance and the name of the storage class. - * @return The mapping from tape copy to tape pool for the specified storage - * class. - */ - common::dataStructures::TapeCopyToPoolMap getTapeCopyToPoolMap(rdbms::Conn &conn, - const StorageClass &storageClass) const; - - /** - * Throws an exception if one of the fields of the specified event have not - * been set. - * - * @param callingFunc The name of the calling function. - * @param event The evnt to be checked. - */ - void checkTapeItemWrittenFieldsAreSet(const std::string &callingFunc, const TapeItemWritten &event) const; - - /** - * Throws an exception if one of the fields of the specified event have not - * been set. - * - * @param callingFunc The name of the calling function. - * @param event The evnt to be checked. - */ - void checkTapeFileWrittenFieldsAreSet(const std::string &callingFunc, const TapeFileWritten &event) const; - - /** - * Throws an exception if the delete request passed in parameter is not consistent - * to allow a deletion of the ArchiveFile from the Catalogue. - * @param deleteRequest, the deleteRequest to check the consistency. - * @param archiveFile the ArchiveFile to delete to check the deleteRequest consistency against. - */ - void checkDeleteRequestConsistency(const cta::common::dataStructures::DeleteArchiveRequest deleteRequest, const cta::common::dataStructures::ArchiveFile & archiveFile) const; - - /** - * Returns a cached version of the result of calling isAdmin(). - * - * @param admin The administrator. - * @return True if the specified user has administrator privileges. - */ - bool isCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const; - - /** - * Returns true if the specified user has administrator privileges. - * - * Please note that this method always queries the Catalogue database. - * - * @param admin The administrator. - * @return True if the specified user has administrator privileges. - */ - bool isNonCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const; - - /** - * Returns the number of tapes in the specified tape pool. - * - * If the tape pool does not exist then this method returns 0. - * - * @param conn The database connection. - * @param name The name of the tape pool. - * @return The number of tapes in the specified tape pool. - */ - uint64_t getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns true if the specified optional string is both set and empty. - * - * @param optionalStr The optional string. - * @return True if the specified optional string is both set and empty. - */ - bool isSetAndEmpty(const std::optional<std::string> &optionalStr) const; - - /** - * Returns true if the specified optional string list is both set and empty. - * - * @param optionalStr The optional string list. - * @return True if the specified optional string list is both set and empty. - */ - bool isSetAndEmpty(const std::optional<std::vector<std::string>> &optionalStrList) const; - - /** - * Returns true if the specified media type is currently being used by one or - * more archive tapes. - * - * @param conn The database connection. - * @param name The name of the media type - */ - bool mediaTypeIsUsedByTapes(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns true if the specified storage class is currently being used by one - * or more archive routes. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class. - */ - bool storageClassIsUsedByArchiveRoutes(rdbms::Conn &conn, const std::string &storageClassName) const; - - /** - * Returns true if the specified storage class is currently being used by one - * or more archive files. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class. - */ - bool storageClassIsUsedByArchiveFiles(rdbms::Conn &conn, const std::string &storageClassName) const; - - /** - * Returns true if the specified storage class is currently being used by one - * or more files in the recycle log. - * - * @param conn The database connection. - * @param storageClassName The name of the storage class. - */ - bool storageClassIsUsedByFileRecyleLogs(rdbms::Conn & conn, const std::string & storageClassName) const; - - /** - * Returns true if the specified Virtual Organization is currently being used by one - * or more StorageClasses - * - * @param conn The database connection. - * @param voName The name of the Virtual Organization. - */ - bool virtualOrganizationIsUsedByStorageClasses(rdbms::Conn &conn, const std::string &voName) const; - - /** - * Returns true if the specified Virtual Organization is currently being used by one - * or more Tapepools - * - * @param conn The database connection. - * @param voName The name of the Virtual Organization. - */ - bool virtualOrganizationIsUsedByTapepools(rdbms::Conn &conn, const std::string &voName) const; - - /** - * Returns the ID of the specified logical library or std::nullopt if the logical - * library does not exist. - * - * @param conn The database connection. - * @param name The name of the tape pool. - * @return the ID of the specified tape pool. - */ - std::optional<uint64_t> getLogicalLibraryId(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns the ID of the specified tape pool or std::nullopt if it the tape pool - * does not exist. - * - * @param conn The database connection. - * @param name The name of the tape pool. - * @return the ID of the specified tape pool. - */ - std::optional<uint64_t> getTapePoolId(rdbms::Conn &conn, const std::string &name) const; - - /** - * Returns the ID of the specified media type or std::nullopt if it the media type - * does not exist. - * - * @param conn The database connection. - * @param name The name of the media type. - * @return the ID of the specified tape pool. - */ - std::optional<uint64_t> getMediaTypeId(rdbms::Conn &conn, const std::string &name) const; - - /** - * Updates the disk file ID of the specified archive file. - * - * @param archiveFileId The unique identifier of the archive file. - * @param diskInstance The instance name of the source disk system. - * @param diskFileId The identifier of the source disk file which is unique - * within it's host disk system. Two files from different disk systems may - * have the same identifier. The combination of diskInstance and diskFileId - * must be globally unique, in other words unique within the CTA catalogue. - */ - void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, - const std::string &diskFileId) override; - - /** - * Insert the ArchiveFile and all its tape files in the FILE_RECYCLE_LOG table. - * There will be one entry on the FILE_RECYCLE_LOG table per deleted tape file - * - * @param request the DeleteRequest object that holds information about the file to delete. - * @param lc the logContext - */ - void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, - log::LogContext & lc) override; - - /** - * Copy the archiveFile and the associated tape files from the ARCHIVE_FILE and TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the ARCHIVE_FILE and TAPE_FILE entries. - * @param conn the database connection - * @param request the request that contains the necessary informations to identify the archiveFile to copy to the FILE_RECYCLE_LOG table - * @param lc the log context - */ - virtual void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn,const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) = 0; - - /** - * Copy the fileRecycleLog to the TAPE_FILE and ARCHIVE_FILE (if the archive file no longer exists) - * table and deletes the corresponding FILE_RECYCLE_LOG table entry - * @param conn the database connection - * @param fileRecycleLog the fileRecycleLog we want to restore - * @param newFid The new eos file id of the archive file to create - * @param lc the log context - */ - virtual void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) = 0; - - /** - * Copies the ARCHIVE_FILE and TAPE_FILE entries to the recycle-bin tables - * @param conn the database connection - * @param request the request that contains the necessary informations to identify the archiveFile to copy to the recycle-bin - */ - void copyArchiveFileToFileRecycleLog(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest & request); - - /** - * Copies the TAPE_FILE entries to the recycle-bin tables - * @param conn the database connection - * @param file the archiveFile whose tapefiles we want to copy - * @param reason The reason for deleting the tape file copy - */ - void copyTapeFilesToFileRecycleLog(rdbms::Conn & conn, const common::dataStructures::ArchiveFile &file, const std::string &reason); - - /** - * Copy the tape files from the TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the TAPE_FILE entry. - * @param conn the database connection - * @param file the archive file containing the tapefile to be copied - * @param reason The reason for deleting the tape file copy - * @param lc the log context - */ - virtual void copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, log::LogContext & lc) = 0; - - /** - * Insert the file in the FILE_RECYCLE_LOG table - * @param conn the database connection - * @param fileRecycleLog the file to insert into the FILE_RECYCLE_LOG table - */ - void insertFileToRecycleLog(rdbms::Conn & conn, const InsertFileRecycleLog & fileRecycleLog); - - /** - * Deletes the ArchiveFile from the ARCHIVE_FILE table - * @param conn the database connection - * @param request the DeleteArchiveRequest that contains the archiveFileId to delete - */ - void deleteArchiveFile(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest & request); - - /** - * Delete the TapeFile from the TAPE_FILE table - * @param conn the database connection - * @param request the DeleteArchiveRequest that contains the archiveFileId to delete the corresponding tape files - */ - void deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest & request); - - /** - * Delete the TapeFiles associated to an ArchiveFile from the TAPE_FILE table - * @param conn the database connection - * @param file the file that contains the tape files to delete - */ - void deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::ArchiveFile &file); - - /** - * Set the DIRTY flag to true - * @param conn the database connection - * @param archiveFileId the ArchiveFile that is going to be deleted and hence dirty the tape because - * the tape files will be removed from this tape - */ - void setTapeDirty(rdbms::Conn & conn, const uint64_t & archiveFileId) const; - - /** - * Delete the archiveFile and the associated tape files from the recycle-bin - * @param archiveFileId the archiveFileId of the archive file to delete - * @param lc the logContext - */ - void deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc); - - /** - * Delete the archiveFile and the associated tape files that are on the specified tape from the recycle-bin - * @param vid the vid of the tape where the files to be deleted are located - * @param lc the logContext - */ - void deleteFilesFromRecycleBin(rdbms::Conn & conn,const std::string & vid, log::LogContext & lc); - - /** - * Deletes all the log entries corresponding to the vid passed in parameter. - * - * Please note that this method is idempotent. If there are no recycle log - * entries associated to the vid passed in parameter, the method will return - * without any error. - * - * @param vid, the vid of the files to be deleted - * @param lc, the logContext - */ - void deleteFilesFromRecycleLog(const std::string & vid, log::LogContext & lc); - - /** - * Deletes all the log entries corresponding to the vid passed in parameter. - * - * Please note that this method is idempotent. If there are no recycle log - * entries associated to the vid passed in parameter, the method will return - * without any error. - * - *@param conn, the database connection - * @param vid, the vid of the files to be deleted - * @param lc, the logContext - */ - void deleteFilesFromRecycleLog(rdbms::Conn & conn, const std::string & vid, log::LogContext & lc); - - /** - * Delete the TapeFiles and the ArchiveFile from the recycle-bin in one transaction - * @param conn the database connection - * @param archiveFileId the archiveFileId of the file to delete from the recycle-bin - */ - virtual void deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn & conn, const uint64_t archiveFileId, log::LogContext & lc) = 0; - - /** - * Delete the tape files from the TAPE_FILE recycle-bin - * @param conn the database connection - * @param archiveFileId the archiveFileId of the tape files to delete - */ - void deleteTapeFilesFromRecycleBin(rdbms::Conn & conn, const uint64_t archiveFileId); - - void deleteTapeFileCopyFromRecycleBin(cta::rdbms::Conn & conn, const common::dataStructures::FileRecycleLog fileRecycleLog); - - /** - * Delete the archive file from the ARCHIVE_FILE recycle-bin - * @param conn the database connection - * @param archiveFileId the archiveFileId of the archive file to delete - */ - void deleteArchiveFileFromRecycleBin(rdbms::Conn & conn, const uint64_t archiveFileId); - - /** - * In the case we insert a TAPE_FILE that already has a copy on the catalogue (same copyNb), - * this TAPE_FILE will go to the FILE_RECYCLE_LOG table. - * - * This case happens always during the repacking of a tape: the new TAPE_FILE created - * will replace the old one, the old one will then be moved to the FILE_RECYCLE_LOG table - * - * @param conn The database connection. - * @returns the list of inserted fileRecycleLog - */ - std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn,const common::dataStructures::TapeFile &tapeFile, const uint64_t archiveFileId); - - /** - * Insert the file passed in parameter in the FILE_RECYCLE_LOG table - * @param conn the database connection - * @param fileRecycleLog the file to insert on the FILE_RECYCLE_LOG table - */ - void insertFileInFileRecycleLog(rdbms::Conn & conn, const InsertFileRecycleLog & fileRecycleLog); - - /** - * Generates the SELECT statement required to search for tapes using 100 tape - * VIDs. Each tape VID is represented in the SQL by a bind parameter with the - * naming convention of ":VN" where N is an integer from 1 to 100 with no - * padding. - */ - std::string getSelectTapesBy100VidsSql() const; - - /** - * Executes the specified "getTapesByVid" statement and collects the results into - * the specified vidToTapeMap. - * - * @param stmt "getTapesByVid" statement - * @param vidToTapeMap the map from VID to tape - */ - void executeGetTapesByVidStmtAndCollectResults(rdbms::Stmt &stmt, - common::dataStructures::VidToTapeMap &vidToTapeMap) const; - - /** - * Generates the SELECT statement required to search for VID to logical - * library name mappings using 100 tape VIDs. Each tape VID is represented in - * the SQL by a bind parameter with the naming convention of ":VN" where N is - * an integer from 1 to 100 with no padding. - */ - std::string getSelectVidToLogicalLibraryBy100Sql() const; - - /** - * Executes the specified "getVidToLogicalLibraryBy100" statement and collects the - * results into the specified vidToLogicalLibrary map. - * @param stmt the "getVidToLogicalLibraryBy100" statement. - * @param vidLogicalLibrary the map from VID to logical library name. - */ - void executeGetVidToLogicalLibraryBy100StmtAndCollectResults(rdbms::Stmt &stmt, - std::map<std::string, std::string> &vidToLogicalLibrary) const; - - /** - * Returns an iterator across the files on the specified tape ordered by - * FSEQ. - * - * @param vid The volume identifier of the tape. - * @return The iterator. - */ - ArchiveFileItor getTapeContentsItor(const std::string &vid) const; - - void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) override; - - std::list<std::string> getTapeDriveNames() const override; - - std::list<common::dataStructures::TapeDrive> getTapeDrives() const override; - - std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const override; - - void setDesiredTapeDriveState(const std::string& tapeDriveName, - const common::dataStructures::DesiredDriveState &desiredState) override; - - void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, - const std::string &comment) override; - - void updateTapeDriveStatistics(const std::string& tapeDriveName, - const std::string& host, const std::string& logicalLibrary, - const common::dataStructures::TapeDriveStatistics& statistics) override; - - void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive); - - void deleteTapeDrive(const std::string &tapeDriveName) override; - - void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) override; - - std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const override; - - void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, - const std::string &keyName, const std::string &value, const std::string &source) override; - - std::list<cta::catalogue::Catalogue::DriveConfig> getTapeDriveConfigs() const override; - - std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig( const std::string &tapeDriveName, - const std::string &keyName) const override; - - void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) override; - - std::map<std::string, uint64_t> getDiskSpaceReservations() const override; - - void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; - - void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; - - - /** - * Cached versions of tape copy to tape tape pool mappings for specific - * storage classes. - */ - mutable TimeBasedCache<StorageClass, common::dataStructures::TapeCopyToPoolMap> m_tapeCopyToPoolCache; - - /** - * Cached versions of mount policies for specific user groups. - */ - mutable TimeBasedCache<Group, std::optional<common::dataStructures::MountPolicy> > m_groupMountPolicyCache; - - /** - * Cached versions of mount policies for specific users. - */ - mutable TimeBasedCache<User, std::optional<common::dataStructures::MountPolicy> > m_userMountPolicyCache; - - /** - * Cached versions of all mount policies - */ - mutable TimeBasedCache<std::string, std::list<common::dataStructures::MountPolicy>> m_allMountPoliciesCache; - - /** - * Cached versions of virtual organization for specific tapepools - */ - mutable TimeBasedCache<std::string, common::dataStructures::VirtualOrganization> m_tapepoolVirtualOrganizationCache; - - /** - * Cached versions of the expected number of archive routes for specific - * storage classes as specified by the call to the createStorageClass() - * method as opposed to the actual number entered so far using the - * createArchiveRoute() method. - */ - mutable TimeBasedCache<StorageClass, uint64_t> m_expectedNbArchiveRoutesCache; - - /** - * Cached version of isAdmin() results. - */ - mutable TimeBasedCache<common::dataStructures::SecurityIdentity, bool> m_isAdminCache; - -private: - void settingSqlTapeDriveValues(cta::rdbms::Stmt *stmt, const common::dataStructures::TapeDrive &tapeDrive) const; - - common::dataStructures::TapeDrive gettingSqlTapeDriveValues(cta::rdbms::Rset* rset) const; - - void checkCommentOrReasonMaxLength(const std::optional<std::string>& comment) const; -}; // class RdbmsCatalogue - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/SchemaCreatingSqliteCatalogue.cpp b/catalogue/SchemaCreatingSqliteCatalogue.cpp index b50ecaaa4e..fc486cb12b 100644 --- a/catalogue/SchemaCreatingSqliteCatalogue.cpp +++ b/catalogue/SchemaCreatingSqliteCatalogue.cpp @@ -15,9 +15,11 @@ * submit itself to any jurisdiction. */ -#include "catalogue/SqliteCatalogueSchema.hpp" #include "catalogue/SchemaCreatingSqliteCatalogue.hpp" +#include "catalogue/SqliteCatalogueSchema.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" #include "common/utils/utils.hpp" +#include "rdbms/ConnPool.hpp" namespace cta { namespace catalogue { @@ -44,7 +46,7 @@ SchemaCreatingSqliteCatalogue::SchemaCreatingSqliteCatalogue( void SchemaCreatingSqliteCatalogue::createCatalogueSchema() { try { const SqliteCatalogueSchema schema; - auto conn = m_connPool.getConn(); + auto conn = m_connPool->getConn(); executeNonQueries(conn, schema.sql); } catch(exception::Exception &ex) { throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); diff --git a/catalogue/SchemaCreatingSqliteCatalogue.hpp b/catalogue/SchemaCreatingSqliteCatalogue.hpp index 649e6863a6..53a8813a0d 100644 --- a/catalogue/SchemaCreatingSqliteCatalogue.hpp +++ b/catalogue/SchemaCreatingSqliteCatalogue.hpp @@ -17,7 +17,7 @@ #pragma once -#include "catalogue/SqliteCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteCatalogue.hpp" namespace cta { namespace catalogue { diff --git a/catalogue/SqliteCatalogue.cpp b/catalogue/SqliteCatalogue.cpp deleted file mode 100644 index 6a37ddd140..0000000000 --- a/catalogue/SqliteCatalogue.cpp +++ /dev/null @@ -1,780 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#include "catalogue/ArchiveFileRow.hpp" -#include "catalogue/ArchiveFileRowWithoutTimestamps.hpp" -#include "catalogue/CatalogueItor.hpp" -#include "catalogue/SqliteCatalogue.hpp" -#include "catalogue/SqliteCatalogueSchema.hpp" -#include "catalogue/TapeItemWrittenPointer.hpp" -#include "common/dataStructures/DeleteArchiveRequest.hpp" -#include "common/dataStructures/FileRecycleLog.hpp" -#include "common/exception/Exception.hpp" -#include "common/exception/FileSizeMismatch.hpp" -#include "common/exception/TapeFseqMismatch.hpp" -#include "common/exception/UserError.hpp" -#include "common/log/TimingList.hpp" -#include "common/threading/MutexLocker.hpp" -#include "common/Timer.hpp" -#include "common/utils/utils.hpp" -#include "rdbms/AutoRollback.hpp" -#include "rdbms/ConstraintError.hpp" -#include "rdbms/PrimaryKeyError.hpp" - -namespace cta { -namespace catalogue { - -//------------------------------------------------------------------------------ -// constructor -//------------------------------------------------------------------------------ -SqliteCatalogue::SqliteCatalogue( - log::Logger &log, - const std::string &filename, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns): - RdbmsCatalogue( - log, - rdbms::Login(rdbms::Login::DBTYPE_SQLITE, "", "", filename, "", 0), - nbConns, - nbArchiveFileListingConns) { -} - -//------------------------------------------------------------------------------ -// destructor -//------------------------------------------------------------------------------ -SqliteCatalogue::~SqliteCatalogue() { -} - -//------------------------------------------------------------------------------ -// deleteArchiveFile -//------------------------------------------------------------------------------ -void SqliteCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, - log::LogContext &lc) { - try { - utils::Timer t; - auto conn = m_connPool.getConn(); - const auto getConnTime = t.secs(); - rdbms::AutoRollback autoRollback(conn); - t.reset(); - const auto archiveFile = getArchiveFileById(conn, archiveFileId); - const auto getArchiveFileTime = t.secs(); - - if(nullptr == archiveFile.get()) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", archiveFileId); - lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); - return; - } - - if(diskInstanceName != archiveFile->diskInstance) { - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("requestDiskInstance", diskInstanceName) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("getArchiveFileTime", getArchiveFileTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << it->copyNb - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << it->copyNb; //this shouldn't be here: repeated field - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " - "of the archived file"); - - exception::UserError ue; - ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " - "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << - archiveFile->diskInstance; - throw ue; - } - - t.reset(); - { - const char *const sql = "BEGIN DEFERRED;"; - auto stmt = conn.createStmt(sql); - stmt.executeNonQuery(); - } - { - const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - - const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); - - std::set<std::string> vidsToSetDirty; - //We will insert the vids to set dirty in a set so that - //we limit the calls to setTapeDirty to the number of tapes that contained the deleted tape files - for(auto &tapeFile: archiveFile->tapeFiles){ - vidsToSetDirty.insert(tapeFile.vid); - } - - for(auto &vidToSetDirty: vidsToSetDirty){ - setTapeDirty(conn,vidToSetDirty); - } - - const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); - - { - const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;"; - auto stmt = conn.createStmt(sql); - stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); - stmt.executeNonQuery(); - } - const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); - - conn.commit(); - const auto commitTime = t.secs(); - - log::ScopedParamContainer spc(lc); - spc.add("fileId", std::to_string(archiveFile->archiveFileID)) - .add("diskInstance", archiveFile->diskInstance) - .add("diskFileId", archiveFile->diskFileId) - .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) - .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) - .add("fileSize", std::to_string(archiveFile->fileSize)) - .add("creationTime", std::to_string(archiveFile->creationTime)) - .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) - .add("storageClass", archiveFile->storageClass) - .add("getConnTime", getConnTime) - .add("getArchiveFileTime", getArchiveFileTime) - .add("deleteFromTapeFileTime", deleteFromTapeFileTime) - .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) - .add("setTapeDirtyTime",setTapeDirtyTime) - .add("commitTime", commitTime); - archiveFile->checksumBlob.addFirstChecksumToLog(spc); - for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { - std::stringstream tapeCopyLogStream; - tapeCopyLogStream << "copy number: " << it->copyNb - << " vid: " << it->vid - << " fSeq: " << it->fSeq - << " blockId: " << it->blockId - << " creationTime: " << it->creationTime - << " fileSize: " << it->fileSize - << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field - << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field - spc.add("TAPE FILE", tapeCopyLogStream.str()); - } - lc.log(log::INFO, "Archive file deleted from CTA catalogue"); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// createAndPopulateTempTableFxid -//------------------------------------------------------------------------------ -std::string SqliteCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const { - try { - const std::string tempTableName = "TEMP.DISK_FXIDS"; - - // Drop any prexisting temporary table and create a new one - conn.executeNonQuery("DROP TABLE IF EXISTS " + tempTableName); - conn.executeNonQuery("CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID TEXT)"); - - if(diskFileIds) { - auto stmt = conn.createStmt("INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"); - for(auto &diskFileId : diskFileIds.value()) { - stmt.bindString(":DISK_FILE_ID", diskFileId); - stmt.executeNonQuery(); - } - } - - return tempTableName; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextArchiveFileId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { - try { - conn.executeNonQuery("INSERT INTO ARCHIVE_FILE_ID VALUES(NULL)"); - uint64_t archiveFileId = 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 + "\'"); - } - archiveFileId = 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 ARCHIVE_FILE_ID"); - - return archiveFileId; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextLogicalLibraryId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) { - try { - conn.executeNonQuery("INSERT INTO LOGICAL_LIBRARY_ID VALUES(NULL)"); - uint64_t logicalLibraryId = 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 + "\'"); - } - logicalLibraryId = 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 LOGICAL_LIBRARY_ID"); - - return logicalLibraryId; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextVirtualOrganizationId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { -try { - conn.executeNonQuery("INSERT INTO VIRTUAL_ORGANIZATION_ID VALUES(NULL)"); - uint64_t virtualOrganizationId = 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 + "\'"); - } - virtualOrganizationId = 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 VIRTUAL_ORGANIZATION_ID"); - - return virtualOrganizationId; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextMediaTypeId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextMediaTypeId(rdbms::Conn &conn) { - try { - conn.executeNonQuery("INSERT INTO MEDIA_TYPE_ID VALUES(NULL)"); - uint64_t id = 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 + "\'"); - } - id = 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 MEDIA_TYPE_ID"); - - return id; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextStorageClassId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextStorageClassId(rdbms::Conn &conn) { - try { - conn.executeNonQuery("INSERT INTO STORAGE_CLASS_ID VALUES(NULL)"); - uint64_t storageClassId = 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 + "\'"); - } - storageClassId = 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 STORAGE_CLASS_ID"); - - return storageClassId; - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// getNextTapePoolId -//------------------------------------------------------------------------------ -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; - } -} - -//------------------------------------------------------------------------------ -// getNextFileRecyleLogId -//------------------------------------------------------------------------------ -uint64_t SqliteCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) { - try { - conn.executeNonQuery("INSERT INTO FILE_RECYCLE_LOG_ID VALUES(NULL)"); - uint64_t fileRecycleLogId = 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 + "\'"); - } - fileRecycleLogId = 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 FILE_RECYCLE_LOG_ID"); - - return fileRecycleLogId; - } 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 " - "LAST_FSEQ AS LAST_FSEQ " - "FROM " - "TAPE " - "WHERE " - "VID = :VID;"; - - auto stmt = conn.createStmt(sql); - stmt.bindString(":VID", vid); - auto rset = stmt.executeQuery(); - if (!rset.next()) { - throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); - } - - return rset.columnUint64("LAST_FSEQ"); - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// filesWrittenToTape -//------------------------------------------------------------------------------ -void SqliteCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { - try { - if(events.empty()) { - return; - } - - auto firstEventItor = events.cbegin(); - const auto &firstEvent = **firstEventItor;; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); - - // The SQLite implementation of this method relies on the fact that a tape - // cannot be physically mounted in two or more drives at the same time - // - // Given the above assumption regarding the laws of physics, a simple lock - // on the mutex of the SqliteCatalogue object is enough to emulate an - // Oracle SELECT FOR UPDATE - threading::MutexLocker locker(m_mutex); - auto conn = m_connPool.getConn(); - - const uint64_t lastFSeq = getTapeLastFSeq(conn, firstEvent.vid); - uint64_t expectedFSeq = lastFSeq + 1; - uint64_t totalLogicalBytesWritten = 0; - uint64_t filesCount = 0; - - for(const auto &eventP: events) { - const auto & event = *eventP; - checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); - - if(event.vid != firstEvent.vid) { - throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); - } - - if(expectedFSeq != event.fSeq) { - exception::TapeFseqMismatch ex; - ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << - firstEvent.fSeq; - throw ex; - } - expectedFSeq++; - - - try { - // If this is a file (as opposed to a placeholder), do the full processing. - const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); - totalLogicalBytesWritten += fileEvent.size; - filesCount++; - } catch (std::bad_cast&) {} - } - - auto lastEventItor = events.cend(); - lastEventItor--; - const TapeItemWritten &lastEvent = **lastEventItor; - updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, lastEvent.tapeDrive); - - for(const auto &event : events) { - try { - // If this is a file (as opposed to a placeholder), do the full processing. - const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(*event); - fileWrittenToTape(conn, fileEvent); - } catch (std::bad_cast&) {} - } - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// fileWrittenToTape -//------------------------------------------------------------------------------ -void SqliteCatalogue::fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event) { - try { - checkTapeFileWrittenFieldsAreSet(__FUNCTION__, event); - - // Try to insert a row into the ARCHIVE_FILE table - it is normal this will - // fail if another tape copy has already been written to tape - try { - ArchiveFileRowWithoutTimestamps row; - row.archiveFileId = event.archiveFileId; - row.diskFileId = event.diskFileId; - row.diskInstance = event.diskInstance; - row.size = event.size; - row.checksumBlob = event.checksumBlob; - row.storageClassName = event.storageClassName; - row.diskFileOwnerUid = event.diskFileOwnerUid; - row.diskFileGid = event.diskFileGid; - insertArchiveFile(conn, row); - } catch(rdbms::PrimaryKeyError &) { - // Ignore this error - } catch(...) { - throw; - } - - const time_t now = time(nullptr); - const auto archiveFileRow = getArchiveFileRowById(conn, event.archiveFileId); - - if(nullptr == archiveFileRow) { - // This should never happen - exception::Exception ex; - ex.getMessage() << "Failed to find archive file row: archiveFileId=" << event.archiveFileId; - throw ex; - } - - std::ostringstream fileContext; - fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << - ", diskFileId=" << event.diskFileId; - - if(archiveFileRow->size != event.size) { - catalogue::FileSizeMismatch ex; - ex.getMessage() << "File size mismatch: expected=" << archiveFileRow->size << ", actual=" << event.size << ": " - << fileContext.str(); - throw ex; - } - - archiveFileRow->checksumBlob.validate(event.checksumBlob); - - // Insert the tape file - common::dataStructures::TapeFile tapeFile; - tapeFile.vid = event.vid; - tapeFile.fSeq = event.fSeq; - tapeFile.blockId = event.blockId; - tapeFile.fileSize = event.size; - tapeFile.copyNb = event.copyNb; - tapeFile.creationTime = now; - insertTapeFile(conn, tapeFile, event.archiveFileId); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyArchiveFileToRecycleBinAndDelete -//------------------------------------------------------------------------------ -void SqliteCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO and a DELETE FROM - //in a single transaction - conn.executeNonQuery("BEGIN TRANSACTION"); - copyArchiveFileToFileRecycleLog(conn,request); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn,request.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,request); - tl.insertAndReset("deleteTapeFilesTime",t); - RdbmsCatalogue::deleteArchiveFile(conn,request); - tl.insertAndReset("deleteArchiveFileTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",request.archiveFileID); - spc.add("diskFileId",request.diskFileId); - spc.add("diskFilePath",request.diskFilePath); - spc.add("diskInstance",request.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In SqliteCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// deleteTapeFilesAndArchiveFileFromRecycleBin -//------------------------------------------------------------------------------ -void SqliteCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId, log::LogContext& lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do two delete in one transaction - conn.executeNonQuery("BEGIN TRANSACTION"); - deleteTapeFilesFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteTapeFilesTime",t); - deleteArchiveFileFromRecycleBin(conn,archiveFileId); - tl.insertAndReset("deleteArchiveFileTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId",archiveFileId); - tl.addToLog(spc); - lc.log(log::INFO,"In SqliteCatalogue::deleteTapeFilesAndArchiveFileFromRecycleBin: tape files and archiveFiles deleted from the recycle-bin."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// copyTapeFileToFileRecyleLogAndDelete -//------------------------------------------------------------------------------ -void SqliteCatalogue::copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, - const std::string &reason, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - //We currently do an INSERT INTO and a DELETE FROM - //in a single transaction - conn.executeNonQuery("BEGIN TRANSACTION"); - copyTapeFilesToFileRecycleLog(conn, file, reason); - tl.insertAndReset("insertToRecycleBinTime",t); - setTapeDirty(conn, file.archiveFileID); - tl.insertAndReset("setTapeDirtyTime",t); - deleteTapeFiles(conn,file); - tl.insertAndReset("deleteTapeFilesTime",t); - conn.commit(); - tl.insertAndReset("commitTime",t); - log::ScopedParamContainer spc(lc); - spc.add("archiveFileId", file.archiveFileID); - spc.add("diskFileId", file.diskFileId); - spc.add("diskFilePath", file.diskFileInfo.path); - spc.add("diskInstance", file.diskInstance); - tl.addToLog(spc); - lc.log(log::INFO,"In SqliteCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); - - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreEntryInRecycleLog -//------------------------------------------------------------------------------ -void SqliteCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - - if (!fileRecycleLogItor.hasMore()) { - throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); - } - auto fileRecycleLog = fileRecycleLogItor.next(); - if (fileRecycleLogItor.hasMore()) { - //stop restoring more than one file at once - throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); - } - - conn.executeNonQuery("BEGIN TRANSACTION"); - - std::unique_ptr<common::dataStructures::ArchiveFile> archiveFilePtr = getArchiveFileById(conn, fileRecycleLog.archiveFileId); - if (!archiveFilePtr) { - restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); - } else { - if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { - //copy with same copy_nb exists, cannot restore - UserSpecifiedExistingDeletedFileCopy ex; - ex.getMessage() << "Cannot restore file copy with archiveFileId " << std::to_string(fileRecycleLog.archiveFileId) - << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) << " because a tapefile with same archiveFileId and copy_nb already exists"; - throw ex; - } - } - - restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); - conn.commit(); - - log::ScopedParamContainer spc(lc); - tl.insertAndReset("commitTime",t); - tl.addToLog(spc); - lc.log(log::INFO,"In SqliteCatalogue::restoreEntryInRecycleLog: all file copies successfully restored."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -//------------------------------------------------------------------------------ -// restoreFileCopyInRecycleLog -//------------------------------------------------------------------------------ -void SqliteCatalogue::restoreFileCopyInRecycleLog(rdbms::Conn &conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, log::LogContext & lc) { - try { - utils::Timer t; - log::TimingList tl; - cta::common::dataStructures::TapeFile tapeFile; - tapeFile.vid = fileRecycleLog.vid; - tapeFile.fSeq = fileRecycleLog.fSeq; - tapeFile.copyNb = fileRecycleLog.copyNb; - tapeFile.blockId = fileRecycleLog.blockId; - tapeFile.fileSize = fileRecycleLog.sizeInBytes; - tapeFile.creationTime = fileRecycleLog.tapeFileCreationTime; - - insertTapeFile(conn, tapeFile, fileRecycleLog.archiveFileId); - tl.insertAndReset("insertTapeFileTime",t); - - deleteTapeFileCopyFromRecycleBin(conn, fileRecycleLog); - tl.insertAndReset("deleteTapeFileCopyFromRecycleBinTime",t); - - log::ScopedParamContainer spc(lc); - spc.add("vid", tapeFile.vid); - spc.add("archiveFileId", fileRecycleLog.archiveFileId); - spc.add("fSeq", tapeFile.fSeq); - spc.add("copyNb", tapeFile.copyNb); - spc.add("fileSize", tapeFile.fileSize); - tl.addToLog(spc); - lc.log(log::INFO,"In SqliteCatalogue::restoreFileCopyInRecycleLog: File restored from the recycle log."); - } catch(exception::UserError &) { - throw; - } catch(exception::Exception &ex) { - ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); - throw; - } -} - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/SqliteCatalogue.hpp b/catalogue/SqliteCatalogue.hpp deleted file mode 100644 index af0d0072cd..0000000000 --- a/catalogue/SqliteCatalogue.hpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * @project The CERN Tape Archive (CTA) - * @copyright Copyright © 2021-2022 CERN - * @license This program is free software, distributed under the terms of the GNU General Public - * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can - * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * In applying this licence, CERN does not waive the privileges and immunities - * granted to it by virtue of its status as an Intergovernmental Organization or - * submit itself to any jurisdiction. - */ - -#pragma once - -#include "catalogue/RdbmsCatalogue.hpp" - -namespace cta { -namespace catalogue { - -class CatalogueFactory; - -/** - * An SQLite implementation of the CTA catalogue. - */ -class SqliteCatalogue: public RdbmsCatalogue { -public: - - /** - * Constructor. - * - * @param log Object representing the API to the CTA logging system. - * @param filename The filename to be passed to the sqlite3_open() function. - * @param nbConns The maximum number of concurrent connections to the - * underlying relational database for all operations accept listing archive - * files which can be relatively long operations. - * @param nbArchiveFileListingConns The maximum number of concurrent - * connections to the underlying relational database for the sole purpose of - * listing archive files. - */ - SqliteCatalogue( - log::Logger &log, - const std::string &filename, - const uint64_t nbConns, - const uint64_t nbArchiveFileListingConns); - -public: - - /** - * Destructor. - */ - ~SqliteCatalogue() override; - - /** - * !!!!!!!!!!!!!!!!!!! THIS METHOD SHOULD NOT BE USED !!!!!!!!!!!!!!!!!!!!!!! - * SqliteCatalogue implements its own version of deleteArchiveFile() because - * SQLite does not supprt 'SELECT FOR UPDATE'. - * - * Deletes the specified archive file and its associated tape copies from the - * catalogue. - * - * Please note that the name of the disk instance is specified in order to - * prevent a disk instance deleting an archive file that belongs to another - * disk instance. - * - * Please note that this method is idempotent. If the file to be deleted does - * not exist in the CTA catalogue then this method returns without error. - * - * @param instanceName The name of the instance from where the deletion request - * originated - * @param archiveFileId The unique identifier of the archive file. - * @param lc The log context. - * @return The metadata of the deleted archive file including the metadata of - * the associated and also deleted tape copies. - */ - void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, log::LogContext &lc) - override; - -protected: - - /** - * Creates a temporary table from the list of disk file IDs provided in the search criteria. - * - * @param conn The database connection. - * @param diskFileIds List of disk file IDs (fxid). - * @return Name of the temporary table - */ - std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const override; - - /** - * Returns a unique archive ID that can be used by a new archive file 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. - * - * PLEASE NOTE the SQLite implemenation of getNextArchiveFileId() takes a lock - * on m_mutex in order to serialize access to the SQLite database. This has - * been done in an attempt to avoid SQLite busy errors. - * - * @param conn The database connection. - * @return A unique archive ID that can be used by a new archive file within - * the catalogue. - */ - uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; - - /** - * Returns a unique logical library ID that can be used by a new logical - * library 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 logical library ID that can be used by a new logical - * library storage class within the catalogue. - */ - uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) override; - - /** - * Returns a unique virtual organization ID that can be used by a new Virtual Organization - * 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 virtual organization ID that can be used by a new Virtual Organization - * within the catalogue. - */ - uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; - - /** - * Returns a unique media type ID that can be used by a new media type 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 media type ID that can be used by a new media type - * within the catalogue. - */ - uint64_t getNextMediaTypeId(rdbms::Conn &conn) override; - - /** - * Returns a unique storage class ID that can be used by a new storage class - * 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 storage class ID that can be used by a new storage class - * within the catalogue. - */ - 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; - - /** - * Returns a unique file recycle log ID that can be used by a new entry of file recycle log 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 file recycle log ID that can be used by a new entry of file recycle log within - * the catalogue. - */ - uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) override; - - /** - * Notifies the catalogue that the specified files have been written to tape. - * - * @param events The tape file written events. - */ - void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) override; - - /** - * Copy the archiveFile and the associated tape files from the ARCHIVE_FILE and TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the ARCHIVE_FILE and TAPE_FILE entries. - * @param conn the database connection - * @param request the request that contains the necessary informations to identify the archiveFile to copy to the FILE_RECYCLE_LOG table - * @param lc the log context - */ - void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; - - /** - * Delete the TapeFiles and the ArchiveFile from the recycle-bin in one transaction - * @param conn the database connection - * @param archiveFileId the archiveFileId of the file to delete from the recycle-bin - */ - void deleteTapeFilesAndArchiveFileFromRecycleBin(rdbms::Conn& conn, const uint64_t archiveFileId, log::LogContext& lc) override; - - /** - * Copy the tape files from the TAPE_FILE tables to the FILE_RECYCLE_LOG table - * and deletes the TAPE_FILE entry. - * @param conn the database connection - * @param file the file to be deleted - * @param reason The reason for deleting the tape file copy - * @param lc the log context - */ - void copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, const cta::common::dataStructures::ArchiveFile &file, - const std::string &reason, log::LogContext & lc) override; - - /** - * Copy the files in fileRecycleLogItor to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entries - * @param conn the database connection - * @param fileRecycleLogItor the collection of fileRecycleLogs we want to restore - * @param lc the log context - */ - void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) override; - - /** - * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry - * @param conn the database connection - * @param fileRecycleLog the fileRecycleLog we want to restore - * @param lc the log context - */ - void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLogItor, log::LogContext & lc); - - -private: - - /** - * Notifies the catalogue that a file has been written to tape. - * - * @param conn The database connection. - * @param event The tape file written event. - */ - void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event); - - /** - * 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. - */ - uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid); - -}; // class SqliteCatalogue - -} // namespace catalogue -} // namespace cta diff --git a/catalogue/TapeDrivesCatalogueState.cpp b/catalogue/TapeDrivesCatalogueState.cpp index 59068a2924..2e842a2333 100644 --- a/catalogue/TapeDrivesCatalogueState.cpp +++ b/catalogue/TapeDrivesCatalogueState.cpp @@ -39,22 +39,22 @@ void TapeDrivesCatalogueState::createTapeDriveStatus(const common::dataStructure const common::dataStructures::DriveStatus& status, const tape::daemon::TpconfigLine& tpConfigLine, const common::dataStructures::SecurityIdentity& identity, log::LogContext & lc) { auto tapeDriveStatus = setTapeDriveStatus(driveInfo, desiredState, type, status, tpConfigLine, identity); - auto driveNames = m_catalogue.getTapeDriveNames(); + auto driveNames = m_catalogue.DriveState()->getTapeDriveNames(); auto it = std::find(driveNames.begin(), driveNames.end(), tapeDriveStatus.driveName); if (it != driveNames.end()) { - m_catalogue.deleteTapeDrive(tapeDriveStatus.driveName); + m_catalogue.DriveState()->deleteTapeDrive(tapeDriveStatus.driveName); } tapeDriveStatus.ctaVersion = CTA_VERSION; - m_catalogue.createTapeDrive(tapeDriveStatus); + m_catalogue.DriveState()->createTapeDrive(tapeDriveStatus); log::ScopedParamContainer spc(lc); spc.add("drive", driveInfo.driveName); lc.log(log::DEBUG, "In TapeDrivesCatalogueState::createTapeDriveStatus(): success."); } void TapeDrivesCatalogueState::checkDriveCanBeCreated(const cta::common::dataStructures::DriveInfo & driveInfo) { - const auto driveNames = m_catalogue.getTapeDriveNames(); + const auto driveNames = m_catalogue.DriveState()->getTapeDriveNames(); try { - const auto tapeDrive = m_catalogue.getTapeDrive(driveInfo.driveName); + const auto tapeDrive = m_catalogue.DriveState()->getTapeDrive(driveInfo.driveName); if (!tapeDrive) return; // tape drive does not exist if (tapeDrive.value().logicalLibrary != driveInfo.logicalLibrary || tapeDrive.value().host != driveInfo.host) { throw DriveAlreadyExistsException(std::string("The drive name=") + driveInfo.driveName + @@ -72,7 +72,7 @@ void TapeDrivesCatalogueState::checkDriveCanBeCreated(const cta::common::dataStr void TapeDrivesCatalogueState::removeDrive(const std::string& drive, log::LogContext &lc) { try { - m_catalogue.deleteTapeDrive(drive); + m_catalogue.DriveState()->deleteTapeDrive(drive); log::ScopedParamContainer params(lc); params.add("driveName", drive); lc.log(log::INFO, "In TapeDrivesCatalogueState::removeDrive(): removed tape drive from database."); @@ -83,10 +83,10 @@ void TapeDrivesCatalogueState::removeDrive(const std::string& drive, log::LogCon void TapeDrivesCatalogueState::setDesiredDriveState(const std::string& drive, const common::dataStructures::DesiredDriveState & desiredState, log::LogContext &lc) { - if(!desiredState.comment){ - m_catalogue.setDesiredTapeDriveState(drive, desiredState); + if (!desiredState.comment) { + m_catalogue.DriveState()->setDesiredTapeDriveState(drive, desiredState); } else { - m_catalogue.setDesiredTapeDriveStateComment(drive, desiredState.comment.value()); + m_catalogue.DriveState()->setDesiredTapeDriveStateComment(drive, desiredState.comment.value()); } } @@ -98,7 +98,8 @@ void TapeDrivesCatalogueState::updateDriveStatistics(const common::dataStructure statistics.bytesTransferedInSession = inputs.bytesTransferred; statistics.filesTransferedInSession = inputs.filesTransferred; statistics.reportTime = inputs.reportTime; - m_catalogue.updateTapeDriveStatistics(driveInfo.driveName, driveInfo.host, driveInfo.logicalLibrary, statistics); + m_catalogue.DriveState()->updateTapeDriveStatistics(driveInfo.driveName, driveInfo.host, driveInfo.logicalLibrary, + statistics); } void TapeDrivesCatalogueState::reportDriveStatus(const common::dataStructures::DriveInfo& driveInfo, @@ -168,7 +169,7 @@ void TapeDrivesCatalogueState::updateDriveStatus(const common::dataStructures::D throw exception::Exception("Unexpected status in DriveRegister::reportDriveStatus"); } - m_catalogue.updateTapeDriveStatus(driveState); + m_catalogue.DriveState()->updateTapeDriveStatus(driveState); } void TapeDrivesCatalogueState::setDriveDown(common::dataStructures::TapeDrive & driveState, diff --git a/catalogue/User.hpp b/catalogue/User.hpp new file mode 100644 index 0000000000..6f962b7836 --- /dev/null +++ b/catalogue/User.hpp @@ -0,0 +1,64 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +namespace cta { +namespace catalogue { + +/** + * A fully qualified user, in other words the name of the disk instance and + * the name of the group. + */ +struct User { + /** + * The name of the disk instance to which the user name belongs. + */ + std::string diskInstanceName; + + /** + * The name of the user which is only guaranteed to be unique within its + * disk instance. + */ + std::string username; + + /** + * Constructor. + * + * @param d The name of the disk instance to which the group name belongs. + * @param u The name of the group which is only guaranteed to be unique + * within its disk instance. + */ + User(const std::string &d, const std::string &u): diskInstanceName(d), username(u) { + } + + /** + * Less than operator. + * + * @param rhs The argument on the right hand side of the operator. + * @return True if this object is less than the argument on the right hand + * side of the operator. + */ + bool operator<(const User &rhs) const { + return diskInstanceName < rhs.diskInstanceName || username < rhs.username; + } +}; // struct User + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/common_catalogue_schema.sql b/catalogue/common_catalogue_schema.sql index f110330744..e72e96a2a3 100644 --- a/catalogue/common_catalogue_schema.sql +++ b/catalogue/common_catalogue_schema.sql @@ -53,8 +53,8 @@ CREATE UNIQUE INDEX DISK_INSTANCE_SPACE_DISN_UN_IDX ON DISK_INSTANCE_SPACE(DISK_ CREATE TABLE DISK_SYSTEM( DISK_SYSTEM_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DSNM_NN NOT NULL, - DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, - DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, + DISK_INSTANCE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DIN_NN NOT NULL, + DISK_INSTANCE_SPACE_NAME VARCHAR(100) CONSTRAINT DISK_SYSTEM_DISN_NN NOT NULL, FILE_REGEXP VARCHAR(100) CONSTRAINT DISK_SYSTEM_FR_NN NOT NULL, TARGETED_FREE_SPACE UINT64TYPE CONSTRAINT DISK_SYSTEM_TFS_NN NOT NULL, SLEEP_TIME UINT64TYPE CONSTRAINT DISK_SYSTEM_ST_NN NOT NULL, diff --git a/catalogue/dummy/DummyAdminUserCatalogue.cpp b/catalogue/dummy/DummyAdminUserCatalogue.cpp new file mode 100644 index 0000000000..6f8a7c1343 --- /dev/null +++ b/catalogue/dummy/DummyAdminUserCatalogue.cpp @@ -0,0 +1,47 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummyAdminUserCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyAdminUserCatalogue::createAdminUser(const common::dataStructures::SecurityIdentity& admin, + const std::string& username, const std::string& comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyAdminUserCatalogue::deleteAdminUser(const std::string& username) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::AdminUser> DummyAdminUserCatalogue::getAdminUsers() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyAdminUserCatalogue::modifyAdminUserComment(const common::dataStructures::SecurityIdentity& admin, + const std::string& username, const std::string& comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +bool DummyAdminUserCatalogue::isAdmin(const common::dataStructures::SecurityIdentity& admin) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyAdminUserCatalogue.hpp b/catalogue/dummy/DummyAdminUserCatalogue.hpp new file mode 100644 index 0000000000..e41347f7e8 --- /dev/null +++ b/catalogue/dummy/DummyAdminUserCatalogue.hpp @@ -0,0 +1,43 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/AdminUserCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyAdminUserCatalogue : public AdminUserCatalogue { +public: + DummyAdminUserCatalogue() = default; + ~DummyAdminUserCatalogue() override = default; + + void createAdminUser(const common::dataStructures::SecurityIdentity &admin, const std::string &username, + const std::string &comment) override; + void deleteAdminUser(const std::string &username) override; + + std::list<common::dataStructures::AdminUser> getAdminUsers() const override; + + void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) override; + + bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyArchiveFileCatalogue.cpp b/catalogue/dummy/DummyArchiveFileCatalogue.cpp new file mode 100644 index 0000000000..53dec33624 --- /dev/null +++ b/catalogue/dummy/DummyArchiveFileCatalogue.cpp @@ -0,0 +1,93 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/dummy/DummyArchiveFileCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +uint64_t DummyArchiveFileCatalogue::checkAndGetNextArchiveFileId(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::ArchiveFileQueueCriteria DummyArchiveFileCatalogue::getArchiveFileQueueCriteria( + const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +ArchiveFileItor DummyArchiveFileCatalogue::getArchiveFilesItor(const TapeFileSearchCriteria &searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::ArchiveFile DummyArchiveFileCatalogue::getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::ArchiveFile> DummyArchiveFileCatalogue::getFilesForRepack(const std::string &vid, + const uint64_t startFSeq, const uint64_t maxNbFiles) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +ArchiveFileItor DummyArchiveFileCatalogue::getArchiveFilesForRepackItor(const std::string &vid, + const uint64_t startFSeq) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::ArchiveFileSummary DummyArchiveFileCatalogue::getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::ArchiveFile DummyArchiveFileCatalogue::getArchiveFileById(const uint64_t id) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveFileCatalogue::modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string &newStorageClassName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveFileCatalogue::modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveFileCatalogue::moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveFileCatalogue::updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveFileCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, + const uint64_t archiveFileId, log::LogContext &lc) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyArchiveFileCatalogue.hpp b/catalogue/dummy/DummyArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..23bddfd34a --- /dev/null +++ b/catalogue/dummy/DummyArchiveFileCatalogue.hpp @@ -0,0 +1,69 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/ArchiveFileCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyArchiveFileCatalogue : public ArchiveFileCatalogue { +public: + DummyArchiveFileCatalogue() = default; + ~DummyArchiveFileCatalogue() override = default; + + uint64_t checkAndGetNextArchiveFileId(const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) override; + + common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override; + + ArchiveFileItor getArchiveFilesItor( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, + const uint64_t maxNbFiles) const override; + + ArchiveFileItor getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const override; + + common::dataStructures::ArchiveFileSummary getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override; + + void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string &newStorageClassName) const override; + + void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const; + + void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) override;\ + + void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) override; + + void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, + log::LogContext &lc) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyArchiveRouteCatalogue.cpp b/catalogue/dummy/DummyArchiveRouteCatalogue.cpp new file mode 100644 index 0000000000..bc75c2a545 --- /dev/null +++ b/catalogue/dummy/DummyArchiveRouteCatalogue.cpp @@ -0,0 +1,53 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummyArchiveRouteCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyArchiveRouteCatalogue::createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, + const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveRouteCatalogue::deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::ArchiveRoute> DummyArchiveRouteCatalogue::getArchiveRoutes() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::ArchiveRoute> DummyArchiveRouteCatalogue::getArchiveRoutes( + const std::string &storageClassName, const std::string &tapePoolName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveRouteCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyArchiveRouteCatalogue::modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyArchiveRouteCatalogue.hpp b/catalogue/dummy/DummyArchiveRouteCatalogue.hpp new file mode 100644 index 0000000000..797d030edf --- /dev/null +++ b/catalogue/dummy/DummyArchiveRouteCatalogue.hpp @@ -0,0 +1,48 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/ArchiveRouteCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyArchiveRouteCatalogue : public ArchiveRouteCatalogue { +public: + DummyArchiveRouteCatalogue() = default; + ~DummyArchiveRouteCatalogue() override = default; + + void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, + const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override; + + void deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &storageClassName, + const std::string &tapePoolName) const override; + + void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override; + + void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyCatalogue.cpp b/catalogue/dummy/DummyCatalogue.cpp new file mode 100644 index 0000000000..a24cd4a4dd --- /dev/null +++ b/catalogue/dummy/DummyCatalogue.cpp @@ -0,0 +1,152 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/dummy/DummyAdminUserCatalogue.hpp" +#include "catalogue/dummy/DummyArchiveFileCatalogue.hpp" +#include "catalogue/dummy/DummyArchiveRouteCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyDiskInstanceCatalogue.hpp" +#include "catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp" +#include "catalogue/dummy/DummyDiskSystemCatalogue.hpp" +#include "catalogue/dummy/DummyDriveConfigCatalogue.hpp" +#include "catalogue/dummy/DummyDriveStateCatalogue.hpp" +#include "catalogue/dummy/DummyFileRecycleLogCatalogue.hpp" +#include "catalogue/dummy/DummyMountPolicyCatalogue.hpp" +#include "catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp" +#include "catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp" +#include "catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp" +#include "catalogue/dummy/DummySchemaCatalogue.hpp" +#include "catalogue/dummy/DummyStorageClassCatalogue.hpp" +#include "catalogue/dummy/DummyTapeCatalogue.hpp" +#include "catalogue/dummy/DummyTapeFileCatalogue.hpp" +#include "catalogue/dummy/DummyTapePoolCatalogue.hpp" +#include "catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp" + + +namespace cta { +namespace catalogue { + +DummyCatalogue::DummyCatalogue() + : m_schema(std::make_unique<DummySchemaCatalogue>()), + m_adminUser(std::make_unique<DummyAdminUserCatalogue>()), + m_diskSystem(std::make_unique<DummyDiskSystemCatalogue>()), + m_diskInstance(std::make_unique<DummyDiskInstanceCatalogue>()), + m_diskInstanceSpace(std::make_unique<DummyDiskInstanceSpaceCatalogue>()), + m_vo(std::make_unique<DummyVirtualOrganizationCatalogue>()), + m_archiveRoute(std::make_unique<DummyArchiveRouteCatalogue>()), + m_storageClass(std::make_unique<DummyStorageClassCatalogue>()), + m_tapePool(std::make_unique<DummyTapePoolCatalogue>()), + m_tape(std::make_unique<DummyTapeCatalogue>()), + m_mountPolicy(std::make_unique<DummyMountPolicyCatalogue>()), + m_requesterActivityMountRule(std::make_unique<DummyRequesterActivityMountRuleCatalogue>()), + m_requesterMountRule(std::make_unique<DummyRequesterMountRuleCatalogue>()), + m_requesterGroupMountRule(std::make_unique<DummyRequesterGroupMountRuleCatalogue>()), + m_tapeFile(std::make_unique<DummyTapeFileCatalogue>()), + m_fileRecycleLog(std::make_unique<DummyFileRecycleLogCatalogue>()), + m_driveConfig(std::make_unique<DummyDriveConfigCatalogue>()), + m_archiveFile(std::make_unique<DummyArchiveFileCatalogue>()), + m_driveState(std::make_unique<DummyDriveStateCatalogue>()) { +} + +const std::unique_ptr<SchemaCatalogue>& DummyCatalogue::Schema() { + return m_schema; +} + +const std::unique_ptr<AdminUserCatalogue>& DummyCatalogue::AdminUser() { + return m_adminUser; +} + +const std::unique_ptr<DiskSystemCatalogue>& DummyCatalogue::DiskSystem() { + return m_diskSystem; +} + +const std::unique_ptr<DiskInstanceCatalogue>& DummyCatalogue::DiskInstance() { + return m_diskInstance; +} + +const std::unique_ptr<DiskInstanceSpaceCatalogue>& DummyCatalogue::DiskInstanceSpace() { + return m_diskInstanceSpace; +} + +const std::unique_ptr<VirtualOrganizationCatalogue>& DummyCatalogue::VO() { + return m_vo; +} + +const std::unique_ptr<ArchiveRouteCatalogue>& DummyCatalogue::ArchiveRoute() { + return m_archiveRoute; +} + +const std::unique_ptr<MediaTypeCatalogue>& DummyCatalogue::MediaType() { + return m_mediaType; +} + +const std::unique_ptr<StorageClassCatalogue>& DummyCatalogue::StorageClass() { + return m_storageClass; +} + +const std::unique_ptr<TapePoolCatalogue>& DummyCatalogue::TapePool() { + return m_tapePool; +} + +const std::unique_ptr<TapeCatalogue>& DummyCatalogue::Tape() { + return m_tape; +} + +const std::unique_ptr<MountPolicyCatalogue>& DummyCatalogue::MountPolicy() { + return m_mountPolicy; +} + +const std::unique_ptr<RequesterActivityMountRuleCatalogue>& DummyCatalogue::RequesterActivityMountRule() { + return m_requesterActivityMountRule; +} + +const std::unique_ptr<RequesterMountRuleCatalogue>& DummyCatalogue::RequesterMountRule() { + return m_requesterMountRule; +} + +const std::unique_ptr<RequesterGroupMountRuleCatalogue>& DummyCatalogue::RequesterGroupMountRule() { + return m_requesterGroupMountRule; +} + +const std::unique_ptr<LogicalLibraryCatalogue>& DummyCatalogue::LogicalLibrary() { + return m_logicalLibrary; +} + +const std::unique_ptr<TapeFileCatalogue>& DummyCatalogue::TapeFile() { + return m_tapeFile; +} + +const std::unique_ptr<FileRecycleLogCatalogue>& DummyCatalogue::FileRecycleLog() { + return m_fileRecycleLog; +} + +const std::unique_ptr<DriveConfigCatalogue>& DummyCatalogue::DriveConfig() { + return m_driveConfig; +} + +const std::unique_ptr<ArchiveFileCatalogue>& DummyCatalogue::ArchiveFile() { + return m_archiveFile; +} + +const std::unique_ptr<DriveStateCatalogue>& DummyCatalogue::DriveState() { + return m_driveState; +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyCatalogue.hpp b/catalogue/dummy/DummyCatalogue.hpp new file mode 100644 index 0000000000..fc06f636a4 --- /dev/null +++ b/catalogue/dummy/DummyCatalogue.hpp @@ -0,0 +1,86 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/Catalogue.hpp" + +namespace cta { +namespace catalogue { + +/** + * An empty implementation of the Catalogue used to populate unit tests of the scheduler database + * as they need a reference to a Catalogue, used in very few situations (requeueing of retrieve + * requests). + */ + +class DummyCatalogue: public Catalogue { +public: + DummyCatalogue(); + ~DummyCatalogue() override = default; + + const std::unique_ptr<SchemaCatalogue>& Schema() override; + const std::unique_ptr<AdminUserCatalogue>& AdminUser() override; + const std::unique_ptr<DiskSystemCatalogue>& DiskSystem() override; + const std::unique_ptr<DiskInstanceCatalogue>& DiskInstance() override; + const std::unique_ptr<DiskInstanceSpaceCatalogue>& DiskInstanceSpace() override; + const std::unique_ptr<VirtualOrganizationCatalogue>& VO() override; + const std::unique_ptr<ArchiveRouteCatalogue>& ArchiveRoute() override; + const std::unique_ptr<MediaTypeCatalogue>& MediaType() override; + const std::unique_ptr<StorageClassCatalogue>& StorageClass() override; + const std::unique_ptr<TapePoolCatalogue>& TapePool() override; + const std::unique_ptr<TapeCatalogue>& Tape() override; + const std::unique_ptr<MountPolicyCatalogue>& MountPolicy() override; + const std::unique_ptr<RequesterActivityMountRuleCatalogue>& RequesterActivityMountRule() override; + const std::unique_ptr<RequesterMountRuleCatalogue>& RequesterMountRule() override; + const std::unique_ptr<RequesterGroupMountRuleCatalogue>& RequesterGroupMountRule() override; + const std::unique_ptr<LogicalLibraryCatalogue>& LogicalLibrary() override; + const std::unique_ptr<TapeFileCatalogue>& TapeFile() override; + const std::unique_ptr<FileRecycleLogCatalogue>& FileRecycleLog() override; + const std::unique_ptr<ArchiveFileCatalogue>& ArchiveFile() override; + const std::unique_ptr<DriveConfigCatalogue>& DriveConfig() override; + const std::unique_ptr<DriveStateCatalogue>& DriveState() override; + +protected: + std::unique_ptr<SchemaCatalogue> m_schema; + std::unique_ptr<AdminUserCatalogue> m_adminUser; + std::unique_ptr<DiskSystemCatalogue> m_diskSystem; + std::unique_ptr<DiskInstanceCatalogue> m_diskInstance; + std::unique_ptr<DiskInstanceSpaceCatalogue> m_diskInstanceSpace; + std::unique_ptr<VirtualOrganizationCatalogue> m_vo; + std::unique_ptr<ArchiveRouteCatalogue> m_archiveRoute; + std::unique_ptr<MediaTypeCatalogue> m_mediaType; + std::unique_ptr<StorageClassCatalogue> m_storageClass; + std::unique_ptr<TapePoolCatalogue> m_tapePool; + std::unique_ptr<TapeCatalogue> m_tape; + std::unique_ptr<MountPolicyCatalogue> m_mountPolicy; + std::unique_ptr<RequesterActivityMountRuleCatalogue> m_requesterActivityMountRule; + std::unique_ptr<RequesterMountRuleCatalogue> m_requesterMountRule; + std::unique_ptr<RequesterGroupMountRuleCatalogue> m_requesterGroupMountRule; + std::unique_ptr<LogicalLibraryCatalogue> m_logicalLibrary; + std::unique_ptr<TapeFileCatalogue> m_tapeFile; + std::unique_ptr<FileRecycleLogCatalogue> m_fileRecycleLog; + std::unique_ptr<DriveConfigCatalogue> m_driveConfig; + std::unique_ptr<ArchiveFileCatalogue> m_archiveFile; + std::unique_ptr<DriveStateCatalogue> m_driveState; +}; + +} // namespace catalogue +} // namespace cta. + diff --git a/catalogue/dummy/DummyDiskInstanceCatalogue.cpp b/catalogue/dummy/DummyDiskInstanceCatalogue.cpp new file mode 100644 index 0000000000..e0e301f73a --- /dev/null +++ b/catalogue/dummy/DummyDiskInstanceCatalogue.cpp @@ -0,0 +1,48 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <string> + +#include "catalogue/dummy/DummyDiskInstanceCatalogue.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyDiskInstanceCatalogue::createDiskInstance(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + m_diskInstances[name] = {name, comment, common::dataStructures::EntryLog(), common::dataStructures::EntryLog()}; +} + +void DummyDiskInstanceCatalogue::deleteDiskInstance(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskInstanceCatalogue::modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::DiskInstance> DummyDiskInstanceCatalogue::getAllDiskInstances() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDiskInstanceCatalogue.hpp b/catalogue/dummy/DummyDiskInstanceCatalogue.hpp new file mode 100644 index 0000000000..cd65da710d --- /dev/null +++ b/catalogue/dummy/DummyDiskInstanceCatalogue.hpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <string> + +#include "catalogue/interfaces/DiskInstanceCatalogue.hpp" +#include "common/dataStructures/DiskInstance.hpp" + +namespace cta { + +namespace catalogue { + +class DummyDiskInstanceCatalogue: public DiskInstanceCatalogue { +public: + DummyDiskInstanceCatalogue() = default; + ~DummyDiskInstanceCatalogue() override = default; + + void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + void deleteDiskInstance(const std::string &name) override; + + void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const override; + +private: + std::map<std::string, common::dataStructures::DiskInstance> m_diskInstances; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.cpp b/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.cpp new file mode 100644 index 0000000000..4777b3fc36 --- /dev/null +++ b/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.cpp @@ -0,0 +1,72 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <string> + +#include "catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp" +#include "common/dataStructures/DiskInstanceSpace.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +std::map<std::string, common::dataStructures::DiskInstanceSpace> DummyDiskInstanceSpaceCatalogue::m_diskInstanceSpaces; + +void DummyDiskInstanceSpaceCatalogue::deleteDiskInstanceSpace(const std::string &name, + const std::string &diskInstance) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskInstanceSpaceCatalogue::createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, const std::string &comment) { + m_diskInstanceSpaces[name] = {name, diskInstance, freeSpaceQueryURL, refreshInterval, 0, 0, comment, + common::dataStructures::EntryLog(), common::dataStructures::EntryLog()}; +} + +std::list<common::dataStructures::DiskInstanceSpace> DummyDiskInstanceSpaceCatalogue::getAllDiskInstanceSpaces() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceRefreshInterval( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const uint64_t refreshInterval) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) { + m_diskInstanceSpaces[name].freeSpace = freeSpace; + m_diskInstanceSpaces[name].lastRefreshTime = time(nullptr); +} + +void DummyDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceQueryURL( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &freeSpaceQueryURL) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp b/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp new file mode 100644 index 0000000000..1ee8449ab2 --- /dev/null +++ b/catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp @@ -0,0 +1,70 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <string> + +#include "catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct DiskInstance; +} +} + +namespace catalogue { + +class DummyDiskInstanceSpaceCatalogue: public DiskInstanceSpaceCatalogue { +public: + DummyDiskInstanceSpaceCatalogue() = default; + ~DummyDiskInstanceSpaceCatalogue() override = default; + + void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) override; + + void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstance, + const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, + const std::string &comment) override; + + std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const override; + + void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &comment) override; + + void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) override; + + void modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) override; + + void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) override; + +private: + friend class DummyDiskSystemCatalogue; + static std::map<std::string, common::dataStructures::DiskInstanceSpace> m_diskInstanceSpaces; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDiskSystemCatalogue.cpp b/catalogue/dummy/DummyDiskSystemCatalogue.cpp new file mode 100644 index 0000000000..f7b47e13e8 --- /dev/null +++ b/catalogue/dummy/DummyDiskSystemCatalogue.cpp @@ -0,0 +1,82 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <map> +#include <string> + +#include "catalogue/dummy/DummyDiskSystemCatalogue.hpp" +#include "catalogue/dummy/DummyDiskInstanceSpaceCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "disk/DiskSystem.hpp" + +namespace cta { +namespace catalogue { + +void DummyDiskSystemCatalogue::createDiskSystem(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, + const std::string &fileRegexp, const uint64_t targetedFreeSpace, const time_t sleepTime,const std::string &comment) { + m_diskSystemList.push_back({name, DummyDiskInstanceSpaceCatalogue::m_diskInstanceSpaces.at(diskInstanceSpaceName), + fileRegexp, targetedFreeSpace, sleepTime, common::dataStructures::EntryLog(), common::dataStructures::EntryLog{}, + comment}); +} + +void DummyDiskSystemCatalogue::deleteDiskSystem(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +disk::DiskSystemList DummyDiskSystemCatalogue::getAllDiskSystems() const { + return m_diskSystemList; +} + +void DummyDiskSystemCatalogue::modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskSystemCatalogue::modifyDiskSystemTargetedFreeSpace( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t targetedFreeSpace) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskSystemCatalogue::modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskSystemCatalogue::modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskSystemCatalogue::modifyDiskSystemDiskInstanceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyDiskSystemCatalogue::modifyDiskSystemDiskInstanceSpaceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceSpaceName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +bool DummyDiskSystemCatalogue::diskSystemExists(const std::string &name) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDiskSystemCatalogue.hpp b/catalogue/dummy/DummyDiskSystemCatalogue.hpp new file mode 100644 index 0000000000..0d74f82ed2 --- /dev/null +++ b/catalogue/dummy/DummyDiskSystemCatalogue.hpp @@ -0,0 +1,67 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/interfaces/DiskSystemCatalogue.hpp" +#include "disk/DiskSystem.hpp" + +namespace cta { + +namespace catalogue { + +class DummyDiskSystemCatalogue: public DiskSystemCatalogue { +public: + DummyDiskSystemCatalogue() = default; + ~DummyDiskSystemCatalogue() override = default; + + void createDiskSystem(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, const std::string &fileRegexp, + const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) override; + + void deleteDiskSystem(const std::string &name) override; + + disk::DiskSystemList getAllDiskSystems() const override; + + void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) override; + + void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t targetedFreeSpace) override; + + void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) override; + + void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName) override; + + void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceSpaceName) override; + + bool diskSystemExists(const std::string &name) const override; + +private: + disk::DiskSystemList m_diskSystemList; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyDriveConfig.hpp b/catalogue/dummy/DummyDriveConfig.hpp new file mode 100644 index 0000000000..8eaaaa7cbb --- /dev/null +++ b/catalogue/dummy/DummyDriveConfig.hpp @@ -0,0 +1,53 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/DriveConfigCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyDriveConfigCatalogue : public DriveConfigCatalogue { +public: + DummyDriveConfigCatalogue() = default; + ~DummyDriveConfigCatalogue() override = default; + + void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::list<DriveConfig> getTapeDriveConfigs() const override; + + std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const override; + + void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) const override; + + void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyDriveConfigCatalogue.cpp b/catalogue/dummy/DummyDriveConfigCatalogue.cpp new file mode 100644 index 0000000000..e33d24aeb1 --- /dev/null +++ b/catalogue/dummy/DummyDriveConfigCatalogue.cpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummyDriveConfigCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyDriveConfigCatalogue::createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> DummyDriveConfigCatalogue::getTapeDriveConfigs() const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +std::list<std::pair<std::string, std::string>> DummyDriveConfigCatalogue::getTapeDriveConfigNamesAndKeys() const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyDriveConfigCatalogue::modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} +std::optional<std::tuple<std::string, std::string, std::string>> DummyDriveConfigCatalogue::getTapeDriveConfig( + const std::string &tapeDriveName, const std::string &keyName) const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyDriveConfigCatalogue::deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyDriveConfigCatalogue.hpp b/catalogue/dummy/DummyDriveConfigCatalogue.hpp new file mode 100644 index 0000000000..c717ab9daa --- /dev/null +++ b/catalogue/dummy/DummyDriveConfigCatalogue.hpp @@ -0,0 +1,54 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveConfigCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyDriveConfigCatalogue: public DriveConfigCatalogue { +public: + DummyDriveConfigCatalogue() = default; + ~DummyDriveConfigCatalogue() override = default; + + void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::list<DriveConfig> getTapeDriveConfigs() const override; + + std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const override; + + void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) const override; + + void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyDriveStateCatalogue.cpp b/catalogue/dummy/DummyDriveStateCatalogue.cpp new file mode 100644 index 0000000000..587c88dc9b --- /dev/null +++ b/catalogue/dummy/DummyDriveStateCatalogue.cpp @@ -0,0 +1,171 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/CatalogueExceptions.hpp" +#include "catalogue/dummy/DummyDriveStateCatalogue.hpp" +#include "common/dataStructures/DesiredDriveState.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/dataStructures/TapeDriveStatistics.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { +namespace catalogue { + +void DummyDriveStateCatalogue::createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyDriveStateCatalogue::deleteTapeDrive(const std::string &tapeDriveName) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +std::list<std::string> DummyDriveStateCatalogue::getTapeDriveNames() const { + return {m_tapeDriveStatus.driveName}; +} + +std::optional<common::dataStructures::TapeDrive> DummyDriveStateCatalogue::getTapeDrive( + const std::string &tapeDriveName) const { + if (m_tapeDriveStatus.driveName != "") return m_tapeDriveStatus; + common::dataStructures::TapeDrive tapeDriveStatus; + const time_t reportTime = time(nullptr); + + tapeDriveStatus.driveName = tapeDriveName; + tapeDriveStatus.host = "Dummy_Host"; + tapeDriveStatus.logicalLibrary = "Dummy_Library"; + + tapeDriveStatus.downOrUpStartTime = reportTime; + + tapeDriveStatus.mountType = common::dataStructures::MountType::NoMount; + tapeDriveStatus.driveStatus = common::dataStructures::DriveStatus::Down; + tapeDriveStatus.desiredUp = false; + tapeDriveStatus.desiredForceDown = false; + + tapeDriveStatus.diskSystemName = "Dummy_System"; + tapeDriveStatus.reservedBytes = 0; + tapeDriveStatus.reservationSessionId = 0; + + + return tapeDriveStatus; +} + +std::list<common::dataStructures::TapeDrive> DummyDriveStateCatalogue::getTapeDrives() const { + std::list<common::dataStructures::TapeDrive> tapeDrives; + const auto tapeDrive = getTapeDrive(m_tapeDriveStatus.driveName); + if (tapeDrive.has_value()) tapeDrives.push_back(tapeDrive.value()); + return tapeDrives; +} + +void DummyDriveStateCatalogue::setDesiredTapeDriveState(const std::string&, + const common::dataStructures::DesiredDriveState &desiredState) { + m_tapeDriveStatus.desiredUp = desiredState.up; + m_tapeDriveStatus.desiredForceDown = desiredState.forceDown; + m_tapeDriveStatus.reasonUpDown = desiredState.reason; +} + +void DummyDriveStateCatalogue::setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) { + m_tapeDriveStatus.userComment = comment; +} + +void DummyDriveStateCatalogue::updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) { + m_tapeDriveStatus.driveName = tapeDriveName; + m_tapeDriveStatus.host = host; + m_tapeDriveStatus.logicalLibrary = logicalLibrary; + m_tapeDriveStatus.bytesTransferedInSession = statistics.bytesTransferedInSession; + m_tapeDriveStatus.filesTransferedInSession = statistics.filesTransferedInSession; + m_tapeDriveStatus.lastModificationLog = statistics.lastModificationLog; +} + +void DummyDriveStateCatalogue::updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) { + m_tapeDriveStatus = tapeDrive; +} + +std::map<std::string, uint64_t> DummyDriveStateCatalogue::getDiskSpaceReservations() const { + std::map<std::string, uint64_t> ret; + const auto tdNames = getTapeDriveNames(); + for (const auto& driveName : tdNames) { + const auto tdStatus = getTapeDrive(driveName); + if (tdStatus.value().diskSystemName) { + // no need to check key, operator[] initializes missing values at zero for scalar types + ret[tdStatus.value().diskSystemName.value()] += tdStatus.value().reservedBytes.value(); + } + } + return ret; +} + +void DummyDriveStateCatalogue::reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + if (diskSpaceReservation.empty()) return; + + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::DEBUG, "In RetrieveMount::reserveDiskSpace(): reservation request."); + + auto tdStatus = getTapeDrive(driveName); + if (!tdStatus) return; + + if (!tdStatus.value().reservationSessionId) { + tdStatus.value().reservationSessionId = mountId; + tdStatus.value().reservedBytes = 0; + } + + if (tdStatus.value().reservationSessionId != mountId) { + tdStatus.value().reservationSessionId = mountId; + tdStatus.value().reservedBytes = 0; + } + + tdStatus.value().diskSystemName = diskSpaceReservation.begin()->first; + tdStatus.value().reservedBytes.value() += diskSpaceReservation.begin()->second; + updateTapeDriveStatus(tdStatus.value()); +} + +void DummyDriveStateCatalogue::releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + if (diskSpaceReservation.empty()) return; + + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::DEBUG, "In RetrieveMount::releaseDiskSpace(): reservation release request."); + + auto tdStatus = getTapeDrive(driveName); + + if (!tdStatus) return; + if (!tdStatus.value().reservationSessionId) { + return; + } + if (tdStatus.value().reservationSessionId != mountId) { + return; + } + auto& bytes = diskSpaceReservation.begin()->second; + if (bytes > tdStatus.value().reservedBytes) throw exception::NegativeDiskSpaceReservationReached( + "In DriveState::subtractDiskSpaceReservation(): we would reach a negative reservation size."); + tdStatus.value().diskSystemName = diskSpaceReservation.begin()->first; + tdStatus.value().reservedBytes.value() -= bytes; + updateTapeDriveStatus(tdStatus.value()); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyDriveStateCatalogue.hpp b/catalogue/dummy/DummyDriveStateCatalogue.hpp new file mode 100644 index 0000000000..875c562740 --- /dev/null +++ b/catalogue/dummy/DummyDriveStateCatalogue.hpp @@ -0,0 +1,74 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveStateCatalogue.hpp" +#include "common/dataStructures/TapeDrive.hpp" + +namespace cta { +namespace catalogue { + +class DummyDriveStateCatalogue : public DriveStateCatalogue { +public: + DummyDriveStateCatalogue() = default; + ~DummyDriveStateCatalogue() override = default; + + void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) override; + + std::list<std::string> getTapeDriveNames() const override; + + std::list<common::dataStructures::TapeDrive> getTapeDrives() const override; + + std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const override; + + void setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) override; + + void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) override; + + void updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) override; + + void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) override; + + void deleteTapeDrive(const std::string &tapeDriveName) override; + + std::map<std::string, uint64_t> getDiskSpaceReservations() const override; + + void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + + void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + +private: + common::dataStructures::TapeDrive m_tapeDriveStatus; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyFileRecycleLogCatalogue.cpp b/catalogue/dummy/DummyFileRecycleLogCatalogue.cpp new file mode 100644 index 0000000000..11e959ee21 --- /dev/null +++ b/catalogue/dummy/DummyFileRecycleLogCatalogue.cpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/dummy/DummyFileRecycleLogCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { +namespace catalogue { + +FileRecycleLogItor DummyFileRecycleLogCatalogue::getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyFileRecycleLogCatalogue::restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyFileRecycleLogCatalogue::deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyFileRecycleLogCatalogue.hpp b/catalogue/dummy/DummyFileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..01e8f25871 --- /dev/null +++ b/catalogue/dummy/DummyFileRecycleLogCatalogue.hpp @@ -0,0 +1,40 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyFileRecycleLogCatalogue: public FileRecycleLogCatalogue { +public: + DummyFileRecycleLogCatalogue() = default; + ~DummyFileRecycleLogCatalogue() override = default; + + FileRecycleLogItor getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const override; + + void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) override; + + void deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyLogicalLibraryCatalogue.cpp b/catalogue/dummy/DummyLogicalLibraryCatalogue.cpp new file mode 100644 index 0000000000..f21b32f405 --- /dev/null +++ b/catalogue/dummy/DummyLogicalLibraryCatalogue.cpp @@ -0,0 +1,60 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummyLogicalLibraryCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + + +void DummyLogicalLibraryCatalogue::createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool isDisabled, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyLogicalLibraryCatalogue::deleteLogicalLibrary(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::LogicalLibrary> DummyLogicalLibraryCatalogue::getLogicalLibraries() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyLogicalLibraryCatalogue::modifyLogicalLibraryName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyLogicalLibraryCatalogue::modifyLogicalLibraryComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyLogicalLibraryCatalogue::modifyLogicalLibraryDisabledReason( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &disabledReason) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyLogicalLibraryCatalogue::setLogicalLibraryDisabled( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyLogicalLibraryCatalogue.hpp b/catalogue/dummy/DummyLogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..cc207083d8 --- /dev/null +++ b/catalogue/dummy/DummyLogicalLibraryCatalogue.hpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/LogicalLibraryCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyLogicalLibraryCatalogue : public LogicalLibraryCatalogue { +public: + DummyLogicalLibraryCatalogue() = default; + ~DummyLogicalLibraryCatalogue() override = default; + + void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool isDisabled, const std::string &comment) override; + + void deleteLogicalLibrary(const std::string &name) override; + + std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const override; + + void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; + + void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &disabledReason) override; + + void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool disabledValue) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyMediaTypeCatalogue.cpp b/catalogue/dummy/DummyMediaTypeCatalogue.cpp new file mode 100644 index 0000000000..cc01827fc3 --- /dev/null +++ b/catalogue/dummy/DummyMediaTypeCatalogue.cpp @@ -0,0 +1,93 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <string> + +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/dummy/DummyMediaTypeCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyMediaTypeCatalogue::createMediaType(const common::dataStructures::SecurityIdentity &admin, + const MediaType &mediaType) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::deleteMediaType(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<MediaTypeWithLogs> DummyMediaTypeCatalogue::getMediaTypes() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +MediaType DummyMediaTypeCatalogue::getMediaTypeByVid(const std::string & vid) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &cartridge) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeCapacityInBytes( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypePrimaryDensityCode( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeSecondaryDensityCode( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint32_t> &nbWraps) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &minLPos) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &maxLPos) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMediaTypeCatalogue::modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyMediaTypeCatalogue.hpp b/catalogue/dummy/DummyMediaTypeCatalogue.hpp new file mode 100644 index 0000000000..b458c929fb --- /dev/null +++ b/catalogue/dummy/DummyMediaTypeCatalogue.hpp @@ -0,0 +1,67 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/MediaTypeCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyMediaTypeCatalogue : public MediaTypeCatalogue { +public: + DummyMediaTypeCatalogue() = default; + ~DummyMediaTypeCatalogue() override = default; + + void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) override; + + void deleteMediaType(const std::string &name) override; + + std::list<MediaTypeWithLogs> getMediaTypes() const override; + + MediaType getMediaTypeByVid(const std::string & vid) const override; + + void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &cartridge) override; + + void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t capacityInBytes) override; + + void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint8_t primaryDensityCode) override; + + void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t secondaryDensityCode) override; + + void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint32_t> &nbWraps) override; + + void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &minLPos) override; + + void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &maxLPos) override; + + void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyMountPolicyCatalogue.cpp b/catalogue/dummy/DummyMountPolicyCatalogue.cpp new file mode 100644 index 0000000000..9125264cc9 --- /dev/null +++ b/catalogue/dummy/DummyMountPolicyCatalogue.cpp @@ -0,0 +1,110 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/dummy/DummyMountPolicyCatalogue.hpp" +#include "common/dataStructures/MountPolicy.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyMountPolicyCatalogue::createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::MountPolicy> DummyMountPolicyCatalogue::getMountPolicies() const { + std::list<common::dataStructures::MountPolicy> mountPolicies; + common::dataStructures::MountPolicy mp1; + mp1.name = "mountPolicy"; + mp1.archivePriority = 1; + mp1.archiveMinRequestAge = 0; + mp1.retrievePriority = 1; + mp1.retrieveMinRequestAge = 0; + mountPolicies.push_back(mp1); + + common::dataStructures::MountPolicy mp2; + mp2.name = "moreAdvantageous"; + mp2.archivePriority = 2; + mp2.archiveMinRequestAge = 0; + mp2.retrievePriority = 2; + mp2.retrieveMinRequestAge = 0; + mountPolicies.push_back(mp1); + return mountPolicies; +} + +std::optional<common::dataStructures::MountPolicy> DummyMountPolicyCatalogue::getMountPolicy( + const std::string &mountPolicyName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::MountPolicy> DummyMountPolicyCatalogue::getCachedMountPolicies() const { + std::list<common::dataStructures::MountPolicy> mountPolicies; + common::dataStructures::MountPolicy mp1; + mp1.name = "mountPolicy"; + mp1.archivePriority = 1; + mp1.archiveMinRequestAge = 0; + mp1.retrievePriority = 1; + mp1.retrieveMinRequestAge = 0; + mountPolicies.push_back(mp1); + + common::dataStructures::MountPolicy mp2; + mp2.name = "moreAdvantageous"; + mp2.archivePriority = 2; + mp2.archiveMinRequestAge = 0; + mp2.retrievePriority = 2; + mp2.retrieveMinRequestAge = 0; + mountPolicies.push_back(mp1); + return mountPolicies; +} + +void DummyMountPolicyCatalogue::deleteMountPolicy(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMountPolicyCatalogue::modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMountPolicyCatalogue::modifyMountPolicyArchiveMinRequestAge( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minArchiveRequestAge) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMountPolicyCatalogue::modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMountPolicyCatalogue::modifyMountPolicyRetrieveMinRequestAge( + const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyMountPolicyCatalogue::modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyMountPolicyCatalogue.hpp b/catalogue/dummy/DummyMountPolicyCatalogue.hpp new file mode 100644 index 0000000000..4f30f5caf9 --- /dev/null +++ b/catalogue/dummy/DummyMountPolicyCatalogue.hpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/MountPolicyCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyMountPolicyCatalogue : public MountPolicyCatalogue { +public: + DummyMountPolicyCatalogue() = default; + ~DummyMountPolicyCatalogue() override = default; + + void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) override; + + std::list<common::dataStructures::MountPolicy> getMountPolicies() const override; + + std::optional<common::dataStructures::MountPolicy> getMountPolicy( + const std::string &mountPolicyName) const override; + + std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const override; + + void deleteMountPolicy(const std::string &name) override; + + void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) override; + + void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minArchiveRequestAge) override; + + void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) override; + + void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) override; + + void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.cpp b/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.cpp new file mode 100644 index 0000000000..2f9ca1538d --- /dev/null +++ b/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.cpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyRequesterActivityMountRuleCatalogue::modifyRequesterActivityMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterActivityMountRuleCatalogue::modifyRequesterActivityMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterActivityMountRuleCatalogue::createRequesterActivityMountRule( + const common::dataStructures::SecurityIdentity &admin, const std::string &mountPolicyName, + const std::string &diskInstance, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::RequesterActivityMountRule> + DummyRequesterActivityMountRuleCatalogue::getRequesterActivityMountRules() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterActivityMountRuleCatalogue::deleteRequesterActivityMountRule(const std::string &diskInstanceName, + const std::string &requesterName, const std::string &activityRegex) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp b/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp new file mode 100644 index 0000000000..9ac7b2b8bd --- /dev/null +++ b/catalogue/dummy/DummyRequesterActivityMountRuleCatalogue.hpp @@ -0,0 +1,49 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyRequesterActivityMountRuleCatalogue : public RequesterActivityMountRuleCatalogue { +public: + DummyRequesterActivityMountRuleCatalogue() = default; + ~DummyRequesterActivityMountRuleCatalogue() override = default; + + void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &mountPolicy) override; + + void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) override; + + void createRequesterActivityMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &activityRegex, const std::string &comment) override; + + std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const override; + + void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, + const std::string &activityRegex) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.cpp b/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.cpp new file mode 100644 index 0000000000..44fffb2cd6 --- /dev/null +++ b/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.cpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyRequesterGroupMountRuleCatalogue::modifyRequesterGroupMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &mountPolicy) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterGroupMountRuleCatalogue::modifyRequesterGroupMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterGroupMountRuleCatalogue::createRequesterGroupMountRule( + const common::dataStructures::SecurityIdentity &admin, const std::string &mountPolicyName, + const std::string &diskInstanceName, const std::string &requesterGroupName, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::RequesterGroupMountRule> + DummyRequesterGroupMountRuleCatalogue::getRequesterGroupMountRules() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + + +void DummyRequesterGroupMountRuleCatalogue::deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp b/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp new file mode 100644 index 0000000000..1a340ed761 --- /dev/null +++ b/catalogue/dummy/DummyRequesterGroupMountRuleCatalogue.hpp @@ -0,0 +1,48 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyRequesterGroupMountRuleCatalogue : public RequesterGroupMountRuleCatalogue { +public: + DummyRequesterGroupMountRuleCatalogue() = default; + ~DummyRequesterGroupMountRuleCatalogue() override = default; + + void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) override; + + void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) override; + + void createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstanceName, const std::string &requesterGroupName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const override; + + + void deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyRequesterMountRuleCatalogue.cpp b/catalogue/dummy/DummyRequesterMountRuleCatalogue.cpp new file mode 100644 index 0000000000..91cc174807 --- /dev/null +++ b/catalogue/dummy/DummyRequesterMountRuleCatalogue.cpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyRequesterMountRuleCatalogue::modifyRequesterMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &mountPolicy) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterMountRuleCatalogue::modifyRequesteMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterMountRuleCatalogue::createRequesterMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::RequesterMountRule> DummyRequesterMountRuleCatalogue::getRequesterMountRules() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyRequesterMountRuleCatalogue::deleteRequesterMountRule(const std::string &diskInstanceName, + const std::string &requesterName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp b/catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp new file mode 100644 index 0000000000..4822252950 --- /dev/null +++ b/catalogue/dummy/DummyRequesterMountRuleCatalogue.hpp @@ -0,0 +1,46 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/RequesterMountRuleCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyRequesterMountRuleCatalogue : public RequesterMountRuleCatalogue { +public: + DummyRequesterMountRuleCatalogue() = default; + ~DummyRequesterMountRuleCatalogue() override = default; + + void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) override; + + void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &comment) override; + + void createRequesterMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const override; + + void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) override; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummySchemaCatalogue.cpp b/catalogue/dummy/DummySchemaCatalogue.cpp new file mode 100644 index 0000000000..fd4128e58c --- /dev/null +++ b/catalogue/dummy/DummySchemaCatalogue.cpp @@ -0,0 +1,38 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummySchemaCatalogue.hpp" +#include "catalogue/SchemaVersion.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +SchemaVersion DummySchemaCatalogue::getSchemaVersion() const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummySchemaCatalogue::verifySchemaVersion() { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummySchemaCatalogue::ping() { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummySchemaCatalogue.hpp b/catalogue/dummy/DummySchemaCatalogue.hpp new file mode 100644 index 0000000000..c465bebc75 --- /dev/null +++ b/catalogue/dummy/DummySchemaCatalogue.hpp @@ -0,0 +1,38 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/SchemaCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummySchemaCatalogue: public SchemaCatalogue { +public: + DummySchemaCatalogue() = default; + ~DummySchemaCatalogue() override = default; + + SchemaVersion getSchemaVersion() const override; + + void verifySchemaVersion() override; + + void ping() override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyStorageClassCatalogue.cpp b/catalogue/dummy/DummyStorageClassCatalogue.cpp new file mode 100644 index 0000000000..bb8b46ee2a --- /dev/null +++ b/catalogue/dummy/DummyStorageClassCatalogue.cpp @@ -0,0 +1,64 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/dummy/DummyStorageClassCatalogue.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyStorageClassCatalogue::createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyStorageClassCatalogue::deleteStorageClass(const std::string &storageClassName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::StorageClass> DummyStorageClassCatalogue::getStorageClasses() const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::StorageClass DummyStorageClassCatalogue::getStorageClass(const std::string &name) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyStorageClassCatalogue::modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyStorageClassCatalogue::modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyStorageClassCatalogue::modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyStorageClassCatalogue::modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/dummy/DummyStorageClassCatalogue.hpp b/catalogue/dummy/DummyStorageClassCatalogue.hpp new file mode 100644 index 0000000000..dc07ba7176 --- /dev/null +++ b/catalogue/dummy/DummyStorageClassCatalogue.hpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "catalogue/interfaces/StorageClassCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyStorageClassCatalogue: public StorageClassCatalogue { +public: + DummyStorageClassCatalogue() = default; + ~DummyStorageClassCatalogue() override = default; + + void createStorageClass(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) override; + + void deleteStorageClass(const std::string &storageClassName) override; + + std::list<common::dataStructures::StorageClass> getStorageClasses() const override; + + common::dataStructures::StorageClass getStorageClass(const std::string &name) const override; + + void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) override; + + void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapeCatalogue.cpp b/catalogue/dummy/DummyTapeCatalogue.cpp new file mode 100644 index 0000000000..588cae45af --- /dev/null +++ b/catalogue/dummy/DummyTapeCatalogue.cpp @@ -0,0 +1,206 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "catalogue/dummy/DummyTapeCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyTapeCatalogue::createTape(const common::dataStructures::SecurityIdentity &admin, + const CreateTapeAttributes & tape) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::deleteTape(const std::string &vid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<common::dataStructures::Tape> DummyTapeCatalogue::getTapes( + const TapeSearchCriteria &searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::VidToTapeMap DummyTapeCatalogue::getTapesByVid(const std::string& vid) const { + std::set<std::string> vids = {vid}; + return getTapesByVid(vids); +} + +common::dataStructures::VidToTapeMap DummyTapeCatalogue::getTapesByVid(const std::set<std::string> &vids) const { + // Minimal implementation of VidToMap for retrieve request unit tests. We just support + // disabled status for the tapes. + // If the tape is not listed, it is listed as enabled in the return value. + threading::MutexLocker lm(m_tapeEnablingMutex); + common::dataStructures::VidToTapeMap ret; + for (const auto & v: vids) { + try { + ret[v].state = m_tapeEnabling.at(v); + } catch (std::out_of_range &) { + ret[v].state = common::dataStructures::Tape::ACTIVE; + } + } + return ret; +} + +std::map<std::string, std::string> DummyTapeCatalogue::getVidToLogicalLibrary( + const std::set<std::string> &vids) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, cta::log::LogContext & lc) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::checkTapeForLabel(const std::string &vid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::tapeLabelled(const std::string &vid, const std::string &drive) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +uint64_t DummyTapeCatalogue::getNbFilesOnTape(const std::string &vid) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &mediaType) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &vendor) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &logicalLibraryName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &tapePoolName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &encryptionKeyName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &verificationStatus) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity& admin, + const std::string& vid, const std::string & reason) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const bool fullValue) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeIsFromCastorInUnitTests(const std::string &vid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string & reason) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::setTapeDirty(const std::string & vid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::optional<std::string> &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::tapeMountedForArchive(const std::string &vid, const std::string &drive) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::tapeMountedForRetrieve(const std::string &vid, const std::string &drive) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::noSpaceLeftOnTape(const std::string &vid) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<TapeForWriting> DummyTapeCatalogue::getTapesForWriting(const std::string &logicalLibraryName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::Label::Format DummyTapeCatalogue::getTapeLabelFormat(const std::string& vid) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeCatalogue::addRepackingTape(const std::string & vid) { + threading::MutexLocker lm(m_tapeEnablingMutex); + m_tapeEnabling[vid]=common::dataStructures::Tape::REPACKING; +} + +void DummyTapeCatalogue::modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, +const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) { + threading::MutexLocker lm(m_tapeEnablingMutex); + if (prev_state.has_value() && prev_state.value() != m_tapeEnabling[vid]) { + throw exception::Exception("Previous state mismatch"); + } + m_tapeEnabling[vid]=state; +} + +bool DummyTapeCatalogue::tapeExists(const std::string& vid) const { + return m_tapeEnabling.find(vid) != m_tapeEnabling.end(); +} + +common::dataStructures::Tape::State DummyTapeCatalogue::getTapeState(const std::string & vid) const { + return m_tapeEnabling.at(vid); +} + +// Special functions for unit tests. +void DummyTapeCatalogue::addEnabledTape(const std::string & vid) { + threading::MutexLocker lm(m_tapeEnablingMutex); + m_tapeEnabling[vid]=common::dataStructures::Tape::ACTIVE; +} +void DummyTapeCatalogue::addDisabledTape(const std::string & vid) { + threading::MutexLocker lm(m_tapeEnablingMutex); + m_tapeEnabling[vid]=common::dataStructures::Tape::DISABLED; +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapeCatalogue.hpp b/catalogue/dummy/DummyTapeCatalogue.hpp new file mode 100644 index 0000000000..411243e4f9 --- /dev/null +++ b/catalogue/dummy/DummyTapeCatalogue.hpp @@ -0,0 +1,121 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/TapeCatalogue.hpp" +#include "common/dataStructures/Tape.hpp" +#include "common/threading/Mutex.hpp" +#include "common/threading/MutexLocker.hpp" + +namespace cta { +namespace catalogue { + +class DummyTapeCatalogue : public TapeCatalogue { +public: + DummyTapeCatalogue() = default; + ~DummyTapeCatalogue() override = default; + + void createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes & tape) override; + + void deleteTape(const std::string &vid) override; + + std::list<common::dataStructures::Tape> getTapes(const TapeSearchCriteria &searchCriteria) const override; + + common::dataStructures::Tape::State getTapeState(const std::string & vid) const; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const override; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const override; + + std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const override; + + void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + cta::log::LogContext & lc) override; + + void checkTapeForLabel(const std::string &vid) override; + + void tapeLabelled(const std::string &vid, const std::string &drive) override; + + uint64_t getNbFilesOnTape(const std::string &vid) const override; + + void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &mediaType) override; + + void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &vendor) override; + + void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &logicalLibraryName) override; + + void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &tapePoolName) override; + + void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &encryptionKeyName) override; + + void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &verificationStatus) override; + + void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, + const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) override; + + bool tapeExists(const std::string &vid) const override; + + void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity& admin, const std::string& vid, + const std::string & reason) override; + + void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool fullValue) override; + + void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) override; + + void setTapeIsFromCastorInUnitTests(const std::string &vid) override; + + void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) override; + + void setTapeDirty(const std::string & vid) override; + + void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::optional<std::string> &comment) override; + + void tapeMountedForArchive(const std::string &vid, const std::string &drive) override; + + void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) override; + + void noSpaceLeftOnTape(const std::string &vid) override; + + std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const override; + + common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const override; + + // This two methods are for unit tests only in GarbageCollectorTests.cpp, they are not defined in the interface + void addEnabledTape(const std::string & vid); + void addDisabledTape(const std::string & vid); + void addRepackingTape(const std::string & vid); + +private: + mutable threading::Mutex m_tapeEnablingMutex; + std::map<std::string, common::dataStructures::Tape::State> m_tapeEnabling; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapeFileCatalogue.cpp b/catalogue/dummy/DummyTapeFileCatalogue.cpp new file mode 100644 index 0000000000..660b772c0b --- /dev/null +++ b/catalogue/dummy/DummyTapeFileCatalogue.cpp @@ -0,0 +1,48 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "catalogue/dummy/DummyTapeFileCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyTapeFileCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapeFileCatalogue::deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +common::dataStructures::RetrieveFileQueueCriteria DummyTapeFileCatalogue::prepareToRetrieveFile( + const std::string &diskInstanceName, const uint64_t archiveFileId, + const common::dataStructures::RequesterIdentity &user, const std::optional<std::string> & activity, + log::LogContext &lc, const std::optional<std::string> &mountPolicyName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapeFileCatalogue.hpp b/catalogue/dummy/DummyTapeFileCatalogue.hpp new file mode 100644 index 0000000000..c37ccc5bf8 --- /dev/null +++ b/catalogue/dummy/DummyTapeFileCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/TapeFileCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyTapeFileCatalogue : public TapeFileCatalogue { +public: + DummyTapeFileCatalogue() = default; + ~DummyTapeFileCatalogue() override = default; + + void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) override; + + void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) override; + + common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string &diskInstanceName, + const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity &user, + const std::optional<std::string> & activity, log::LogContext &lc, + const std::optional<std::string> &mountPolicyName = std::nullopt) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapePoolCatalogue.cpp b/catalogue/dummy/DummyTapePoolCatalogue.cpp new file mode 100644 index 0000000000..62da77dd8a --- /dev/null +++ b/catalogue/dummy/DummyTapePoolCatalogue.cpp @@ -0,0 +1,82 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <optional> +#include <string> + +#include "catalogue/dummy/DummyTapePoolCatalogue.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/TapePoolSearchCriteria.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyTapePoolCatalogue::createTapePool(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::deleteTapePool(const std::string &name) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::list<TapePool> DummyTapePoolCatalogue::getTapePools(const TapePoolSearchCriteria &searchCriteria) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +std::optional<TapePool> DummyTapePoolCatalogue::getTapePool(const std::string &tapePoolName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbPartialTapes) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool encryptionValue) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &supply) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +void DummyTapePoolCatalogue::modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +bool DummyTapePoolCatalogue::tapePoolExists(const std::string &tapePoolName) const { + throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyTapePoolCatalogue.hpp b/catalogue/dummy/DummyTapePoolCatalogue.hpp new file mode 100644 index 0000000000..14064a7a1b --- /dev/null +++ b/catalogue/dummy/DummyTapePoolCatalogue.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/interfaces/TapePoolCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyTapePoolCatalogue : public TapePoolCatalogue { +public: + DummyTapePoolCatalogue() = default; + ~DummyTapePoolCatalogue() override = default; + + void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) override; + + void deleteTapePool(const std::string &name) override; + + std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria) const override; + + std::optional<TapePool> getTapePool(const std::string &tapePoolName) const override; + + void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t nbPartialTapes) override; + + void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + 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; + + void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + bool tapePoolExists(const std::string& tapePoolName) const override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyVirtualOrganizationCatalogue.cpp b/catalogue/dummy/DummyVirtualOrganizationCatalogue.cpp new file mode 100644 index 0000000000..68fcd9adaf --- /dev/null +++ b/catalogue/dummy/DummyVirtualOrganizationCatalogue.cpp @@ -0,0 +1,84 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <string> + +#include "catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +void DummyVirtualOrganizationCatalogue::createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::deleteVirtualOrganization(const std::string &voName) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +std::list<common::dataStructures::VirtualOrganization> DummyVirtualOrganizationCatalogue::getVirtualOrganizations() const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +common::dataStructures::VirtualOrganization DummyVirtualOrganizationCatalogue::getVirtualOrganizationOfTapepool( + const std::string &tapepoolName) const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +common::dataStructures::VirtualOrganization DummyVirtualOrganizationCatalogue::getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationReadMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationWriteMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationMaxFileSize( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +void DummyVirtualOrganizationCatalogue::modifyVirtualOrganizationDiskInstanceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) { + throw exception::Exception(std::string("In ") + __PRETTY_FUNCTION__ + ": not implemented"); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp b/catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..936eaac300 --- /dev/null +++ b/catalogue/dummy/DummyVirtualOrganizationCatalogue.hpp @@ -0,0 +1,67 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "catalogue/interfaces/VirtualOrganizationCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class DummyVirtualOrganizationCatalogue: public VirtualOrganizationCatalogue { +public: + DummyVirtualOrganizationCatalogue() = default; + ~DummyVirtualOrganizationCatalogue() override = default; + + void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) override; + + void deleteVirtualOrganization(const std::string &voName) override; + + std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const override; + + common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + void modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) override; + + void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t readMaxDrives) override; + + void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t writeMaxDrives) override; + + void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t maxFileSize) override; + + void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &comment) override; + + void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &diskInstance) override; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/AdminUserCatalogue.hpp b/catalogue/interfaces/AdminUserCatalogue.hpp new file mode 100644 index 0000000000..97513e94e9 --- /dev/null +++ b/catalogue/interfaces/AdminUserCatalogue.hpp @@ -0,0 +1,64 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct AdminUser; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringUsername); + +class AdminUserCatalogue { +public: + virtual ~AdminUserCatalogue() = default; + + virtual void createAdminUser(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) = 0; + + virtual void deleteAdminUser(const std::string &username) = 0; + + virtual std::list<common::dataStructures::AdminUser> getAdminUsers() const = 0; + + virtual void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) = 0; + + /** + * Returns true if the specified user running the CTA command-line tool on + * the specified host has administrator privileges. + * + * @param admin The administrator. + * @return True if the specified user running the CTA command-line tool on + * the specified host has administrator privileges. + */ + virtual bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/ArchiveFileCatalogue.hpp b/catalogue/interfaces/ArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..faf4fb3184 --- /dev/null +++ b/catalogue/interfaces/ArchiveFileCatalogue.hpp @@ -0,0 +1,230 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <stdint.h> + +#include <list> +#include <string> + +#include "catalogue/TapeFileSearchCriteria.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct ArchiveFile; +struct ArchiveFileQueueCriteria; +struct ArchiveFileSummary; +struct DeleteArchiveRequest; +struct RequesterIdentity; +} // namespace dataStructures +} // namespace common + +namespace log { +struct LogContext; +} + +namespace catalogue { + +template <typename Item> +class CatalogueItor; + +using ArchiveFileItor = CatalogueItor<common::dataStructures::ArchiveFile>; + +class ArchiveFileCatalogue { +public: + virtual ~ArchiveFileCatalogue() = default; + + /** + * Checks the specified archival could take place and returns a new and + * unique archive file identifier that can be used by a new archive file + * within the catalogue. + * + * @param diskInstanceName The name of the disk instance to which the + * storage class belongs. + * @param storageClassName The name of the storage class of the file to be + * archived. The storage class name is only guaranteed to be unique within + * its disk instance. The storage class name will be used by the Catalogue + * to determine the destination tape pool for each tape copy. + * @param user The user for whom the file is to be archived. This will be + * used by the Catalogue to determine the mount policy to be used when + * archiving the file. + * @return The new archive file identifier. + * @throw UserErrorWithCacheInfo if there was a user error. + */ + virtual uint64_t checkAndGetNextArchiveFileId( + const std::string &diskInstanceName, + const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) = 0; + + /** + * Returns the information required to queue an archive request. + * + * @param diskInstanceName The name of the disk instance to which the + * storage class belongs. + * @param storageClassName The name of the storage class of the file to be + * archived. The storage class name is only guaranteed to be unique within + * its disk instance. The storage class name will be used by the Catalogue + * to determine the destination tape pool for each tape copy. + * @param user The user for whom the file is to be archived. This will be + * used by the Catalogue to determine the mount policy to be used when + * archiving the file. + * @return The information required to queue an archive request. + */ + virtual common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria( + const std::string &diskInstanceName, + const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) = 0; + + /** + * Returns the specified archive files. Please note that the list of files + * is ordered by archive file ID. + * + * @param searchCriteria The search criteria. + * @return The archive files. + */ + virtual ArchiveFileItor getArchiveFilesItor( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; + + /** + * Returns the specified archive file. If the search criteria result in more than one tape file being returned + * an exception is thrown. + * @param searchCriteria The search criteria. + * @return The archive file. + */ + virtual common::dataStructures::ArchiveFile getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; + + /** + * Returns the specified files in tape file sequence order. + * + * @param vid The volume identifier of the tape. + * @param startFSeq The file sequence number of the first file. Please note + * that there might not be a file with this exact file sequence number. + * @param maxNbFiles The maximum number of files to be returned. + * @return The specified files in tape file sequence order. + */ + virtual std::list<common::dataStructures::ArchiveFile> getFilesForRepack( + const std::string &vid, + const uint64_t startFSeq, + const uint64_t maxNbFiles) const = 0; + + /** + * Returns all the tape copies (no matter their VIDs) of the archive files + * associated with the tape files on the specified tape in FSEQ order + * starting at the specified startFSeq. + * + * @param vid The volume identifier of the tape. + * @param startFSeq The file sequence number of the first file. Please note + * that there might not be a file with this exact file sequence number. + * @return The specified files in FSEQ order. + */ + virtual ArchiveFileItor getArchiveFilesForRepackItor( + const std::string &vid, + const uint64_t startFSeq) const = 0; + + /** + * Returns a summary of the tape files that meet the specified search + * criteria. + * + * @param searchCriteria The search criteria. + * @return The summary. + */ + virtual common::dataStructures::ArchiveFileSummary getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const = 0; + + /** + * Returns the archive file with the specified unique identifier. + * + * This method assumes that the archive file being requested exists and will + * therefore throw an exception if it does not. + * + * Please note that an archive file with no associated tape files is + * considered not to exist by this method. + * + * @param id The unique identifier of the archive file. + * @return The archive file. + */ + virtual common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const = 0; + + /** + * Changes the name of hte storage class + * @param archiveFileId Id for file found in ARCHIVE_FILE + * @param newStorageClassName The name of the storage class + */ + virtual void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string& newStorageClassName) const = 0; + + /** + * Changes the fxid in for a archive file + * @param archiveId The archive file id + * @param fxId The eos fxid related to the archive file + * @param diskInstance Disk instace + */ + virtual void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const = 0; + + /** + * Insert the ArchiveFile and all its tape files in the FILE_RECYCLE_LOG table. + * There will be one entry on the FILE_RECYCLE_LOG table per deleted tape file + * + * @param request the DeleteRequest object that holds information about the file to delete. + * @param lc the logContext + */ + virtual void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) = 0; + + /** + * Updates the disk file ID of the specified archive file. + * + * @param archiveFileId The unique identifier of the archive file. + * @param diskInstance The instance name of the source disk system. + * @param diskFileId The identifier of the source disk file which is unique + * within it's host disk system. Two files from different disk systems may + * have the same identifier. The combination of diskInstance and diskFileId + * must be globally unique, in other words unique within the CTA catalogue. + */ + virtual void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) = 0; + + /** + * !!!!!!!!!!!!!!!!!!! THIS METHOD SHOULD NOT BE USED !!!!!!!!!!!!!!!!!!!!!!! + * Deletes the specified archive file and its associated tape copies from the + * catalogue. + * + * Please note that the name of the disk instance is specified in order to + * prevent a disk instance deleting an archive file that belongs to another + * disk instance. + * + * Please note that this method is idempotent. If the file to be deleted does + * not exist in the CTA catalogue then this method returns without error. + * + * @param instanceName The name of the instance from where the deletion request + * originated + * @param archiveFileId The unique identifier of the archive file. + * @param lc The log context. + * @return The metadata of the deleted archive file including the metadata of + * the associated and also deleted tape copies. + */ + virtual void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &instanceName, const uint64_t archiveFileId, + log::LogContext &lc) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/ArchiveRouteCatalogue.hpp b/catalogue/interfaces/ArchiveRouteCatalogue.hpp new file mode 100644 index 0000000000..7c5e157f6f --- /dev/null +++ b/catalogue/interfaces/ArchiveRouteCatalogue.hpp @@ -0,0 +1,97 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <stdint.h> + +#include <string> +#include <list> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct ArchiveRoute; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentArchiveRoute); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroCopyNb); + +class ArchiveRouteCatalogue { +public: + virtual ~ArchiveRouteCatalogue() = default; + + virtual void createArchiveRoute( + const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, + const uint32_t copyNb, + const std::string &tapePoolName, + const std::string &comment) = 0; + + /** + * Deletes the specified archive route. + * + * @param storageClassName The name of the storage class. + * @param copyNb The copy number of the tape file. + */ + virtual void deleteArchiveRoute( + const std::string &storageClassName, + const uint32_t copyNb) = 0; + + virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const = 0; + + /** + * @return the archive routes of the given storage class and destination tape + * pool. + * + * Under normal circumstances this method should return either 0 or 1 route. + * For a given storage class there should be no more than one route to any + * given tape pool. + * + * @param storageClassName The name of the storage class. + * @param tapePoolName The name of the tape pool. + */ + virtual std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes( + const std::string &storageClassName, + const std::string &tapePoolName) const = 0; + + /** + * Modifies the tape pool of the specified archive route. + * + * @param admin The administrator. + * @param storageClassName The name of the storage class. + * @param copyNb The copy number. + * @param tapePoolName The name of the tape pool. + * @throw UserSpecifiedANonExistentTapePool if the user specified a + * non-existent tape pool. + */ + virtual void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) = 0; + + virtual void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/DiskInstanceCatalogue.hpp b/catalogue/interfaces/DiskInstanceCatalogue.hpp new file mode 100644 index 0000000000..b93af857e6 --- /dev/null +++ b/catalogue/interfaces/DiskInstanceCatalogue.hpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct DiskInstance; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskInstanceName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskInstanceAfterDelete); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskInstance); + +class DiskInstanceCatalogue { +public: + virtual ~DiskInstanceCatalogue() = default; + + virtual void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) = 0; + + virtual void deleteDiskInstance(const std::string &name) = 0; + + virtual void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) = 0; + + virtual std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp b/catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp new file mode 100644 index 0000000000..cb147245e9 --- /dev/null +++ b/catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp @@ -0,0 +1,89 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct DiskInstanceSpace; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskInstanceSpaceName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskInstanceSpaceAfterDelete); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskInstanceSpace); + +class DiskInstanceSpaceCatalogue { +public: + virtual ~DiskInstanceSpaceCatalogue() = default; + + /** + * Deletes a disk instance space. + * + * @param name The name of the disk instance. + * @param diskInstance The disk instance of the disk instance space. + */ + virtual void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) = 0; + + /** + * Creates the specified Disk Instance Space + * @param admin The administrator. + * @param name the name of the new disk instance space + * @param diskInstance the disk instance associated to the disk instance space + * @param freeSpaceQueryURL the URL to query to obtain the disk instance space free space + * @param refreshInterval the period to query for disk instance space free space + * @param comment the comment of the new disk instance space + */ + virtual void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstance, + const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, + const std::string &comment) = 0; + + /** + * Returns all the disk instance spaces within the CTA catalogue. + * + * @return The disk instance spaces in the CTA catalogue. + */ + virtual std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const = 0; + + virtual void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &comment) = 0; + + virtual void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) = 0; + + virtual void modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) = 0; + + virtual void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/DiskSystemCatalogue.hpp b/catalogue/interfaces/DiskSystemCatalogue.hpp new file mode 100644 index 0000000000..ac539aba0b --- /dev/null +++ b/catalogue/interfaces/DiskSystemCatalogue.hpp @@ -0,0 +1,106 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +} +} + +namespace disk { +class DiskSystemList; +} + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringDiskSystemName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringFileRegexp); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyDiskSystemAfterDelete); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentDiskSystem); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroSleepTime); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroTargetedFreeSpace); + +class DiskSystemCatalogue { +public: + virtual ~DiskSystemCatalogue() = default; + + /** + * Creates a disk system. + * + * @param admin The administrator. + * @param name The name of the disk system. + * @param fileRegexp The regular expression allowing matching destination URLs + * for this disk system. + * @param freeSpaceQueryURL The query URL that describes a method to query the + * free space from the disk system. + * @param refreshInterval The refresh interval (seconds) defining how long do + * we use a free space value. + * @param targetedFreeSpace The targeted free space (margin) based on the free + * space update latency (inherent to the file system and induced by the refresh + * interval), and the expected external bandwidth from sources external to CTA. + * @param comment Comment. + */ + virtual void createDiskSystem( + const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstanceName, + const std::string &diskInstanceSpaceName, + const std::string &fileRegexp, + const uint64_t targetedFreeSpace, + const time_t sleepTime, + const std::string &comment) = 0; + + /** + * Deletes a disk system. + * + * @param name The name of the disk system. + */ + virtual void deleteDiskSystem(const std::string &name) = 0; + + virtual disk::DiskSystemList getAllDiskSystems() const = 0; + + virtual void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) = 0; + + virtual void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t targetedFreeSpace) = 0; + + virtual void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t sleepTime) = 0; + + virtual void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) = 0; + + virtual void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName) = 0; + + virtual void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceSpaceName) = 0; + + virtual bool diskSystemExists(const std::string &name) const = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/DriveConfigCatalogue.hpp b/catalogue/interfaces/DriveConfigCatalogue.hpp new file mode 100644 index 0000000000..96156bdeba --- /dev/null +++ b/catalogue/interfaces/DriveConfigCatalogue.hpp @@ -0,0 +1,99 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +namespace cta { + +namespace catalogue { + +/** + * Specifies the interface to a factory Catalogue objects. + */ +class DriveConfigCatalogue { +public: + virtual ~DriveConfigCatalogue() = default; + + /* + * Struct with a drive configuration + */ + struct DriveConfig { + std::string tapeDriveName; + std::string category; + std::string keyName; + std::string value; + std::string source; + }; + + /** + * Creates a specified parameter of the configuration for a certain Tape Drive + * @param tapeDriveName The name of the tape drive. + * @param category The category of the parameter. + * @param keyName The key of the parameter. + * @param value The value of the parameter. + * @param source The source from which the parameter was gotten. + */ + virtual void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) = 0; + + /** + * Gets all Drive Configurations of all TapeDrives. + * @return Drive Configurations of all TapeDrives. + */ + virtual std::list<DriveConfig> getTapeDriveConfigs() const = 0; + + /** + * Gets the Key and Names of configurations of all TapeDrives + * @return Keys and Names of configurations. + */ + virtual std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const = 0; + + /** + * Modifies a specified parameter of the configuration for a certain Tape Drive + * @param tapeDriveName The name of the tape drive. + * @param category The category of the parameter. + * @param keyName The key of the parameter. + * @param value The value of the parameter. + * @param source The source from which the parameter was gotten. + */ + virtual void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) = 0; + + /** + * Gets a specified parameter of the configuration for a certain Tape Drive + * @param tapeDriveName The name of the tape drive. + * @param keyName The key of the parameter. + * @return Returns the category, value and source of a parameter of the configuarion + */ + virtual std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) const = 0; + + /** + * Deletes the entry of a Drive Configuration + * @param tapeDriveName The name of the tape drive. + */ + virtual void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) = 0; +}; // class TapeDriveCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/interfaces/DriveStateCatalogue.hpp b/catalogue/interfaces/DriveStateCatalogue.hpp new file mode 100644 index 0000000000..210e5b22f0 --- /dev/null +++ b/catalogue/interfaces/DriveStateCatalogue.hpp @@ -0,0 +1,119 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <optional> +#include <string> + +#include "common/dataStructures/DiskSpaceReservationRequest.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +class DesiredDriveState; +struct TapeDrive; +struct TapeDriveStatistics; +} +} + +namespace log { +class LogContext; +} + +namespace catalogue { + +/** + * Specifies the interface to a factory Catalogue objects. + */ +class DriveStateCatalogue { +public: + virtual ~DriveStateCatalogue() = default; + + /** + * Creates the specified Tape Drive + * @param tapeDrive Parameters of the Tape Drive. + */ + virtual void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) = 0; + + /** + * Gets the names of all stored Tape Drive + * @return List of tape drive names + */ + virtual std::list<std::string> getTapeDriveNames() const = 0; + + /** + * Gets the information of all Tape Drives + * @return Parameters of all Tape Drives. + */ + virtual std::list<common::dataStructures::TapeDrive> getTapeDrives() const = 0; + + /** + * Gets the information of the specified Tape Drive + * @param tapeDriveName The name of the tape drive. + * @return Parameters of the Tape Drive. + */ + virtual std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const = 0; + + /** + * Modifies the desired state parameters off the specified Tape Drive + * @param tapeDriveName Name of the Tape Drive. + * @param desiredState Desired state parameters of the Tape Drive. + */ + virtual void setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) = 0; + + virtual void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) = 0; + + virtual void updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) = 0; + + virtual void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) = 0; + + /** + * Deletes the entry of a Tape Drive + * @param tapeDriveName The name of the tape drive. + */ + virtual void deleteTapeDrive(const std::string &tapeDriveName) = 0; + + /** + * Gets the disk space reservations for all disk systems + */ + virtual std::map<std::string, uint64_t> getDiskSpaceReservations() const = 0; + + /** + * Adds to the current disk space reservation + */ + virtual void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) = 0; + + /** + * Subtracts from the current disk space reservation. + * + * If the amount released exceeds the current reservation, the reservation will be reduced to zero. + */ + virtual void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) = 0; +}; // class DriveStateCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/interfaces/FileRecycleLogCatalogue.hpp b/catalogue/interfaces/FileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..21a8002298 --- /dev/null +++ b/catalogue/interfaces/FileRecycleLogCatalogue.hpp @@ -0,0 +1,80 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/RecyleTapeFileSearchCriteria.hpp" + +namespace cta { +namespace common { +namespace dataStructures { +struct FileRecycleLog; +} // namespace dataStructures +} // namespace common + +namespace log { +struct LogContext; +} + +namespace catalogue { + +template <typename Item> +class CatalogueItor; + +using FileRecycleLogItor = CatalogueItor<common::dataStructures::FileRecycleLog>; + +/** + * Specifies the interface to a factory Catalogue objects. + */ +class FileRecycleLogCatalogue { +public: + virtual ~FileRecycleLogCatalogue() = default; + + /** + * Returns all the currently deleted files by looking at the FILE_RECYCLE_LOG table + * + * @return The deleted archive files ordered by archive file ID. + */ + virtual FileRecycleLogItor getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const = 0; + + /** + * Restores the deleted file in the Recycle log that match the criteria passed + * + * @param searchCriteria The search criteria + * @param newFid the new Fid of the archive file (if the archive file must be restored) + */ + virtual void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) = 0; + + /** + * Deletes all the log entries corresponding to the vid passed in parameter. + * + * Please note that this method is idempotent. If there are no recycle log + * entries associated to the vid passed in parameter, the method will return + * without any error. + * + * @param vid, the vid of the files to be deleted + * @param lc, the logContext + */ + virtual void deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) = 0; +}; // class FileRecyleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/interfaces/LogicalLibraryCatalogue.hpp b/catalogue/interfaces/LogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..ec0aae840d --- /dev/null +++ b/catalogue/interfaces/LogicalLibraryCatalogue.hpp @@ -0,0 +1,73 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct LogicalLibrary; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringLogicalLibraryName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyLogicalLibrary); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentLogicalLibrary); + + +class LogicalLibraryCatalogue { +public: + virtual ~LogicalLibraryCatalogue() = default; + + virtual void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool isDisabled, const std::string &comment) = 0; + + virtual void deleteLogicalLibrary(const std::string &name) = 0; + + virtual std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const = 0; + + /** + * Modifies the name of the specified logical library. + * + * @param admin The administrator. + * @param currentName The current name of the logical library. + * @param newName The new name of the logical library. + */ + virtual void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) = 0; + + virtual void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) = 0; + + virtual void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &disabledReason) = 0; + + virtual void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool disabledValue) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/MediaTypeCatalogue.hpp b/catalogue/interfaces/MediaTypeCatalogue.hpp new file mode 100644 index 0000000000..640bcf2d84 --- /dev/null +++ b/catalogue/interfaces/MediaTypeCatalogue.hpp @@ -0,0 +1,171 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <optional> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringMediaTypeName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringMediaType); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedMediaTypeUsedByTapes); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroCapacity); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringCartridge); + +struct MediaType; +struct MediaTypeWithLogs; + +class MediaTypeCatalogue { +public: + virtual ~MediaTypeCatalogue() = default; + + /** + * Creates a tape media type. + * + * @param admin The administrator. + * @param mediaType The tape media type. + */ + virtual void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) = 0; + + /** + * Deletes the specified tape media type. + * + * @param name The name of the tape media type. + */ + virtual void deleteMediaType(const std::string &name) = 0; + + /** + * Returns all tape media types. + * + * @return All tape media types. + */ + virtual std::list<MediaTypeWithLogs> getMediaTypes() const = 0; + + /** + * Return the media type associated to the tape corresponding to the + * vid passed in parameter + * @param vid the vid of the tape to return its media type + * @return the media type associated to the tape corresponding to the vid passed in parameter + */ + virtual MediaType getMediaTypeByVid(const std::string & vid) const = 0; + + /** + * Modifies the name of the specified tape media type. + * + * @param admin The administrator. + * @param currentName The current name of the tape media type. + * @param newName The new name of the tape media type. + */ + virtual void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) = 0; + + /** + * Modifies the cartidge of the specified tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param cartridge The new cartidge. + */ + virtual void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &cartridge) = 0; + + /** + * Modify the capacity in bytes of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param capacityInBytes The new capacity in bytes. + */ + virtual void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t capacityInBytes) = 0; + + /** + * Modify the SCSI primary density code of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param primaryDensityCode The new SCSI primary density code. + */ + virtual void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t primaryDensityCode) = 0; + + /** + * Modify the SCSI secondary density code of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param secondaryDensityCode The new SCSI secondary density code. + */ + virtual void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t secondaryDensityCode) = 0; + + /** + * Modify the number of tape wraps of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param nbWraps The new number of tape wraps. + */ + virtual void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint32_t> &nbWraps) = 0; + + /** + * Modify the minimum longitudinal tape position of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param minLPos The new minimum longitudinal tape position. + */ + virtual void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &minLPos) = 0; + + /** + * Modify the maximum longitudinal tape position of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param maxLPos The new maximum longitudinal tape position. + */ + virtual void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &maxLPos) = 0; + + /** + * Modify the comment of a tape media type. + * + * @param admin The administrator. + * @param name The name of the tape media type. + * @param comment The new comment. + */ + virtual void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/MountPolicyCatalogue.hpp b/catalogue/interfaces/MountPolicyCatalogue.hpp new file mode 100644 index 0000000000..444200c9fc --- /dev/null +++ b/catalogue/interfaces/MountPolicyCatalogue.hpp @@ -0,0 +1,92 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <optional> +#include <string> + +namespace cta { + +namespace common { +namespace dataStructures { +struct MountPolicy; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +class CreateMountPolicyAttributes; + +class MountPolicyCatalogue { +public: + virtual ~MountPolicyCatalogue() = default; + + virtual void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) = 0; + + /** + * Returns the list of all existing mount policies. + * + * @return the list of all existing mount policies. + */ + virtual std::list<common::dataStructures::MountPolicy> getMountPolicies() const = 0; + + /** + * Returns the mount policy with the specified name. + * + * @return the specified mount policy + */ + virtual std::optional<common::dataStructures::MountPolicy> getMountPolicy( + const std::string &mountPolicyName) const = 0; + + + /** + * Returns the cached list of all existing mount policies. + * + * @return the list of all existing mount policies. + */ + virtual std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const = 0; + + /** + * Deletes the specified mount policy. + * + * @param name The name of the mount policy. + */ + virtual void deleteMountPolicy(const std::string &name) = 0; + + virtual void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) = 0; + + virtual void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minArchiveRequestAge) = 0; + + virtual void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) = 0; + + virtual void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) = 0; + + virtual void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) = 0; + +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp b/catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp new file mode 100644 index 0000000000..ed0632b07b --- /dev/null +++ b/catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp @@ -0,0 +1,90 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +namespace cta { + +namespace common { +namespace dataStructures { +struct RequesterActivityMountRule; +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +class RequesterActivityMountRuleCatalogue { +public: + virtual ~RequesterActivityMountRuleCatalogue() = default; + + virtual void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &mountPolicy) = 0; + + virtual void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) = 0; + + /** + * Creates the rule that the specified mount policy will be used for the + * specified requester+matching activities. + * + * Please note that requester-activity mount-rules overrule requester + * mount-rules. + * + * @param admin The administrator. + * @param mountPolicyName The name of the mount policy. + * @param diskInstance The name of the disk instance to which the requester + * belongs. + * @param activityRegex The regex to match request activities + * @param requesterName The name of the requester which is only guarantted to + * be unique within its disk instance. + * @param comment Comment. + */ + virtual void createRequesterActivityMountRule( + const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, + const std::string &diskInstance, + const std::string &requesterName, + const std::string &activityRegex, + const std::string &comment) = 0; + + /** + * Returns the rules that specify which mount policy is be used for which + * requester + activity. + * + * @return the rules that specify which mount policy is be used for which + * requester + activity. + */ + virtual std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const = 0; + + /** + * Deletes the specified mount rule. + * + * @param diskInstanceName The name of the disk instance to which the + * requester belongs. + * @param requesterName The name of the requester which is only guaranteed to + * be unique within its disk instance. + * @param activityRegex The regex to match request activities + */ + virtual void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, + const std::string &activityRegex) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp b/catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp new file mode 100644 index 0000000000..ba084a00dc --- /dev/null +++ b/catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp @@ -0,0 +1,89 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +namespace cta { + +namespace common { +namespace dataStructures { +class SecurityIdentity; +struct RequesterGroupMountRule; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +class RequesterGroupMountRuleCatalogue { +public: + virtual ~RequesterGroupMountRuleCatalogue() = default; + + virtual void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) = 0; + + virtual void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) = 0; + + /** + * Creates the rule that the specified mount policy will be used for the + * specified requester group. + * + * Please note that requester mount-rules overrule requester-group + * mount-rules. + * + * @param admin The administrator. + * @param mountPolicyName The name of the mount policy. + * @param diskInstanceName The name of the disk instance to which the + * requester group belongs. + * @param requesterGroupName The name of the requester group which is only + * guarantted to be unique within its disk instance. + * @param comment Comment. + */ + virtual void createRequesterGroupMountRule( + const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, + const std::string &diskInstanceName, + const std::string &requesterGroupName, + const std::string &comment) = 0; + + /** + * Returns the rules that specify which mount policy is be used for which + * requester group. + * + * @return the rules that specify which mount policy is be used for which + * requester group. + */ + virtual std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const = 0; + + /** + * Deletes the specified mount rule. + * + * @param diskInstanceName The name of the disk instance to which the + * requester group belongs. + * @param requesterGroupName The name of the requester group which is only + * guaranteed to be unique within its disk instance. + */ + virtual void deleteRequesterGroupMountRule( + const std::string &diskInstanceName, + const std::string &requesterGroupName) = 0; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/interfaces/RequesterMountRuleCatalogue.hpp b/catalogue/interfaces/RequesterMountRuleCatalogue.hpp new file mode 100644 index 0000000000..698425b1ce --- /dev/null +++ b/catalogue/interfaces/RequesterMountRuleCatalogue.hpp @@ -0,0 +1,86 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +namespace cta { + +namespace common { +namespace dataStructures { +class SecurityIdentity; +struct RequesterMountRule; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +class RequesterMountRuleCatalogue { +public: + virtual ~RequesterMountRuleCatalogue() = default; + + virtual void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) = 0; + + virtual void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &comment) = 0; + + /** + * Creates the rule that the specified mount policy will be used for the + * specified requester. + * + * Please note that requester mount-rules overrule requester-group + * mount-rules. + * + * @param admin The administrator. + * @param mountPolicyName The name of the mount policy. + * @param diskInstance The name of the disk instance to which the requester + * belongs. + * @param requesterName The name of the requester which is only guarantted to + * be unique within its disk instance. + * @param comment Comment. + */ + virtual void createRequesterMountRule( + const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, + const std::string &diskInstance, + const std::string &requesterName, + const std::string &comment) = 0; + + /** + * Returns the rules that specify which mount policy is be used for which + * requester. + * + * @return the rules that specify which mount policy is be used for which + * requester. + */ + virtual std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const = 0; + + /** + * Deletes the specified mount rule. + * + * @param diskInstanceName The name of the disk instance to which the + * requester belongs. + * @param requesterName The name of the requester which is only guaranteed to + * be unique within its disk instance. + */ + virtual void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/SchemaCatalogue.hpp b/catalogue/interfaces/SchemaCatalogue.hpp new file mode 100644 index 0000000000..f02b92872d --- /dev/null +++ b/catalogue/interfaces/SchemaCatalogue.hpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "common/exception/Exception.hpp" + +namespace cta { +namespace catalogue { + +class SchemaVersion; + +CTA_GENERATE_EXCEPTION_CLASS(WrongSchemaVersionException); + +class SchemaCatalogue { +public: + virtual ~SchemaCatalogue() = default; + + /** + * Returns the SchemaVersion object corresponding to the catalogue schema version: + * - SCHEMA_VERSION_MAJOR + * - SCHEMA_VERSION_MINOR + * - SCHEMA_VERSION_MAJOR_NEXT (future major version number of the schema in case of upgrade) + * - SCHEMA_VERSION_MINOR_NEXT (future minor version number of the schema in case of upgrade) + * - STATUS (UPGRADING or PRODUCTION) + * + * @return The SchemaVersion object corresponding to the catalogue schema version + */ + virtual SchemaVersion getSchemaVersion() const = 0; + + /** + * Checks that the online database schema MAJOR version number matches + * the schema MAJOR version number defined in version.h + */ + virtual void verifySchemaVersion() = 0; + + /** + * Checks that the most trivial query goes through. Throws an exception if not. + */ + virtual void ping() = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/StorageClassCatalogue.hpp b/catalogue/interfaces/StorageClassCatalogue.hpp new file mode 100644 index 0000000000..6c209266bc --- /dev/null +++ b/catalogue/interfaces/StorageClassCatalogue.hpp @@ -0,0 +1,88 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +struct StorageClass; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringStorageClassName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVo); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByArchiveFiles); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByArchiveRoutes); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedStorageClassUsedByFileRecycleLogs); + +class StorageClassCatalogue { +public: + virtual ~StorageClassCatalogue() = default; + + /** + * Creates the specified storage class. + * + * @param admin The administrator. + * @param storageClass The storage class. + */ + virtual void createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) = 0; + + /** + * Deletes the specified storage class. + * + * @param storageClassName The name of the storage class which is only + * guaranteed to be unique within its disk instance. + */ + virtual void deleteStorageClass(const std::string &storageClassName) = 0; + + virtual std::list<common::dataStructures::StorageClass> getStorageClasses() const = 0; + + virtual common::dataStructures::StorageClass getStorageClass(const std::string &name) const = 0; + + virtual void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) = 0; + + virtual void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) = 0; + + virtual void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) = 0; + + /** + * Modifies the name of the specified storage class. + * + * @param currentName The current name of the storage class. + * @param newName The new name of the storage class. + */ + virtual void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/TapeCatalogue.hpp b/catalogue/interfaces/TapeCatalogue.hpp new file mode 100644 index 0000000000..219d6ab438 --- /dev/null +++ b/catalogue/interfaces/TapeCatalogue.hpp @@ -0,0 +1,286 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <optional> +#include <set> +#include <string> + +#include "catalogue/TapeSearchCriteria.hpp" +#include "common/dataStructures/VidToTapeMap.hpp" +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +struct Tape; +} +} + +namespace log { +class LogContext; +} + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVendor); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringVid); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonEmptyTape); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTape); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTapeState); + +class CreateTapeAttributes; +class TapeForWriting; + +class TapeCatalogue { +public: + virtual ~TapeCatalogue() = default; + + /** + * Creates a tape which is assumed to have isFromCastor disabled. + * + * @param admin The administrator. + * @param tape The attributes of the tape to be created. + */ + virtual void createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes &tape) = 0; + + virtual void deleteTape(const std::string &vid) = 0; + + /** + * Returns the list of tapes that meet the specified search criteria. + * + * @param searchCriteria The search criteria. + * @return The list of tapes. + * @throw UserSpecifiedANonExistentTapePool if the user specified a + * non-existent tape pool. + */ + virtual std::list<common::dataStructures::Tape> getTapes( + const TapeSearchCriteria &searchCriteria = TapeSearchCriteria()) const = 0; + + /** + * Returns the tape with the specified volume identifier. + * + * This method will throw an exception if it cannot find the specified tape. + * + * @param vids The tape volume identifier (VID). + * @return Map from tape volume identifier to tape. + */ + virtual common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const = 0; + + /** + * Returns the tapes with the specified volume identifiers. + * + * This method will throw an exception if it cannot find ALL of the specified + * tapes. + * + * @param vids The tape volume identifiers (VIDs). + * @return Map from tape volume identifier to tape. + */ + virtual common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const = 0; + + /** + * Returns map from VID to logical library name for specified set of VIDs. + * + * @param vids The tape volume identifiers (VIDs). + * @return map from VID to logical library name. + */ + virtual std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const = 0; + + /** + * Reclaims the specified tape. + * + * This method will throw an exception if the specified tape does not exist. + * + * This method will throw an exception if the specified tape is not FULL. + * + * This method will throw an exception if there is still at least one tape + * file recorded in the catalogue as being on the specified tape. + * + * @param admin The administrator. + * @param vid The volume identifier of the tape to be reclaimed. + * @param lc the logContext + */ + virtual void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + cta::log::LogContext & lc) = 0; + + /** + * Checks the specified tape for the tape label command. + * + * This method checks if the tape is safe to be labeled and will throw an + * exception if the specified tape does not ready to be labeled. + * + * @param vid The volume identifier of the tape to be checked. + */ + virtual void checkTapeForLabel(const std::string &vid) = 0; + + /** + * Notifies the catalogue that the specified tape was labelled. + * + * @param vid The volume identifier of the tape. + * @param drive The name of tape drive that was used to label the tape. + */ + virtual void tapeLabelled(const std::string &vid, const std::string &drive) = 0; + + /** + * Returns the number of any files contained in the tape identified by its vid + * @param vid the vid in which we will the number of files + * @return the number of files on the tape + */ + virtual uint64_t getNbFilesOnTape(const std::string &vid) const = 0; + + virtual void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &mediaType) = 0; + + virtual void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &vendor) = 0; + + virtual void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &logicalLibraryName) = 0; + + virtual void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &tapePoolName) = 0; + + virtual void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &encryptionKeyName) = 0; + + virtual void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &verificationStatus) = 0; + + /** + * Returns true if the specified tape exists. + * + * @param vid The volume identifier of the tape. + * @return True if the tape exists. + */ + virtual bool tapeExists(const std::string &vid) const = 0; + + /** + * Modify the state of the specified tape + * @param admin, the person or the system who modified the state of the tape + * @param vid the VID of the tape to change the state + * @param state the new state + * @param stateReason the reason why the state changes, if the state is ACTIVE and the stateReason is std::nullopt, the state will be reset to null + */ + virtual void modifyTapeState(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) = 0; + /** + * Sets the full status of the specified tape. + * + * Please note that this method is to be called by the CTA front-end in + * response to a command from the CTA command-line interface (CLI). + * + * @param admin The administrator. + * @param vid The volume identifier of the tape to be marked as full. + * @param fullValue Set to true if the tape is full. + */ + virtual void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool fullValue) = 0; + + /** + * Sets the dirty status of the specified tape. + * + * Please note that this method is to be called by the CTA front-end in + * response to a command from the CTA command-line interface (CLI). + * + * @param admin The administrator. + * @param vid The volume identifier of the tape to be marked as full. + * @param dirty Set to true if the tape is dirty. + */ + virtual void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirty) = 0; + + /** + * This method notifies the CTA catalogue to set the specified tape is from CASTOR. + * This method only for unitTests and MUST never be called in CTA!!! + * + * @param vid The volume identifier of the tape. + */ + virtual void setTapeIsFromCastorInUnitTests(const std::string &vid) = 0; + + virtual void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) = 0; + + virtual void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) = 0; + + virtual void setTapeDirty(const std::string & vid) = 0; + + /** + * Modifies the tape comment + * If the comment == std::nullopt, it will delete the comment from the tape table + * @param admin the admin who removes the comment + * @param vid the vid of the tape to remove the comment + * @param comment the new comment. If comment == std::nullopt, the comment will be deleted. + */ + virtual void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::optional<std::string> &comment) = 0; + + /** + * Notifies the CTA catalogue that the specified tape has been mounted in + * order to archive files. + * + * The purpose of this method is to keep track of which drive mounted a given + * tape for archiving files last. + * + * @param vid The volume identifier of the tape. + * @param drive The name of the drive where the tape was mounted. + */ + virtual void tapeMountedForArchive(const std::string &vid, const std::string &drive) = 0; // internal function (noCLI) + + /** + * Notifies the CTA catalogue that the specified tape has been mounted in + * order to retrieve files. + * + * The purpose of this method is to keep track of which drive mounted a given + * tape for retrieving files last. + * + * @param vid The volume identifier of the tape. + * @param drive The name of the drive where the tape was mounted. + */ + virtual void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) = 0; + + /** + * This method notifies the CTA catalogue that there is no more free space on + * the specified tape. + * + * @param vid The volume identifier of the tape. + */ + virtual void noSpaceLeftOnTape(const std::string &vid) = 0; + + /** + * Returns the list of tapes that can be written to by a tape drive in the + * specified logical library, in other words tapes that are labelled, not + * disabled, not full, not read-only and are in the specified logical library. + * + * @param logicalLibraryName The name of the logical library. + * @return The list of tapes for writing. + */ + virtual std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const = 0; + + virtual common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/TapeFileCatalogue.hpp b/catalogue/interfaces/TapeFileCatalogue.hpp new file mode 100644 index 0000000000..fbad28d441 --- /dev/null +++ b/catalogue/interfaces/TapeFileCatalogue.hpp @@ -0,0 +1,96 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <set> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct ArchiveFile; +struct RequesterIdentity; +struct RetrieveFileQueueCriteria; +} +} + +namespace log { +struct LogContext; +} + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedExistingDeletedFileCopy); + +class TapeItemWrittenPointer; + +/** + * Specifies the interface to a factory Catalogue objects. + */ +class TapeFileCatalogue { +public: + virtual ~TapeFileCatalogue() = default; + + /** + * Notifies the catalogue that the specified files have been written to tape. + * + * @param events The tape file written events. + * @throw TapeFseqMismatch If an unexpected tape file sequence number is encountered. + * @throw FileSizeMismatch If an unexpected tape file size is encountered. + */ + virtual void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) = 0; + + /** + * Deletes a tape file copy + * + * @param file The tape file to delete + * @param reason The reason for deleting the tape file copy + */ + virtual void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) = 0; + + /** + * Prepares for a file retrieval by returning the information required to + * queue the associated retrieve request(s). + * + * @param diskInstanceName The name of the instance from where the retrieval + * request originated + * @param archiveFileId The unique identifier of the archived file that is + * to be retrieved. + * @param user The user for whom the file is to be retrieved. This will be + * used by the Catalogue to determine the mount policy to be used when + * retrieving the file. + * @param activity The activity under which the user wants to start the retrieve + * The call will fail if the activity is set and unknown. + * @param lc The log context. + * + * @return The information required to queue the associated retrieve request(s). + */ + virtual common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile( + const std::string &diskInstanceName, + const uint64_t archiveFileId, + const common::dataStructures::RequesterIdentity &user, + const std::optional<std::string> & activity, + log::LogContext &lc, + const std::optional<std::string> &mountPolicyName = std::nullopt) = 0; +}; // class FileRecyleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/interfaces/TapePoolCatalogue.hpp b/catalogue/interfaces/TapePoolCatalogue.hpp new file mode 100644 index 0000000000..eb2e7ab3f1 --- /dev/null +++ b/catalogue/interfaces/TapePoolCatalogue.hpp @@ -0,0 +1,87 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/TapePoolSearchCriteria.hpp" +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +class TapePool; + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringTapePoolName); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyTapePool); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentTapePool); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedTapePoolUsedInAnArchiveRoute); + +class TapePoolCatalogue { +public: + virtual ~TapePoolCatalogue() = default; + + virtual void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) = 0; + + virtual void deleteTapePool(const std::string &name) = 0; + + virtual std::list<TapePool> getTapePools( + const TapePoolSearchCriteria &searchCriteria = TapePoolSearchCriteria()) const = 0; + + virtual std::optional<TapePool> getTapePool(const std::string &tapePoolName) const = 0; + + virtual void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) = 0; + + virtual void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbPartialTapes) = 0; + + virtual void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) = 0; + + 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; + + virtual void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) = 0; + + /** + * Returns true if the specified tape pool exists. + * + * @param tapePoolName The name of the tape pool. + * @return True if the tape pool exists. + */ + virtual bool tapePoolExists(const std::string &tapePoolName) const = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/interfaces/VirtualOrganizationCatalogue.hpp b/catalogue/interfaces/VirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..f17cc46371 --- /dev/null +++ b/catalogue/interfaces/VirtualOrganizationCatalogue.hpp @@ -0,0 +1,135 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <string> + +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +struct VirtualOrganization; +} // namespace dataStructures +} // namespace common + +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedANonExistentVirtualOrganization); + +class VirtualOrganizationCatalogue { +public: + virtual ~VirtualOrganizationCatalogue() = default; + + /** + * Creates the specified Virtual Organization + * @param admin The administrator. + * @param vo the Virtual Organization + */ + virtual void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) = 0; + + /** + * Deletes the specified Virtual Organization + * @param voName the name of the VirtualOrganization to delete + */ + virtual void deleteVirtualOrganization(const std::string &voName) = 0; + + /** + * Get all the Virtual Organizations from the Catalogue + * @return the list of all the Virtual Organizations + */ + virtual std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const = 0; + + /** + * Get the virtual organization corresponding to the tapepool passed in parameter + * @param tapepoolName the name of the tapepool which we want the virtual organization + * @return the VirtualOrganization associated to the tapepool passed in parameter + */ + virtual common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const = 0; + + /** + * Get, from the cache, the virtual organization corresponding to the tapepool passed in parameter + * @param tapepoolName the name of the tapepool which we want the virtual organization + * @return the VirtualOrganization associated to the tapepool passed in parameter + */ + virtual common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const = 0; + + /** + * Modifies the name of the specified Virtual Organization. + * + * @param currentVoName The current name of the Virtual Organization. + * @param newVoName The new name of the Virtual Organization. + */ + virtual void modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) = 0; + + /** + * Modifies the max number of allocated drives for read for the specified Virtual Organization + * + * @param voName the VO name + * @param readMaxDrives the new max number of allocated drives for read for the specified Virtual Organization + */ + virtual void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t readMaxDrives) = 0; + + /** + * Modifies the max number of allocated drives for write for the specified Virtual Organization + * + * @param voName the VO name + * @param writeMaxDrives the new max number of allocated drives for write for the specified Virtual Organization + */ + virtual void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t writeMaxDrives) = 0; + + /** + * Modifies the max size of files for the specified Virtual Organization + * + * @param voName the VO name + * @param maxFileSize the new max file size for the specified Virtual Organization + */ + virtual void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t maxFileSize) = 0; + + /** + * Modifies the comment of the specified Virtual Organization + * + * @param voName The name of the Virtual Organization. + * @param comment The new comment of the Virtual Organization. + */ + virtual void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &comment) = 0; + + /** + * Modifies the comment of the specified Virtual Organization + * + * @param voName The name of the Virtual Organization. + * @param diskInstance The new disk instance of the Virtual Organization. + */ + virtual void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &diskInstance) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/CommonExceptions.hpp b/catalogue/rdbms/CommonExceptions.hpp new file mode 100644 index 0000000000..02359c9165 --- /dev/null +++ b/catalogue/rdbms/CommonExceptions.hpp @@ -0,0 +1,31 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <common/exception/Exception.hpp> +#include <common/exception/UserError.hpp> + +namespace cta { +namespace catalogue { + +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringComment); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAZeroRefreshInterval); +CTA_GENERATE_USER_EXCEPTION_CLASS(UserSpecifiedAnEmptyStringFreeSpaceQueryURL); + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsAdminUserCatalogue.cpp b/catalogue/rdbms/RdbmsAdminUserCatalogue.cpp new file mode 100644 index 0000000000..ff1b31a375 --- /dev/null +++ b/catalogue/rdbms/RdbmsAdminUserCatalogue.cpp @@ -0,0 +1,287 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsAdminUserCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/Logger.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + + +RdbmsAdminUserCatalogue::RdbmsAdminUserCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool): + m_log(log), m_connPool(connPool), m_isAdminCache(10) {} + +void RdbmsAdminUserCatalogue::createAdminUser( + const common::dataStructures::SecurityIdentity &admin, + const std::string &username, + const std::string &comment) { + try { + if (username.empty()) { + throw UserSpecifiedAnEmptyStringUsername("Cannot create admin user because the username is an empty string"); + } + + if (comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create admin user because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + auto conn = m_connPool->getConn(); + if (adminUserExists(conn, username)) { + throw exception::UserError(std::string("Cannot create admin user " + username + + " because an admin user with the same name already exists")); + } + const uint64_t now = time(nullptr); + const char *const sql = + "INSERT INTO ADMIN_USER(" + "ADMIN_USER_NAME," + + "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(" + ":ADMIN_USER_NAME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":ADMIN_USER_NAME", username); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsAdminUserCatalogue::adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const { + try { + const char *const sql = + "SELECT " + "ADMIN_USER_NAME AS ADMIN_USER_NAME " + "FROM " + "ADMIN_USER " + "WHERE " + "ADMIN_USER_NAME = :ADMIN_USER_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":ADMIN_USER_NAME", adminUsername); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsAdminUserCatalogue::deleteAdminUser(const std::string &username) { + try { + const char *const sql = "DELETE FROM ADMIN_USER WHERE ADMIN_USER_NAME = :ADMIN_USER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":ADMIN_USER_NAME", username); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete admin-user ") + username + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::AdminUser> RdbmsAdminUserCatalogue::getAdminUsers() const { + try { + std::list<common::dataStructures::AdminUser> admins; + const char *const sql = + "SELECT " + "ADMIN_USER_NAME AS ADMIN_USER_NAME," + + "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 " + "FROM " + "ADMIN_USER " + "ORDER BY " + "ADMIN_USER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::AdminUser admin; + + admin.name = rset.columnString("ADMIN_USER_NAME"); + admin.comment = rset.columnString("USER_COMMENT"); + admin.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + admin.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + admin.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + admin.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + admin.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + admin.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + admins.push_back(admin); + } + + return admins; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsAdminUserCatalogue::modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) { + try { + if (username.empty()) { + throw UserSpecifiedAnEmptyStringUsername("Cannot modify admin user because the username is an empty string"); + } + + if (comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot modify admin user because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE ADMIN_USER SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "ADMIN_USER_NAME = :ADMIN_USER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":ADMIN_USER_NAME", username); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify admin user ") + username + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// isNonCachedAdmin +//------------------------------------------------------------------------------ +bool RdbmsAdminUserCatalogue::isNonCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const { + try { + const char *const sql = + "SELECT " + "ADMIN_USER_NAME AS ADMIN_USER_NAME " + "FROM " + "ADMIN_USER " + "WHERE " + "ADMIN_USER_NAME = :ADMIN_USER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":ADMIN_USER_NAME", admin.username); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsAdminUserCatalogue::isCachedAdmin(const common::dataStructures::SecurityIdentity &admin) + const { + try { + auto getNonCachedValue = [&] { + return isNonCachedAdmin(admin); + }; + return m_isAdminCache.getCachedValue(admin, getNonCachedValue).value; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsAdminUserCatalogue::isAdmin(const common::dataStructures::SecurityIdentity &admin) const { + try { + return isCachedAdmin(admin); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta + diff --git a/catalogue/rdbms/RdbmsAdminUserCatalogue.hpp b/catalogue/rdbms/RdbmsAdminUserCatalogue.hpp new file mode 100644 index 0000000000..7583f0ce13 --- /dev/null +++ b/catalogue/rdbms/RdbmsAdminUserCatalogue.hpp @@ -0,0 +1,90 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/AdminUserCatalogue.hpp" +#include "catalogue/TimeBasedCache.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsAdminUserCatalogue : public AdminUserCatalogue { +public: + RdbmsAdminUserCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsAdminUserCatalogue() override = default; + + void createAdminUser(const common::dataStructures::SecurityIdentity &admin, const std::string &username, + const std::string &comment) override; + + void deleteAdminUser(const std::string &username) override; + + std::list<common::dataStructures::AdminUser> getAdminUsers() const override; + + void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) override; + + bool isAdmin(const common::dataStructures::SecurityIdentity &admin) const override; + +private: + /** + * Returns true if the specified admin user exists. + * + * @param conn The database connection. + * @param adminUsername The name of the admin user. + * @return True if the admin user exists. + */ + bool adminUserExists(rdbms::Conn &conn, const std::string adminUsername) const; + + /** + * Returns a cached version of the result of calling isAdmin(). + * + * @param admin The administrator. + * @return True if the specified user has administrator privileges. + */ + bool isCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const; + + /** + * Returns true if the specified user has administrator privileges. + * + * Please note that this method always queries the Catalogue database. + * + * @param admin The administrator. + * @return True if the specified user has administrator privileges. + */ + bool isNonCachedAdmin(const common::dataStructures::SecurityIdentity &admin) const; + + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + + /** + * Cached version of isAdmin() results. + */ + mutable TimeBasedCache<common::dataStructures::SecurityIdentity, bool> m_isAdminCache; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsArchiveFileCatalogue.cpp b/catalogue/rdbms/RdbmsArchiveFileCatalogue.cpp new file mode 100644 index 0000000000..213a838ebf --- /dev/null +++ b/catalogue/rdbms/RdbmsArchiveFileCatalogue.cpp @@ -0,0 +1,1209 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/ArchiveFileRow.hpp" +#include "catalogue/ArchiveFileRowWithoutTimestamps.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/Group.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" +#include "catalogue/User.hpp" +#include "catalogue/ValueAndTimeBasedCacheInfo.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/RequesterIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/LostDatabaseConnection.hpp" +#include "common/exception/UserError.hpp" +#include "common/exception/UserErrorWithCacheInfo.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsArchiveFileCatalogue::RdbmsArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), + m_connPool(connPool), + m_rdbmsCatalogue(rdbmsCatalogue), + m_tapeCopyToPoolCache(10), + m_expectedNbArchiveRoutesCache(10) {} + +uint64_t RdbmsArchiveFileCatalogue::checkAndGetNextArchiveFileId(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { + try { + const auto storageClass = catalogue::StorageClass(storageClassName); + const auto copyToPoolMap = getCachedTapeCopyToPoolMap(storageClass); + const auto expectedNbRoutes = getCachedExpectedNbArchiveRoutes(storageClass); + + // Check that the number of archive routes is correct + if(copyToPoolMap.empty()) { + exception::UserError ue; + ue.getMessage() << "Storage class " << storageClassName << " has no archive routes"; + throw ue; + } + if(copyToPoolMap.size() != expectedNbRoutes) { + exception::UserError ue; + ue.getMessage() << "Storage class " << storageClassName << " does not have the" + " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" << + copyToPoolMap.size(); + throw ue; + } + + const auto userMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, user.name)); + const auto userMountPolicy = userMountPolicyAndCacheInfo.value; + // Only consider the requester's group if there is no user mount policy + if(!userMountPolicy) { + const auto groupMountPolicyAndCacheInfo = getCachedRequesterGroupMountPolicy(Group(diskInstanceName, user.group)); + const auto groupMountPolicy = groupMountPolicyAndCacheInfo.value; + + if(!groupMountPolicy) { + + const auto defaultUserMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, "default")); + const auto defaultUserMountPolicy = defaultUserMountPolicyAndCacheInfo.value; + + if(!defaultUserMountPolicy) { + exception::UserErrorWithCacheInfo ue(userMountPolicyAndCacheInfo.cacheInfo); + ue.getMessage() << "Failed to check and get next archive file ID: No mount rules: storageClass=" << + storageClassName << " requester=" << diskInstanceName << ":" << user.name << ":" << user.group; + throw ue; + } + } + } + + // Now that we have found both the archive routes and the mount policy it's + // safe to consume an archive file identifier + { + auto conn = m_connPool->getConn(); + return getNextArchiveFileId(conn); + } + } catch(exception::UserErrorWithCacheInfo &ue) { + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("cacheInfo", ue.cacheInfo) + .add("userError", ue.getMessage().str()); + lc.log(log::INFO, "Catalogue::checkAndGetNextArchiveFileId caught a UserErrorWithCacheInfo"); + throw; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::ArchiveFileQueueCriteria RdbmsArchiveFileCatalogue::getArchiveFileQueueCriteria( + const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) { + try { + const auto storageClass = catalogue::StorageClass(storageClassName); + const common::dataStructures::TapeCopyToPoolMap copyToPoolMap = getCachedTapeCopyToPoolMap(storageClass); + const uint64_t expectedNbRoutes = getCachedExpectedNbArchiveRoutes(storageClass); + + // Check that the number of archive routes is correct + if(copyToPoolMap.empty()) { + exception::UserError ue; + ue.getMessage() << "Storage class " << diskInstanceName << ": " << storageClassName << " has no archive routes"; + throw ue; + } + if(copyToPoolMap.size() != expectedNbRoutes) { + exception::UserError ue; + ue.getMessage() << "Storage class " << diskInstanceName << ": " << storageClassName << " does not have the" + " expected number of archive routes routes: expected=" << expectedNbRoutes << ", actual=" << + copyToPoolMap.size(); + throw ue; + } + + // Get the mount policy - user mount policies overrule group ones + const auto userMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, user.name)); + const auto userMountPolicy = userMountPolicyAndCacheInfo.value; + + if(userMountPolicy) { + return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *userMountPolicy); + } else { + const auto groupMountPolicyAndCacheInfo = getCachedRequesterGroupMountPolicy(Group(diskInstanceName, user.group)); + const auto groupMountPolicy = groupMountPolicyAndCacheInfo.value; + + if(groupMountPolicy) { + return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *groupMountPolicy); + } else { + const auto defaultUserMountPolicyAndCacheInfo = getCachedRequesterMountPolicy(User(diskInstanceName, "default")); + const auto defaultUserMountPolicy = defaultUserMountPolicyAndCacheInfo.value; + + if(defaultUserMountPolicy) { + return common::dataStructures::ArchiveFileQueueCriteria(copyToPoolMap, *defaultUserMountPolicy); + } else { + exception::UserErrorWithCacheInfo ue(defaultUserMountPolicyAndCacheInfo.cacheInfo); + ue.getMessage() << "Failed to get archive file queue criteria: No mount rules: storageClass=" << + storageClassName << " requester=" << diskInstanceName << ":" << user.name << ":" << user.group; + throw ue; + } + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +ArchiveFileItor RdbmsArchiveFileCatalogue::getArchiveFilesItor(const TapeFileSearchCriteria &searchCriteria) const { + checkTapeFileSearchCriteria(searchCriteria); + + // If this is the listing of the contents of a tape + if (!searchCriteria.archiveFileId && !searchCriteria.diskInstance && !searchCriteria.diskFileIds && + !searchCriteria.fSeq && searchCriteria.vid) { + return getTapeContentsItor(searchCriteria.vid.value()); + } + + try { + // Create a connection to populate the temporary table (specialised by database type) + auto conn = m_rdbmsCatalogue->m_archiveFileListingConnPool->getConn(); + const auto tempDiskFxidsTableName = m_rdbmsCatalogue->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); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::ArchiveFile RdbmsArchiveFileCatalogue::getArchiveFileForDeletion( + const TapeFileSearchCriteria &criteria) const { + if (!criteria.diskFileIds && !criteria.archiveFileId) { + throw exception::UserError("To delete a file copy either the diskFileId+diskInstanceName or archiveFileId must be specified"); + } + if (criteria.diskFileIds && !criteria.diskInstance) { + throw exception::UserError("DiskFileId makes no sense without disk instance"); + } + if (!criteria.vid) { + throw exception::UserError("Vid must be specified"); + } + + auto vid = criteria.vid.value(); + TapeFileSearchCriteria searchCriteria = criteria; + searchCriteria.vid = std::nullopt; //unset vid, we want to get all copies of the archive file so we can check that it is not a one copy file + auto itor = getArchiveFilesItor(searchCriteria); + + // itor should have at most one archive file since we always search on unique attributes + if (!itor.hasMore()) { + if (criteria.archiveFileId) { + throw exception::UserError(std::string("Cannot delete a copy of the file with archiveFileId ") + + std::to_string(criteria.archiveFileId.value()) + + " because the file does not exist"); + } else { + throw exception::UserError(std::string("Cannot delete a copy of the file with eosFxid ") + + criteria.diskFileIds.value().front() + " and diskInstance " + + criteria.diskInstance.value() + " because the file does not exist"); + } + } + + cta::common::dataStructures::ArchiveFile af = itor.next(); + + if (af.tapeFiles.size() == 1) { + if (criteria.archiveFileId) { + throw exception::UserError(std::string("Cannot delete a copy of the file with archiveFileId ") + + std::to_string(criteria.archiveFileId.value()) + + " because it is the only copy"); + } else { + throw exception::UserError(std::string("Cannot delete a copy of the file with eosFxid ") + + criteria.diskFileIds.value().front() + " and diskInstance " + + criteria.diskInstance.value() + " because it is the only copy"); + } + } + af.tapeFiles.removeAllVidsExcept(vid); // assume there is only one copy per vid, this should return a list with at most one item + if (af.tapeFiles.empty()) { + if (criteria.archiveFileId) { + throw exception::UserError(std::string("No copy of the file with archiveFileId ") + + std::to_string(criteria.archiveFileId.value()) + + " on vid " + vid); + } else { + throw exception::UserError(std::string("No copy of the file with eosFxid ") + + criteria.diskFileIds.value().front() + " and diskInstance " + + criteria.diskInstance.value() + " on vid " + vid); + } + } + if (af.tapeFiles.size() > 1){ + if (criteria.archiveFileId) { + throw exception::UserError(std::string("Error: More than one copy of the file with archiveFileId ") + + std::to_string(criteria.archiveFileId.value()) + + " on vid " + vid); + } else { + throw exception::UserError(std::string("Error: More than one copy of the file with eosFxid ") + + criteria.diskFileIds.value().front() + " and diskInstance " + + criteria.diskInstance.value() + " on vid " + vid); + } + } + return af; +} + +std::list<common::dataStructures::ArchiveFile> RdbmsArchiveFileCatalogue::getFilesForRepack(const std::string &vid, + const uint64_t startFSeq, const uint64_t maxNbFiles) const { + try { + std::string sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "INNER JOIN TAPE ON " + "TAPE_FILE.VID = TAPE.VID " + "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 " + "ORDER BY FSEQ"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.bindUint64(":START_FSEQ", startFSeq); + auto rset = stmt.executeQuery(); + + std::list<common::dataStructures::ArchiveFile> archiveFiles; + while(rset.next()) { + common::dataStructures::ArchiveFile archiveFile; + + archiveFile.archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); + archiveFile.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + archiveFile.diskFileId = rset.columnString("DISK_FILE_ID"); + archiveFile.diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); + archiveFile.diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); + archiveFile.fileSize = rset.columnUint64("SIZE_IN_BYTES"); + archiveFile.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + archiveFile.storageClass = rset.columnString("STORAGE_CLASS_NAME"); + archiveFile.creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + archiveFile.reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); + + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = rset.columnString("VID"); + tapeFile.fSeq = rset.columnUint64("FSEQ"); + tapeFile.blockId = rset.columnUint64("BLOCK_ID"); + tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); + tapeFile.copyNb = rset.columnUint64("COPY_NB"); + tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + tapeFile.checksumBlob = archiveFile.checksumBlob; // Duplicated for convenience + + archiveFile.tapeFiles.push_back(tapeFile); + + archiveFiles.push_back(archiveFile); + + if(maxNbFiles == archiveFiles.size()) break; + } + return archiveFiles; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +ArchiveFileItor RdbmsArchiveFileCatalogue::getArchiveFilesForRepackItor(const std::string &vid, + const uint64_t startFSeq) const { + try { + auto impl = new RdbmsCatalogueGetArchiveFilesForRepackItor(m_log, *(m_rdbmsCatalogue->m_archiveFileListingConnPool), + vid, startFSeq); + return ArchiveFileItor(impl); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::ArchiveFileSummary RdbmsArchiveFileCatalogue::getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria) const { + try { + auto conn = m_connPool->getConn(); + + std::string sql = + "SELECT " + "COALESCE(SUM(ARCHIVE_FILE.SIZE_IN_BYTES), 0) AS TOTAL_BYTES," + "COUNT(ARCHIVE_FILE.ARCHIVE_FILE_ID) AS TOTAL_FILES " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "INNER JOIN TAPE ON " + "TAPE_FILE.VID = TAPE.VID " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID"; + + const bool thereIsAtLeastOneSearchCriteria = + searchCriteria.archiveFileId || + searchCriteria.diskInstance || + searchCriteria.vid || + searchCriteria.diskFileIds; + + if(thereIsAtLeastOneSearchCriteria) { + sql += " WHERE "; + } + + bool addedAWhereConstraint = false; + + if(searchCriteria.archiveFileId) { + sql += " ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + addedAWhereConstraint = true; + } + if(searchCriteria.diskInstance) { + if(addedAWhereConstraint) sql += " AND "; + sql += "ARCHIVE_FILE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; + addedAWhereConstraint = true; + } + if(searchCriteria.vid) { + if(addedAWhereConstraint) sql += " AND "; + sql += "TAPE_FILE.VID = :VID"; + addedAWhereConstraint = true; + } + if(searchCriteria.diskFileIds) { + const auto tempDiskFxidsTableName = m_rdbmsCatalogue->createAndPopulateTempTableFxid(conn, + searchCriteria.diskFileIds); + + if(addedAWhereConstraint) sql += " AND "; + sql += "ARCHIVE_FILE.DISK_FILE_ID IN (SELECT DISK_FILE_ID FROM " + tempDiskFxidsTableName + ")"; + addedAWhereConstraint = true; + } + + auto stmt = conn.createStmt(sql); + if(searchCriteria.archiveFileId) { + stmt.bindUint64(":ARCHIVE_FILE_ID", searchCriteria.archiveFileId.value()); + } + if(searchCriteria.diskInstance) { + stmt.bindString(":DISK_INSTANCE_NAME", searchCriteria.diskInstance.value()); + } + if(searchCriteria.vid) { + stmt.bindString(":VID", searchCriteria.vid.value()); + } + auto rset = stmt.executeQuery(); + + if(!rset.next()) { + throw exception::Exception("SELECT COUNT statement did not return a row"); + } + + common::dataStructures::ArchiveFileSummary summary; + summary.totalBytes = rset.columnUint64("TOTAL_BYTES"); + summary.totalFiles = rset.columnUint64("TOTAL_FILES"); + return summary; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::ArchiveFile RdbmsArchiveFileCatalogue::getArchiveFileById(const uint64_t id) const { + try { + auto conn = m_connPool->getConn(); + const auto archiveFile = getArchiveFileById(conn, id); + + // Throw an exception if the archive file does not exist + if(nullptr == archiveFile.get()) { + exception::Exception ex; + ex.getMessage() << "No such archive file with ID " << id; + throw (ex); + } + + return *archiveFile; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsArchiveFileCatalogue::getArchiveFileById(rdbms::Conn &conn, + const uint64_t id) const { + try { + const char *const sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " + "ORDER BY " + "TAPE_FILE.CREATION_TIME ASC"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", id); + auto rset = stmt.executeQuery(); + std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; + while (rset.next()) { + if(nullptr == archiveFile.get()) { + archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); + + archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); + archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); + archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); + archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); + archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); + archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); + archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); + } + + // If there is a tape file + if(!rset.columnIsNull("VID")) { + // Add the tape file to the archive file's in-memory structure + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = rset.columnString("VID"); + tapeFile.fSeq = rset.columnUint64("FSEQ"); + tapeFile.blockId = rset.columnUint64("BLOCK_ID"); + tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); + tapeFile.copyNb = rset.columnUint64("COPY_NB"); + tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience + + archiveFile->tapeFiles.push_back(tapeFile); + } + } + + return archiveFile; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::TapeCopyToPoolMap RdbmsArchiveFileCatalogue::getCachedTapeCopyToPoolMap( + const catalogue::StorageClass &storageClass) const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + return getTapeCopyToPoolMap(conn, storageClass); + }; + return m_tapeCopyToPoolCache.getCachedValue(storageClass, getNonCachedValue).value; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t RdbmsArchiveFileCatalogue::getCachedExpectedNbArchiveRoutes( + const catalogue::StorageClass &storageClass) const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + return getExpectedNbArchiveRoutes(conn, storageClass); + }; + return m_expectedNbArchiveRoutesCache.getCachedValue(storageClass, getNonCachedValue).value; + } catch (exception::LostDatabaseConnection &le) { + throw exception::LostDatabaseConnection(std::string(__FUNCTION__) + " failed: " + le.getMessage().str()); + } catch(exception::UserError &) { + throw; + } catch (exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy>> + RdbmsArchiveFileCatalogue::getCachedRequesterMountPolicy(const User &user) const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + const auto mountPolicy = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + return mountPolicy->getRequesterMountPolicy(conn, user); + }; + return m_rdbmsCatalogue->m_userMountPolicyCache.getCachedValue(user, getNonCachedValue); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getCachedRequesterGroupMountPolicy +//------------------------------------------------------------------------------ +ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy>> + RdbmsArchiveFileCatalogue::getCachedRequesterGroupMountPolicy(const Group &group) const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + const auto mountPolicyCatalogue = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + return mountPolicyCatalogue->getRequesterGroupMountPolicy(conn, group); + }; + return m_rdbmsCatalogue->m_groupMountPolicyCache.getCachedValue(group, getNonCachedValue); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +ArchiveFileItor RdbmsArchiveFileCatalogue::getArchiveFilesItor(rdbms::Conn &conn, + const TapeFileSearchCriteria &searchCriteria) const { + + checkTapeFileSearchCriteria(conn, searchCriteria); + + // If this is the listing of the contents of a tape + if (!searchCriteria.archiveFileId && !searchCriteria.diskInstance && !searchCriteria.diskFileIds && + searchCriteria.vid) { + return getTapeContentsItor(searchCriteria.vid.value()); + } + + try { + auto archiveListingConn = m_rdbmsCatalogue->m_archiveFileListingConnPool->getConn(); + const auto tempDiskFxidsTableName = m_rdbmsCatalogue->createAndPopulateTempTableFxid(archiveListingConn, + searchCriteria.diskFileIds); + // Pass ownership of the connection to the Iterator object + auto impl = new RdbmsCatalogueGetArchiveFilesItor(m_log, std::move(archiveListingConn), searchCriteria, + tempDiskFxidsTableName); + return ArchiveFileItor(impl); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveFileCatalogue::checkTapeFileSearchCriteria(const TapeFileSearchCriteria &searchCriteria) const { + auto conn = m_connPool->getConn(); + checkTapeFileSearchCriteria(conn, searchCriteria); + +} + +void RdbmsArchiveFileCatalogue::checkTapeFileSearchCriteria(rdbms::Conn &conn, + const TapeFileSearchCriteria &searchCriteria) const { + if(searchCriteria.archiveFileId) { + if(!RdbmsCatalogueUtils::archiveFileIdExists(conn, searchCriteria.archiveFileId.value())) { + throw exception::UserError(std::string("Archive file with ID ") + + std::to_string(searchCriteria.archiveFileId.value()) + " does not exist"); + } + } + + if(searchCriteria.diskFileIds && !searchCriteria.diskInstance) { + throw exception::UserError(std::string("Disk file IDs are ambiguous without disk instance name")); + } + + if (searchCriteria.fSeq && !searchCriteria.vid) { + throw exception::UserError(std::string("fSeq makes no sense without vid")); + } + + if(searchCriteria.vid) { + if(!RdbmsCatalogueUtils::tapeExists(conn, searchCriteria.vid.value())) { + throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist"); + } + } +} + +ArchiveFileItor RdbmsArchiveFileCatalogue::getTapeContentsItor(const std::string &vid) const { + try { + // Create a connection to populate the temporary table (specialised by database type) + auto impl = new RdbmsCatalogueTapeContentsItor(m_log, *m_connPool, vid); + return ArchiveFileItor(impl); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::TapeCopyToPoolMap RdbmsArchiveFileCatalogue::getTapeCopyToPoolMap(rdbms::Conn &conn, + const catalogue::StorageClass &storageClass) const { + try { + common::dataStructures::TapeCopyToPoolMap copyToPoolMap; + const char *const sql = + "SELECT " + "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," + "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.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClass.storageClassName); + auto rset = stmt.executeQuery(); + while (rset.next()) { + const uint32_t copyNb = rset.columnUint64("COPY_NB"); + const std::string tapePoolName = rset.columnString("TAPE_POOL_NAME"); + copyToPoolMap[copyNb] = tapePoolName; + } + + return copyToPoolMap; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t RdbmsArchiveFileCatalogue::getExpectedNbArchiveRoutes(rdbms::Conn &conn, + const catalogue::StorageClass &storageClass) const { + try { + const char *const sql = + "SELECT " + "COUNT(*) AS NB_ROUTES " + "FROM " + "ARCHIVE_ROUTE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClass.storageClassName); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set of SELECT COUNT(*) is empty"); + } + return rset.columnUint64("NB_ROUTES"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveFileCatalogue::modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string& newStorageClassName) const { + try { + auto conn = m_connPool->getConn(); + if(!RdbmsCatalogueUtils::storageClassExists(conn, newStorageClassName)) { + exception::UserError ue; + ue.getMessage() << "Cannot modify archive file " << ": " << archiveFileId << " because storage class " + << ":" << newStorageClassName << " does not exist"; + throw ue; + } + + const char *const sql = + "UPDATE ARCHIVE_FILE " + "SET STORAGE_CLASS_ID = (" + "SELECT STORAGE_CLASS_ID FROM STORAGE_CLASS WHERE STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME " + ") " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", newStorageClassName); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + auto rset = stmt.executeQuery(); + + } catch(exception::UserError &ue) { + throw ue; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + } +} + +void RdbmsArchiveFileCatalogue::modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const { + const char *const sql = + "UPDATE ARCHIVE_FILE SET " + "DISK_FILE_ID = :FXID," + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":FXID", fxId); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveId); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.executeNonQuery(); +} + +//------------------------------------------------------------------------------ +// moveArchiveFileToRecycleBin +//------------------------------------------------------------------------------ +void RdbmsArchiveFileCatalogue::moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) { + if(!request.archiveFile){ + //The archive file does not exist in the catalogue, nothing to do with it + return; + } + cta::common::dataStructures::ArchiveFile archiveFile = request.archiveFile.value(); + utils::Timer t, totalTime; + log::TimingList tl; + try { + checkDeleteRequestConsistency(request,archiveFile); + tl.insertAndReset("checkDeleteRequestConsistency",t); + } catch(const cta::exception::Exception & ex){ + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(request.archiveFileID)) + .add("diskInstance", archiveFile.diskInstance) + .add("requestDiskInstance", request.diskInstance) + .add("diskFileId", archiveFile.diskFileId) + .add("diskFileInfo.owner_uid", archiveFile.diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile.diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile.fileSize)) + .add("creationTime", std::to_string(archiveFile.creationTime)) + .add("reconciliationTime", std::to_string(archiveFile.reconciliationTime)) + .add("diskFilePath",request.diskFilePath) + .add("errorMessage",ex.getMessageValue()) + .add("storageClass", archiveFile.storageClass); + archiveFile.checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile.tapeFiles.begin(); it!=archiveFile.tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize; + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::WARNING, "Failed to move archive file to the file-recycle-log."); + + exception::UserError ue; + ue.getMessage() << "Failed to move archive file with ID " << request.archiveFileID + << " to the file-recycle-log. errorMessage=" << ex.getMessageValue(); + throw ue; + } + + try { + //All checks are good, we can move the file to the recycle-bin + auto conn = m_connPool->getConn(); + rdbms::AutoRollback autoRollback(conn); + copyArchiveFileToFileRecyleLogAndDelete(conn,request,lc); + tl.insertAndReset("copyArchiveFileToFileRecyleLogAndDeleteTime",t); + tl.insertAndReset("totalTime",totalTime); + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(request.archiveFileID)) + .add("diskInstance", archiveFile.diskInstance) + .add("requestDiskInstance", request.diskInstance) + .add("diskFileId", archiveFile.diskFileId) + .add("diskFileInfo.owner_uid", archiveFile.diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile.diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile.fileSize)) + .add("creationTime", std::to_string(archiveFile.creationTime)) + .add("reconciliationTime", std::to_string(archiveFile.reconciliationTime)) + .add("storageClass", archiveFile.storageClass); + archiveFile.checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile.tapeFiles.begin(); it!=archiveFile.tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize; + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + tl.addToLog(spc); + lc.log(log::INFO, "In RdbmsCatalogue::moveArchiveFileToRecycleLog(): ArchiveFile moved to the file-recycle-log."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveFileCatalogue::checkDeleteRequestConsistency( + const cta::common::dataStructures::DeleteArchiveRequest deleteRequest, + const cta::common::dataStructures::ArchiveFile& archiveFile) const { + if(deleteRequest.diskInstance != archiveFile.diskInstance){ + std::ostringstream msg; + msg << "Failed to move archive file with ID " << deleteRequest.archiveFileID + << " to the recycle-bin because the disk instance of " + "the request does not match that of the archived file: archiveFileId=" << archiveFile.archiveFileID + << " requestDiskInstance=" << deleteRequest.diskInstance << " archiveFileDiskInstance=" << + archiveFile.diskInstance; + throw cta::exception::Exception(msg.str()); + } + if(deleteRequest.diskFilePath.empty()){ + std::ostringstream msg; + msg << "Failed to move archive file with ID " << deleteRequest.archiveFileID + << " to the recycle-bin because the disk file path has not been provided."; + throw cta::exception::Exception(msg.str()); + } +} + +void RdbmsArchiveFileCatalogue::deleteArchiveFile(rdbms::Conn& conn, + const common::dataStructures::DeleteArchiveRequest& request) { + try{ + const char *const deleteArchiveFileSql = + "DELETE FROM " + "ARCHIVE_FILE " + "WHERE ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + + auto deleteArchiveFileStmt = conn.createStmt(deleteArchiveFileSql); + deleteArchiveFileStmt.bindUint64(":ARCHIVE_FILE_ID",request.archiveFileID); + deleteArchiveFileStmt.executeNonQuery(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveFileCatalogue::insertArchiveFile(rdbms::Conn &conn, const ArchiveFileRowWithoutTimestamps &row) const { + try { + if(!RdbmsCatalogueUtils::storageClassExists(conn, row.storageClassName)) { + throw exception::UserError(std::string("Storage class ") + row.diskInstance + ":" + row.storageClassName + + " does not exist"); + } + + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO ARCHIVE_FILE(" + "ARCHIVE_FILE_ID," + "DISK_INSTANCE_NAME," + "DISK_FILE_ID," + "DISK_FILE_UID," + "DISK_FILE_GID," + "SIZE_IN_BYTES," + "CHECKSUM_BLOB," + "CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + "CREATION_TIME," + "RECONCILIATION_TIME)" + "SELECT " + ":ARCHIVE_FILE_ID," + ":DISK_INSTANCE_NAME," + ":DISK_FILE_ID," + ":DISK_FILE_UID," + ":DISK_FILE_GID," + ":SIZE_IN_BYTES," + ":CHECKSUM_BLOB," + ":CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + ":CREATION_TIME," + ":RECONCILIATION_TIME " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + + stmt.bindUint64(":ARCHIVE_FILE_ID", row.archiveFileId); + stmt.bindString(":DISK_INSTANCE_NAME", row.diskInstance); + stmt.bindString(":DISK_FILE_ID", row.diskFileId); + stmt.bindUint64(":DISK_FILE_UID", row.diskFileOwnerUid); + stmt.bindUint64(":DISK_FILE_GID", row.diskFileGid); + stmt.bindUint64(":SIZE_IN_BYTES", row.size); + stmt.bindBlob (":CHECKSUM_BLOB", row.checksumBlob.serialize()); + // Keep transition ADLER32 checksum up-to-date if it exists + uint32_t adler32; + try { + std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(row.checksumBlob.at(checksum::ADLER32)); + adler32 = strtoul(adler32hex.c_str(), 0, 16); + } catch(exception::ChecksumTypeMismatch &ex) { + adler32 = 0; + } + stmt.bindUint64(":CHECKSUM_ADLER32", adler32); + stmt.bindString(":STORAGE_CLASS_NAME", row.storageClassName); + stmt.bindUint64(":CREATION_TIME", now); + stmt.bindUint64(":RECONCILIATION_TIME", now); + + stmt.executeNonQuery(); + } catch (exception::UserError &) { + throw; + } catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: archiveFileId=" + std::to_string(row.archiveFileId) + + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getArchiveFileRowByArchiveId +//------------------------------------------------------------------------------ +std::unique_ptr<ArchiveFileRow> RdbmsArchiveFileCatalogue::getArchiveFileRowById(rdbms::Conn &conn, + const uint64_t id) const { + try { + const char *const sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID, " + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID, " + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID, " + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID, " + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES, " + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB, " + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32, " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME, " + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME, " + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", id); + auto rset = stmt.executeQuery(); + + std::unique_ptr<ArchiveFileRow> row; + if (rset.next()) { + row = std::make_unique<ArchiveFileRow>(); + + row->archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + row->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + row->diskFileId = rset.columnString("DISK_FILE_ID"); + row->diskFileOwnerUid = rset.columnUint64("DISK_FILE_UID"); + row->diskFileGid = rset.columnUint64("DISK_FILE_GID"); + row->size = rset.columnUint64("SIZE_IN_BYTES"); + row->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + row->storageClassName = rset.columnString("STORAGE_CLASS_NAME"); + row->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + row->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); + } + + return row; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +//------------------------------------------------------------------------------ +// updateDiskFileId +//------------------------------------------------------------------------------ +void RdbmsArchiveFileCatalogue::updateDiskFileId(const uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) { + try { + const char *const sql = + "UPDATE ARCHIVE_FILE SET " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME, " + "DISK_FILE_ID = :DISK_FILE_ID " + "WHERE " + "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_FILE_ID", diskFileId); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + std::ostringstream msg; + msg << "Cannot update the disk file ID of the archive file with archive file ID " << archiveFileId << + " because the archive file does not exist"; + throw exception::UserError(msg.str()); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getArchiveFileToRetrieveByArchiveFileId +//------------------------------------------------------------------------------ +std::unique_ptr<common::dataStructures::ArchiveFile> RdbmsArchiveFileCatalogue::getArchiveFileToRetrieveByArchiveFileId( + rdbms::Conn &conn, const uint64_t archiveFileId) const { + try { + const char *const sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "INNER JOIN TAPE ON " + "TAPE_FILE.VID = TAPE.VID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID AND " + "TAPE.TAPE_STATE IN ('ACTIVE', 'DISABLED') " + "ORDER BY " + "TAPE_FILE.CREATION_TIME ASC"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + auto rset = stmt.executeQuery(); + std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; + while (rset.next()) { + if(nullptr == archiveFile.get()) { + archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); + + archiveFile->archiveFileID = rset.columnUint64("ARCHIVE_FILE_ID"); + archiveFile->diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + archiveFile->diskFileId = rset.columnString("DISK_FILE_ID"); + archiveFile->diskFileInfo.owner_uid = rset.columnUint64("DISK_FILE_UID"); + archiveFile->diskFileInfo.gid = rset.columnUint64("DISK_FILE_GID"); + archiveFile->fileSize = rset.columnUint64("SIZE_IN_BYTES"); + archiveFile->checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + archiveFile->storageClass = rset.columnString("STORAGE_CLASS_NAME"); + archiveFile->creationTime = rset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + archiveFile->reconciliationTime = rset.columnUint64("RECONCILIATION_TIME"); + } + + // If there is a tape file we add it to the archiveFile's list of tape files + if(!rset.columnIsNull("VID")) { + // Add the tape file to the archive file's in-memory structure + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = rset.columnString("VID"); + tapeFile.fSeq = rset.columnUint64("FSEQ"); + tapeFile.blockId = rset.columnUint64("BLOCK_ID"); + tapeFile.fileSize = rset.columnUint64("LOGICAL_SIZE_IN_BYTES"); + tapeFile.copyNb = rset.columnUint64("COPY_NB"); + tapeFile.creationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience + + archiveFile->tapeFiles.push_back(tapeFile); + } + } + + //If there are no tape files that belong to the archive file, then return a nullptr. + if(archiveFile.get() != nullptr && archiveFile->tapeFiles.empty()){ + archiveFile.reset(nullptr); + } + + return archiveFile; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getArchiveFileToRetrieveByArchiveFileId +//------------------------------------------------------------------------------ +const std::list<std::pair<std::string, std::string>> RdbmsArchiveFileCatalogue::getTapeFileStateListForArchiveFileId( + rdbms::Conn &conn, const uint64_t archiveFileId) const { + try { + const char *const sql = + "SELECT " + "TAPE_FILE.VID AS VID," + "TAPE.TAPE_STATE AS STATE " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "INNER JOIN TAPE ON " + "TAPE_FILE.VID = TAPE.VID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID "; + + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + auto rset = stmt.executeQuery(); + std::list<std::pair<std::string, std::string>> ret; + while (rset.next()) { + const auto &vid = rset.columnString("VID"); + const auto &state = rset.columnString("STATE"); + ret.push_back(std::pair<std::string, std::string>(vid, state)); + } + return ret; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp b/catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..35bf9470f3 --- /dev/null +++ b/catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp @@ -0,0 +1,334 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/ArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" +#include "catalogue/TimeBasedCache.hpp" +#include "common/dataStructures/TapeCopyToPoolMap.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct DeleteArchiveRequest; +struct MountPolicy; +struct RequesterIdentity; +} +} + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +struct ArchiveFileRowWithoutTimestamps; +struct ArchiveFileRow; + +class RdbmsCatalogue; + +template <typename Value> +class ValueAndTimeBasedCacheInfo; + +struct User; +struct Group; + +class RdbmsArchiveFileCatalogue : public ArchiveFileCatalogue { +public: + ~RdbmsArchiveFileCatalogue() override = default; + + uint64_t checkAndGetNextArchiveFileId(const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) override; + + common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override; + + ArchiveFileItor getArchiveFilesItor( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, + const uint64_t maxNbFiles) const override; + + ArchiveFileItor getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const override; + + common::dataStructures::ArchiveFileSummary getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override; + + void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string& newStorageClassName) const override; + + void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const override; + + void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) override; + + void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) override; + +protected: + RdbmsArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + /** + * Returns a unique archive ID that can be used by a new archive file 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 archive ID that can be used by a new archive file within + * the catalogue. + */ + virtual uint64_t getNextArchiveFileId(rdbms::Conn &conn) = 0; + + friend class OracleFileRecycleLogCatalogue; + friend class PostgresFileRecycleLogCatalogue; + friend class SqliteFileRecycleLogCatalogue; + /** + * Returns the archive file with the specified unique identifier or nullptr if + * it does not exist. + * + * Please note that an archive file with no associated tape files is + * considered not to exist by this method. + * + * @param conn The database connection. + * @param id The unique identifier of the archive file. + * @return The archive file. + */ + std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileById(rdbms::Conn &conn, + const uint64_t archiveFileId) const; + + /** + * Copy the archiveFile and the associated tape files from the ARCHIVE_FILE and TAPE_FILE tables to the FILE_RECYCLE_LOG table + * and deletes the ARCHIVE_FILE and TAPE_FILE entries. + * @param conn the database connection + * @param request the request that contains the necessary informations to identify the archiveFile to copy to the FILE_RECYCLE_LOG table + * @param lc the log context + */ + virtual void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) = 0; + + void deleteArchiveFile(rdbms::Conn& conn, const common::dataStructures::DeleteArchiveRequest& request); + +protected: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + +private: + + /** + * Cached versions of tape copy to tape tape pool mappings for specific + * storage classes. + */ + mutable TimeBasedCache<catalogue::StorageClass, common::dataStructures::TapeCopyToPoolMap> m_tapeCopyToPoolCache; + + /** + * Cached versions of the expected number of archive routes for specific + * storage classes as specified by the call to the createStorageClass() + * method as opposed to the actual number entered so far using the + * createArchiveRoute() method. + */ + mutable TimeBasedCache<catalogue::StorageClass, uint64_t> m_expectedNbArchiveRoutesCache; + + /** + * Returns a cached version of the mapping from tape copy to tape pool for the + * specified storage class. + * + * This method updates the cache when necessary. + * + * @param storageClass The fully qualified storage class, in other words the + * name of the disk instance and the name of the storage class. + * @return The mapping from tape copy to tape pool for the specified storage + * class. + */ + common::dataStructures::TapeCopyToPoolMap getCachedTapeCopyToPoolMap( + const catalogue::StorageClass &storageClass) const; + + /** + * Returns a cached version of the expected number of archive routes for the + * specified storage class as specified by the call to the + * createStorageClass() method as opposed to the actual number entered so far + * using the createArchiveRoute() method. + * + * This method updates the cache when necessary. + * + * @param storageClass The fully qualified storage class, in other words the + * name of the disk instance and the name of the storage class. + * @return The expected number of archive routes. + */ + uint64_t getCachedExpectedNbArchiveRoutes(const catalogue::StorageClass &storageClass) const; + + /** + * Returns a cached version of the specified requester mount-policy or std::nullopt + * if one does not exist. + * + * @param user The fully qualified user, in other words the name of the disk + * instance and the name of the group. + * @return The mount policy or std::nullopt if one does not exists. + * @throw UserErrorWithTimeBasedCacheInfo if there was a user error. + */ + ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy> > getCachedRequesterMountPolicy( + const User &user) const; + + /** + * Returns a cached version of the specified requester-group mount-policy or + * nullptr if one does not exist. + * + * This method updates the cache when necessary. + * + * @param group The fully qualified group, in other words the name of the disk + * instance and the name of the group. + * @return The cached mount policy or std::nullopt if one does not exists. + */ + ValueAndTimeBasedCacheInfo<std::optional<common::dataStructures::MountPolicy> > getCachedRequesterGroupMountPolicy( + const Group &group) const; + + /** + * Throws a UserError exception if the specified searchCriteria is not valid + * due to a user error. + * + * @param searchCriteria The search criteria. + */ + void checkTapeFileSearchCriteria(const TapeFileSearchCriteria &searchCriteria) const; + + /** + * 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 checkTapeFileSearchCriteria(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const; + + /** + * Returns an iterator across the files on the specified tape ordered by + * FSEQ. + * + * @param vid The volume identifier of the tape. + * @return The iterator. + */ + ArchiveFileItor getTapeContentsItor(const std::string &vid) const; + + /** + * Returns the specified archive files. Please note that the list of files + * is ordered by archive file ID. + * + * @param conn The database connection. + * @param searchCriteria The search criteria. + * @return The archive files. + */ + ArchiveFileItor getArchiveFilesItor(rdbms::Conn &conn, const TapeFileSearchCriteria &searchCriteria) const; + + /** + * Returns the mapping from tape copy to tape pool for the specified storage + * class. + * + * @param conn The database connection. + * @param storageClass The fully qualified storage class, in other words the + * name of the disk instance and the name of the storage class. + * @return The mapping from tape copy to tape pool for the specified storage + * class. + */ + common::dataStructures::TapeCopyToPoolMap getTapeCopyToPoolMap(rdbms::Conn &conn, + const catalogue::StorageClass &storageClass) const; + + /** + * Returns the expected number of archive routes for the specified storage + * class as specified by the call to the createStorageClass() method as + * opposed to the actual number entered so far using the createArchiveRoute() + * method. + * + * @param conn The database connection. + * @param storageClass The fully qualified storage class, in other words the + * name of the disk instance and the name of the storage class. + * @return The expected number of archive routes. + */ + uint64_t getExpectedNbArchiveRoutes(rdbms::Conn &conn, const catalogue::StorageClass &storageClass) const; + + /** + * Throws an exception if the delete request passed in parameter is not consistent + * to allow a deletion of the ArchiveFile from the Catalogue. + * @param deleteRequest, the deleteRequest to check the consistency. + * @param archiveFile the ArchiveFile to delete to check the deleteRequest consistency against. + */ + void checkDeleteRequestConsistency(const cta::common::dataStructures::DeleteArchiveRequest deleteRequest, + const cta::common::dataStructures::ArchiveFile & archiveFile) const; + + friend class RdbmsFileRecycleLogCatalogue; + friend class SqliteTapeFileCatalogue; + + /** + * An RdbmsCatalogue specific method that inserts the specified row into the + * ArchiveFile table. + * + * @param conn The database connection. + * @param row The row to be inserted. + */ + void insertArchiveFile(rdbms::Conn &conn, const ArchiveFileRowWithoutTimestamps &row) const; + + /** + * Returns the specified archive file row. A nullptr pointer is returned if + * there is no corresponding row in the ARCHIVE_FILE table. + * + * @param conn The database connection. + * @param id The identifier of the archive file. + * @return The archive file row or nullptr. + */ + std::unique_ptr<ArchiveFileRow> getArchiveFileRowById(rdbms::Conn &conn, const uint64_t id) const; + + friend class RdbmsTapeFileCatalogue; + /** + * Returns the specified archive file. A nullptr pointer is returned if + * there are no corresponding rows in the TAPE_FILE table. Only looks at TAPE_FILE entries + * on Tapes with state 'ACTIVE' + * + * @param conn The database connection. + * @param archiveFileId The identifier of the archive file. + * @return The archive file or nullptr. + */ + std::unique_ptr<common::dataStructures::ArchiveFile> getArchiveFileToRetrieveByArchiveFileId(rdbms::Conn &conn, + const uint64_t archiveFileId) const; + + /** + * Returns the specified archive file. A nullptr pointer is returned if + * there are no corresponding rows in the TAPE_FILE table. + * + * @param conn The database connection. + * @param archiveFileId The identifier of the archive file. + * @return A list of tape file vid and corresponding tape state pairs + */ + const std::list<std::pair<std::string, std::string>> getTapeFileStateListForArchiveFileId(rdbms::Conn &conn, + const uint64_t archiveFileId) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsArchiveRouteCatalogue.cpp b/catalogue/rdbms/RdbmsArchiveRouteCatalogue.cpp new file mode 100644 index 0000000000..46cc5fae2f --- /dev/null +++ b/catalogue/rdbms/RdbmsArchiveRouteCatalogue.cpp @@ -0,0 +1,411 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp" +#include "catalogue/interfaces/StorageClassCatalogue.hpp" +#include "catalogue/interfaces/TapePoolCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/Logger.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + + +RdbmsArchiveRouteCatalogue::RdbmsArchiveRouteCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool): + m_log(log), m_connPool(connPool) {} + +void RdbmsArchiveRouteCatalogue::createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName, + const std::string &comment) { + try { + if(storageClassName.empty()) { + throw UserSpecifiedAnEmptyStringStorageClassName("Cannot create archive route because storage class name is an" + " empty string"); + } + if(0 == copyNb) { + throw UserSpecifiedAZeroCopyNb("Cannot create archive route because copy number is zero"); + } + if(tapePoolName.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create archive route because tape pool name is an empty" + " string"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create archive route because comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::archiveRouteExists(conn, storageClassName, copyNb)) { + exception::UserError ue; + ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb + << "->" << tapePoolName << " because it already exists"; + throw ue; + } + { + const auto routes = getArchiveRoutes(conn, storageClassName, tapePoolName); + if(!routes.empty()) { + exception::UserError ue; + ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb + << "->" << tapePoolName << " because a route already exists for this storage class and tape pool"; + throw ue; + } + } + if(!RdbmsCatalogueUtils::storageClassExists(conn, storageClassName)) { + exception::UserError ue; + ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb + << "->" << tapePoolName << " because storage class " << ":" << storageClassName << + " does not exist"; + throw ue; + } + if(!RdbmsCatalogueUtils::tapePoolExists(conn, tapePoolName)) { + exception::UserError ue; + ue.getMessage() << "Cannot create archive route " << ": " << storageClassName << "," << copyNb + << "->" << tapePoolName << " because tape pool " << tapePoolName + " does not exist"; + throw ue; + } + + const char *const sql = + "INSERT INTO ARCHIVE_ROUTE(" + "STORAGE_CLASS_ID," + "COPY_NB," + "TAPE_POOL_ID," + + "USER_COMMENT," + + "CREATION_LOG_USER_NAME," + "CREATION_LOG_HOST_NAME," + "CREATION_LOG_TIME," + + "LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME)" + "SELECT " + "STORAGE_CLASS_ID," + ":COPY_NB," + "(SELECT TAPE_POOL_ID FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME) AS TAPE_POOL_ID," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindUint64(":COPY_NB", copyNb); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveRouteCatalogue::deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) { + try { + const char *const sql = + "DELETE FROM " + "ARCHIVE_ROUTE " + "WHERE " + "STORAGE_CLASS_ID = (" + "SELECT " + "STORAGE_CLASS_ID " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " + "COPY_NB = :COPY_NB"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindUint64(":COPY_NB", copyNb); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + exception::UserError ue; + ue.getMessage() << "Cannot delete archive route for storage-class " << ":" + storageClassName + + " and copy number " << copyNb << " because it does not exist"; + throw ue; + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::ArchiveRoute> RdbmsArchiveRouteCatalogue::getArchiveRoutes() const { + try { + std::list<common::dataStructures::ArchiveRoute> routes; + const char *const sql = + "SELECT " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_ROUTE.COPY_NB AS COPY_NB," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + + "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT," + + "ARCHIVE_ROUTE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "ARCHIVE_ROUTE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "ARCHIVE_ROUTE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "ARCHIVE_ROUTE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "ARCHIVE_ROUTE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "ARCHIVE_ROUTE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "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 " + "ORDER BY " + "STORAGE_CLASS_NAME, COPY_NB"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::ArchiveRoute route; + + route.storageClassName = rset.columnString("STORAGE_CLASS_NAME"); + route.copyNb = rset.columnUint64("COPY_NB"); + route.tapePoolName = rset.columnString("TAPE_POOL_NAME"); + route.comment = rset.columnString("USER_COMMENT"); + route.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + route.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + route.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + route.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + route.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + route.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + routes.push_back(route); + } + + return routes; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::ArchiveRoute> RdbmsArchiveRouteCatalogue::getArchiveRoutes( + const std::string &storageClassName, const std::string &tapePoolName) const { + try { + auto conn = m_connPool->getConn(); + return getArchiveRoutes(conn, storageClassName, tapePoolName); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::ArchiveRoute> RdbmsArchiveRouteCatalogue::getArchiveRoutes(rdbms::Conn &conn, + const std::string &storageClassName, const std::string &tapePoolName) const { + try { + std::list<common::dataStructures::ArchiveRoute> routes; + const char *const sql = + "SELECT " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME, " + "ARCHIVE_ROUTE.COPY_NB AS COPY_NB, " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME, " + + "ARCHIVE_ROUTE.USER_COMMENT AS USER_COMMENT, " + + "ARCHIVE_ROUTE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME, " + "ARCHIVE_ROUTE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME, " + "ARCHIVE_ROUTE.CREATION_LOG_TIME AS CREATION_LOG_TIME, " + + "ARCHIVE_ROUTE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME, " + "ARCHIVE_ROUTE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME, " + "ARCHIVE_ROUTE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "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.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND " + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME " + "ORDER BY " + "STORAGE_CLASS_NAME, COPY_NB"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::ArchiveRoute route; + + route.storageClassName = rset.columnString("STORAGE_CLASS_NAME"); + route.copyNb = rset.columnUint64("COPY_NB"); + route.tapePoolName = rset.columnString("TAPE_POOL_NAME"); + route.comment = rset.columnString("USER_COMMENT"); + route.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + route.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + route.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + route.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + route.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + route.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + routes.push_back(route); + } + + return routes; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveRouteCatalogue::modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE ARCHIVE_ROUTE SET " + "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 " + "WHERE " + "STORAGE_CLASS_ID = (" + "SELECT " + "STORAGE_CLASS_ID " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " + "COPY_NB = :COPY_NB"; + auto conn = m_connPool->getConn(); + + if(!RdbmsCatalogueUtils::archiveRouteExists(conn, storageClassName, copyNb)) { + throw UserSpecifiedANonExistentArchiveRoute("Archive route does not exist"); + } + + if(!RdbmsCatalogueUtils::tapePoolExists(conn, tapePoolName)) { + throw UserSpecifiedANonExistentTapePool("Tape pool does not exist"); + } + + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindUint64(":COPY_NB", copyNb); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentArchiveRoute("Archive route does not exist"); + } + } catch(exception::UserError &ue) { + std::ostringstream msg; + msg << "Cannot modify tape pool of archive route: storageClassName=" << storageClassName << " copyNb=" << copyNb << + " tapePoolName=" << tapePoolName << ": " << ue.getMessage().str(); + ue.getMessage().str(msg.str()); + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsArchiveRouteCatalogue::modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE ARCHIVE_ROUTE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "STORAGE_CLASS_ID = (" + "SELECT " + "STORAGE_CLASS_ID " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME) AND " + "COPY_NB = :COPY_NB"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindUint64(":COPY_NB", copyNb); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + exception::UserError ue; + ue.getMessage() << "Cannot modify archive route for storage-class " << ":" + storageClassName + + " and copy number " << copyNb << " because it does not exist"; + throw ue; + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +} // namespace catalogue +} // namespace cta + diff --git a/catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp b/catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp new file mode 100644 index 0000000000..5fd1582253 --- /dev/null +++ b/catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp @@ -0,0 +1,77 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/ArchiveRouteCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsArchiveRouteCatalogue : public ArchiveRouteCatalogue { +public: + RdbmsArchiveRouteCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsArchiveRouteCatalogue() override = default; + + void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, + const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override; + + void deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &storageClassName, + const std::string &tapePoolName) const override; + + void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override; + + void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + + /** + * @return the archive routes of the given storage class and destination tape + * pool. + * + * Under normal circumstances this method should return either 0 or 1 route. + * For a given storage class there should be no more than one route to any + * given tape pool. + * + * @param conn The database connection. + * @param storageClassName The name of the storage class which is only + * guaranteed to be unique within its disk instance. + * @param tapePoolName The name of the tape pool. + */ + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(rdbms::Conn &conn, + const std::string &storageClassName, const std::string &tapePoolName) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsCatalogue.cpp b/catalogue/rdbms/RdbmsCatalogue.cpp new file mode 100644 index 0000000000..1e2e53c0e3 --- /dev/null +++ b/catalogue/rdbms/RdbmsCatalogue.cpp @@ -0,0 +1,164 @@ + /* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/rdbms/RdbmsAdminUserCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveRouteCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp" +#include "catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp" +#include "catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp" +#include "catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp" +#include "catalogue/rdbms/RdbmsDriveStateCatalogue.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp" +#include "catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp" +#include "catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp" +#include "catalogue/rdbms/RdbmsSchemaCatalogue.hpp" +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" + +namespace cta { +namespace catalogue { + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +RdbmsCatalogue::RdbmsCatalogue( + log::Logger &log, + const rdbms::Login &login, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns): + m_log(log), + m_connPool(std::make_shared<rdbms::ConnPool>(login, nbConns)), + m_archiveFileListingConnPool(std::make_shared<rdbms::ConnPool>(login, nbArchiveFileListingConns)), + m_groupMountPolicyCache(10), + m_userMountPolicyCache(10), + m_allMountPoliciesCache(60), + m_tapepoolVirtualOrganizationCache(60), + m_schema(std::make_unique<RdbmsSchemaCatalogue>(m_log, m_connPool)), + m_adminUser(std::make_unique<RdbmsAdminUserCatalogue>(m_log, m_connPool)), + m_diskSystem(std::make_unique<RdbmsDiskSystemCatalogue>(m_log, m_connPool)), + m_diskInstance(std::make_unique<RdbmsDiskInstanceCatalogue>(m_log, m_connPool)), + m_diskInstanceSpace(std::make_unique<RdbmsDiskInstanceSpaceCatalogue>(m_log, m_connPool)), + m_archiveRoute(std::make_unique<RdbmsArchiveRouteCatalogue>(m_log, m_connPool)), + m_mountPolicy(std::make_unique<RdbmsMountPolicyCatalogue>(m_log, m_connPool, this)), + m_requesterActivityMountRule(std::make_unique<RdbmsRequesterActivityMountRuleCatalogue>(m_log, m_connPool, this)), + m_requesterMountRule(std::make_unique<RdbmsRequesterMountRuleCatalogue>(m_log, m_connPool, this)), + m_requesterGroupMountRule(std::make_unique<RdbmsRequesterGroupMountRuleCatalogue>(m_log, m_connPool, this)), + m_driveConfig(std::make_unique<RdbmsDriveConfigCatalogue>(m_log, m_connPool)), + m_driveState(std::make_unique<RdbmsDriveStateCatalogue>(m_log, m_connPool)) { +} + +const std::unique_ptr<SchemaCatalogue>& RdbmsCatalogue::Schema() { + return m_schema; +} + +const std::unique_ptr<AdminUserCatalogue>& RdbmsCatalogue::AdminUser() { + return m_adminUser; +} + +const std::unique_ptr<DiskSystemCatalogue>& RdbmsCatalogue::DiskSystem() { + return m_diskSystem; +} + +const std::unique_ptr<DiskInstanceCatalogue>& RdbmsCatalogue::DiskInstance() { + return m_diskInstance; +} + +const std::unique_ptr<DiskInstanceSpaceCatalogue>& RdbmsCatalogue::DiskInstanceSpace() { + return m_diskInstanceSpace; +} + +const std::unique_ptr<VirtualOrganizationCatalogue>& RdbmsCatalogue::VO() { + return m_vo; +} + +const std::unique_ptr<ArchiveRouteCatalogue>& RdbmsCatalogue::ArchiveRoute() { + return m_archiveRoute; +} + +const std::unique_ptr<MediaTypeCatalogue>& RdbmsCatalogue::MediaType() { + return m_mediaType; +} + +const std::unique_ptr<StorageClassCatalogue>& RdbmsCatalogue::StorageClass() { + return m_storageClass; +} + +const std::unique_ptr<TapePoolCatalogue>& RdbmsCatalogue::TapePool() { + return m_tapePool; +} + +const std::unique_ptr<TapeCatalogue>& RdbmsCatalogue::Tape() { + return m_tape; +} + +const std::unique_ptr<MountPolicyCatalogue>& RdbmsCatalogue::MountPolicy() { + return m_mountPolicy; +} + +const std::unique_ptr<RequesterActivityMountRuleCatalogue>& RdbmsCatalogue::RequesterActivityMountRule() { + return m_requesterActivityMountRule; +} + +const std::unique_ptr<RequesterMountRuleCatalogue>& RdbmsCatalogue::RequesterMountRule() { + return m_requesterMountRule; +} + +const std::unique_ptr<RequesterGroupMountRuleCatalogue>& RdbmsCatalogue::RequesterGroupMountRule() { + return m_requesterGroupMountRule; +} + +const std::unique_ptr<LogicalLibraryCatalogue>& RdbmsCatalogue::LogicalLibrary() { + return m_logicalLibrary; +} + +const std::unique_ptr<TapeFileCatalogue>& RdbmsCatalogue::TapeFile() { + return m_tapeFile; +} + +const std::unique_ptr<FileRecycleLogCatalogue>& RdbmsCatalogue::FileRecycleLog() { + return m_fileRecycleLog; +} + +const std::unique_ptr<DriveConfigCatalogue>& RdbmsCatalogue::DriveConfig() { + return m_driveConfig; +} + +const std::unique_ptr<ArchiveFileCatalogue>& RdbmsCatalogue::ArchiveFile() { + return m_archiveFile; +} + +const std::unique_ptr<DriveStateCatalogue>& RdbmsCatalogue::DriveState() { + return m_driveState; +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsCatalogue.hpp b/catalogue/rdbms/RdbmsCatalogue.hpp new file mode 100644 index 0000000000..5a98a16007 --- /dev/null +++ b/catalogue/rdbms/RdbmsCatalogue.hpp @@ -0,0 +1,182 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/Group.hpp" +#include "catalogue/TimeBasedCache.hpp" +#include "catalogue/User.hpp" +#include "common/threading/Mutex.hpp" +#include "common/log/Logger.hpp" + +#include "common/dataStructures/MountPolicy.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" + +namespace cta { + +namespace rdbms { +class Login; +class Conn; +class ConnPool; +} + +namespace catalogue { +/** + * CTA catalogue implemented using a relational database backend. + */ +class RdbmsCatalogue: public Catalogue { +protected: + /** + * Protected constructor only to be called by sub-classes. + * + * @param log Object representing the API to the CTA logging system. + * @param login The database login details to be used to create new + * connections. + * @param nbConns The maximum number of concurrent connections to the + * underlying relational database for all operations accept listing archive + * files which can be relatively long operations. + * @param nbArchiveFileListingConns The maximum number of concurrent + * connections to the underlying relational database for the sole purpose of + * listing archive files. + */ + RdbmsCatalogue( + log::Logger &log, + const rdbms::Login &login, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns); + +public: + ~RdbmsCatalogue() override = default; + + const std::unique_ptr<SchemaCatalogue>& Schema() override; + const std::unique_ptr<AdminUserCatalogue>& AdminUser() override; + const std::unique_ptr<DiskSystemCatalogue>& DiskSystem() override; + const std::unique_ptr<DiskInstanceCatalogue>& DiskInstance() override; + const std::unique_ptr<DiskInstanceSpaceCatalogue>& DiskInstanceSpace() override; + const std::unique_ptr<VirtualOrganizationCatalogue>& VO() override; + const std::unique_ptr<ArchiveRouteCatalogue>& ArchiveRoute() override; + const std::unique_ptr<MediaTypeCatalogue>& MediaType() override; + const std::unique_ptr<StorageClassCatalogue>& StorageClass() override; + const std::unique_ptr<TapePoolCatalogue>& TapePool() override; + const std::unique_ptr<TapeCatalogue>& Tape() override; + const std::unique_ptr<MountPolicyCatalogue>& MountPolicy() override; + const std::unique_ptr<RequesterActivityMountRuleCatalogue>& RequesterActivityMountRule() override; + const std::unique_ptr<RequesterMountRuleCatalogue>& RequesterMountRule() override; + const std::unique_ptr<RequesterGroupMountRuleCatalogue>& RequesterGroupMountRule() override; + const std::unique_ptr<LogicalLibraryCatalogue>& LogicalLibrary() override; + const std::unique_ptr<TapeFileCatalogue>& TapeFile() override; + const std::unique_ptr<FileRecycleLogCatalogue>& FileRecycleLog() override; + const std::unique_ptr<DriveConfigCatalogue>& DriveConfig() override; + const std::unique_ptr<DriveStateCatalogue>& DriveState() override; + const std::unique_ptr<ArchiveFileCatalogue>& ArchiveFile() override; + +protected: + friend class RdbmsFileRecycleLogCatalogue; + friend class RdbmsTapeCatalogue; + friend class RdbmsArchiveFileCatalogue; + friend class OracleTapeFileCatalogue; + friend class SqliteTapeFileCatalogue; + /** + * Object representing the API to the CTA logging system. + */ + log::Logger &m_log; + + /** + * Mutex to be used to a take a global lock on the database. + */ + threading::Mutex m_mutex; + + /** + * The pool of connections to the underlying relational database to be used + * for all operations accept listing archive files which can be relatively + * long operations. + */ + mutable std::shared_ptr<rdbms::ConnPool> m_connPool; + + /** + * The pool of connections to the underlying relational database to be used + * for the sole purpose of listing archive files. + */ + mutable std::shared_ptr<rdbms::ConnPool> m_archiveFileListingConnPool; + + /** + * Creates a temporary table from the list of disk file IDs provided in the search criteria. + * + * @param conn The database connection. + * @param diskFileIds List of disk file IDs (fxid). + * @return Name of the temporary table + */ + virtual std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const = 0; + + friend class RdbmsMountPolicyCatalogue; + friend class RdbmsRequesterActivityMountRuleCatalogue; + friend class RdbmsRequesterMountRuleCatalogue; + friend class RdbmsRequesterGroupMountRuleCatalogue; + + /** + * Cached versions of mount policies for specific user groups. + */ + mutable TimeBasedCache<Group, std::optional<common::dataStructures::MountPolicy> > m_groupMountPolicyCache; + + /** + * Cached versions of mount policies for specific users. + */ + mutable TimeBasedCache<User, std::optional<common::dataStructures::MountPolicy> > m_userMountPolicyCache; + + /** + * Cached versions of all mount policies + */ + mutable TimeBasedCache<std::string, std::list<common::dataStructures::MountPolicy>> m_allMountPoliciesCache; + + friend class RdbmsVirtualOrganizationCatalogue; + friend class RdbmsTapePoolCatalogue; + /** + * Cached versions of virtual organization for specific tapepools + */ + mutable TimeBasedCache<std::string, common::dataStructures::VirtualOrganization> m_tapepoolVirtualOrganizationCache; + +protected: + std::unique_ptr<SchemaCatalogue> m_schema; + std::unique_ptr<AdminUserCatalogue> m_adminUser; + std::unique_ptr<DiskSystemCatalogue> m_diskSystem; + std::unique_ptr<DiskInstanceCatalogue> m_diskInstance; + std::unique_ptr<DiskInstanceSpaceCatalogue> m_diskInstanceSpace; + std::unique_ptr<VirtualOrganizationCatalogue> m_vo; + std::unique_ptr<ArchiveRouteCatalogue> m_archiveRoute; + std::unique_ptr<MediaTypeCatalogue> m_mediaType; + std::unique_ptr<StorageClassCatalogue> m_storageClass; + std::unique_ptr<TapePoolCatalogue> m_tapePool; + std::unique_ptr<TapeCatalogue> m_tape; + std::unique_ptr<MountPolicyCatalogue> m_mountPolicy; + std::unique_ptr<RequesterActivityMountRuleCatalogue> m_requesterActivityMountRule; + std::unique_ptr<RequesterMountRuleCatalogue> m_requesterMountRule; + std::unique_ptr<RequesterGroupMountRuleCatalogue> m_requesterGroupMountRule; + std::unique_ptr<LogicalLibraryCatalogue> m_logicalLibrary; + std::unique_ptr<DriveConfigCatalogue> m_driveConfig; + std::unique_ptr<DriveStateCatalogue> m_driveState; + std::unique_ptr<TapeFileCatalogue> m_tapeFile; + std::unique_ptr<FileRecycleLogCatalogue> m_fileRecycleLog; + std::unique_ptr<ArchiveFileCatalogue> m_archiveFile; +}; // class RdbmsCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp similarity index 99% rename from catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp rename to catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp index c944b44c4f..89c706cdf6 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp +++ b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.cpp @@ -16,7 +16,7 @@ */ #include "catalogue/CatalogueItor.hpp" -#include "catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp" #include "common/exception/Exception.hpp" #include "common/exception/LostDatabaseConnection.hpp" #include "common/exception/UserError.hpp" diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp similarity index 98% rename from catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp rename to catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp index b8d8f1b6c5..8ed84fc6d1 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp +++ b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesForRepackItor.hpp @@ -32,7 +32,7 @@ namespace catalogue { * RdbmsCatalogue::getArchiveFilesForRepack() implementation of * ArchiveFileItorImpl. */ -class RdbmsCatalogueGetArchiveFilesForRepackItor: public Catalogue::ArchiveFileItor::Impl { +class RdbmsCatalogueGetArchiveFilesForRepackItor: public catalogue::ArchiveFileItor::Impl { public: /** diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.cpp similarity index 99% rename from catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp rename to catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.cpp index be4c0bcb4f..82df93b706 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesItor.cpp +++ b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.cpp @@ -16,7 +16,7 @@ */ #include "catalogue/CatalogueItor.hpp" -#include "catalogue/RdbmsCatalogueGetArchiveFilesItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp" #include "common/exception/Exception.hpp" #include "common/exception/LostDatabaseConnection.hpp" #include "common/exception/UserError.hpp" diff --git a/catalogue/RdbmsCatalogueGetArchiveFilesItor.hpp b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp similarity index 98% rename from catalogue/RdbmsCatalogueGetArchiveFilesItor.hpp rename to catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp index 5d757b6865..10651a1dfd 100644 --- a/catalogue/RdbmsCatalogueGetArchiveFilesItor.hpp +++ b/catalogue/rdbms/RdbmsCatalogueGetArchiveFilesItor.hpp @@ -32,7 +32,7 @@ namespace catalogue { /** * RdbmsCatalogue::getArchiveFiles() implementation of ArchiveFileItorImpl. */ -class RdbmsCatalogueGetArchiveFilesItor: public Catalogue::ArchiveFileItor::Impl { +class RdbmsCatalogueGetArchiveFilesItor: public catalogue::ArchiveFileItor::Impl { public: /** diff --git a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp b/catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.cpp similarity index 99% rename from catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp rename to catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.cpp index 0a969372b5..c8170fba1c 100644 --- a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.cpp +++ b/catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.cpp @@ -16,7 +16,7 @@ */ #include "catalogue/CatalogueItor.hpp" -#include "catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp" #include "common/dataStructures/FileRecycleLog.hpp" #include "common/exception/UserError.hpp" #include "common/log/LogContext.hpp" diff --git a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp b/catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp similarity index 96% rename from catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp rename to catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp index 5bf51cd53e..df9dcb76aa 100644 --- a/catalogue/RdbmsCatalogueGetFileRecycleLogItor.hpp +++ b/catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp @@ -26,7 +26,7 @@ namespace cta { namespace catalogue { -class RdbmsCatalogueGetFileRecycleLogItor : public Catalogue::FileRecycleLogItor::Impl { +class RdbmsCatalogueGetFileRecycleLogItor : public FileRecycleLogItor::Impl { public: /** * Constructor. @@ -108,4 +108,4 @@ private: }; } // namespace catalogue -} // namespace cta \ No newline at end of file +} // namespace cta diff --git a/catalogue/RdbmsCatalogueTapeContentsItor.cpp b/catalogue/rdbms/RdbmsCatalogueTapeContentsItor.cpp similarity index 99% rename from catalogue/RdbmsCatalogueTapeContentsItor.cpp rename to catalogue/rdbms/RdbmsCatalogueTapeContentsItor.cpp index 9b90e56e59..dff694ad75 100644 --- a/catalogue/RdbmsCatalogueTapeContentsItor.cpp +++ b/catalogue/rdbms/RdbmsCatalogueTapeContentsItor.cpp @@ -16,7 +16,7 @@ */ #include "catalogue/CatalogueItor.hpp" -#include "catalogue/RdbmsCatalogueTapeContentsItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp" #include "common/exception/Exception.hpp" #include "common/exception/LostDatabaseConnection.hpp" #include "common/exception/UserError.hpp" diff --git a/catalogue/RdbmsCatalogueTapeContentsItor.hpp b/catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp similarity index 97% rename from catalogue/RdbmsCatalogueTapeContentsItor.hpp rename to catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp index e26494e3ba..bb89ab75c8 100644 --- a/catalogue/RdbmsCatalogueTapeContentsItor.hpp +++ b/catalogue/rdbms/RdbmsCatalogueTapeContentsItor.hpp @@ -32,7 +32,7 @@ namespace catalogue { /** * Iteratess across the tape files that make up the contents of a given tape. */ -class RdbmsCatalogueTapeContentsItor: public Catalogue::ArchiveFileItor::Impl { +class RdbmsCatalogueTapeContentsItor: public ArchiveFileItor::Impl { public: /** * Constructor. diff --git a/catalogue/rdbms/RdbmsCatalogueUtils.cpp b/catalogue/rdbms/RdbmsCatalogueUtils.cpp new file mode 100644 index 0000000000..b0e5fda3d6 --- /dev/null +++ b/catalogue/rdbms/RdbmsCatalogueUtils.cpp @@ -0,0 +1,508 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <optional> +#include <string> +#include <vector> + +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "common/log/Logger.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +bool RdbmsCatalogueUtils::diskSystemExists(rdbms::Conn &conn, const std::string &name) { + try { + const char *const sql = + "SELECT " + "DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME " + "FROM " + "DISK_SYSTEM " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_SYSTEM_NAME", name); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(const std::optional<std::string>& str, log::Logger* log) { + const size_t MAX_CHAR_COMMENT = 1000; + if (!str.has_value()) return; + if (str.value().length() > MAX_CHAR_COMMENT) { + log::LogContext lc(*log); + log::ScopedParamContainer spc(lc); + spc.add("Large_Message: ", str.value()); + lc.log(log::ERR, "The reason or comment has more characters than the maximun allowed."); + throw CommentOrReasonWithMoreSizeThanMaximunAllowed( + "The comment or reason string value has more than 1000 characters"); + } +} + +bool RdbmsCatalogueUtils::storageClassExists(rdbms::Conn &conn, const std::string &storageClassName) { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::virtualOrganizationExists(rdbms::Conn &conn, const std::string &voName) { + try { + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " + "FROM " + "VIRTUAL_ORGANIZATION " + "WHERE " + "UPPER(VIRTUAL_ORGANIZATION_NAME) = UPPER(:VIRTUAL_ORGANIZATION_NAME)"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::mediaTypeExists(rdbms::Conn &conn, const std::string &name) { + try { + const char *const sql = + "SELECT " + "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME " + "FROM " + "MEDIA_TYPE " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":MEDIA_TYPE_NAME", name); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::diskInstanceExists(rdbms::Conn &conn, const std::string &name) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME " + "FROM " + "DISK_INSTANCE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", name); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName) { + try { + const char *const sql = + "SELECT " + "TAPE_POOL_NAME AS TAPE_POOL_NAME " + "FROM " + "TAPE_POOL " + "WHERE " + "TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName) { + try { + const char *const sql = + "SELECT " + "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME " + "FROM " + "LOGICAL_LIBRARY " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::tapeExists(rdbms::Conn &conn, const std::string &vid) { + try { + const char *const sql = + "SELECT " + "VID AS VID " + "FROM " + "TAPE " + "WHERE " + "VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId) { + try { + const char *const sql = + "SELECT " + "ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " + "FROM " + "ARCHIVE_FILE " + "WHERE " + "ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName) { + try { + const char *const sql = + "SELECT " + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME " + "FROM " + "MOUNT_POLICY " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::archiveRouteExists(rdbms::Conn &conn, const std::string &storageClassName, + const uint32_t copyNb) { + try { + const char *const sql = + "SELECT " + "ARCHIVE_ROUTE.STORAGE_CLASS_ID AS STORAGE_CLASS_ID," + "ARCHIVE_ROUTE.COPY_NB AS COPY_NB " + "FROM " + "ARCHIVE_ROUTE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "STORAGE_CLASS.STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME AND " + "ARCHIVE_ROUTE.COPY_NB = :COPY_NB"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + stmt.bindUint64(":COPY_NB", copyNb); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::requesterActivityMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterName, const std::string &activityRegex) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "REQUESTER_NAME AS REQUESTER_NAME, " + "ACTIVITY_REGEX AS ACTIVITY_REGEX " + "FROM " + "REQUESTER_ACTIVITY_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME AND " + "ACTIVITY_REGEX = :ACTIVITY_REGEX"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":ACTIVITY_REGEX", activityRegex); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &diskFileId) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "DISK_FILE_ID AS DISK_FILE_ID " + "FROM " + "ARCHIVE_FILE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "DISK_FILE_ID = :DISK_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":DISK_FILE_ID", diskFileId); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName, + uint32_t diskFileOwnerUid) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "DISK_FILE_UID AS DISK_FILE_UID " + "FROM " + "ARCHIVE_FILE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "DISK_FILE_UID = :DISK_FILE_UID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindUint64(":DISK_FILE_UID", diskFileOwnerUid); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName, + uint32_t diskFileGid) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "DISK_FILE_GID AS DISK_FILE_GID " + "FROM " + "ARCHIVE_FILE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "DISK_FILE_GID = :DISK_FILE_GID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindUint64(":DISK_FILE_GID", diskFileGid); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterName) { + try { + const char *const sql = + "SELECT " + "REQUESTER_NAME AS REQUESTER_NAME " + "FROM " + "REQUESTER_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsCatalogueUtils::requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterGroupName) { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME, " + "REQUESTER_GROUP_NAME AS REQUESTER_GROUP_NAME " + "FROM " + "REQUESTER_GROUP_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +bool RdbmsCatalogueUtils::isSetAndEmpty(const std::optional<std::string> &optionalStr) { + return optionalStr && optionalStr->empty(); +} + +bool RdbmsCatalogueUtils::isSetAndEmpty(const std::optional<std::vector<std::string>> &optionalStrList) { + return optionalStrList && optionalStrList->empty(); +} + +void RdbmsCatalogueUtils::setTapeDirty(rdbms::Conn& conn, const std::string& vid) { + try { + const char * const sql = + "UPDATE TAPE SET DIRTY='1' WHERE VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsCatalogueUtils::setTapeDirty(rdbms::Conn& conn, const uint64_t & archiveFileId) { + try { + const char * const sql = + "UPDATE TAPE SET DIRTY='1' " + "WHERE VID IN " + " (SELECT DISTINCT TAPE_FILE.VID AS VID FROM TAPE_FILE WHERE TAPE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID)"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsCatalogueUtils::updateTape(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq, + const uint64_t compressedBytesWritten, const uint64_t filesWritten, const std::string &tapeDrive) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "LAST_FSEQ = :LAST_FSEQ," + "DATA_IN_BYTES = DATA_IN_BYTES + :DATA_IN_BYTES," + "MASTER_DATA_IN_BYTES = MASTER_DATA_IN_BYTES + :MASTER_DATA_IN_BYTES," + "NB_MASTER_FILES = NB_MASTER_FILES + :MASTER_FILES," + "LAST_WRITE_DRIVE = :LAST_WRITE_DRIVE," + "LAST_WRITE_TIME = :LAST_WRITE_TIME " + "WHERE " + "VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.bindUint64(":LAST_FSEQ", lastFSeq); + stmt.bindUint64(":DATA_IN_BYTES", compressedBytesWritten); + stmt.bindUint64(":MASTER_FILES", filesWritten); + stmt.bindUint64(":MASTER_DATA_IN_BYTES", compressedBytesWritten); + stmt.bindString(":LAST_WRITE_DRIVE", tapeDrive); + stmt.bindUint64(":LAST_WRITE_TIME", now); + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::string RdbmsCatalogueUtils::generateTapeStateModifiedBy( const common::dataStructures::SecurityIdentity & admin) { + return admin.username + "@" + admin.host; +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsCatalogueUtils.hpp b/catalogue/rdbms/RdbmsCatalogueUtils.hpp new file mode 100644 index 0000000000..638cd2723f --- /dev/null +++ b/catalogue/rdbms/RdbmsCatalogueUtils.hpp @@ -0,0 +1,87 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <optional> +#include <string> +#include <vector> + +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +} +} + +namespace log { +class Logger; +} + +namespace rdbms { +class Conn; +} + +namespace catalogue { + +CTA_GENERATE_EXCEPTION_CLASS(CommentOrReasonWithMoreSizeThanMaximunAllowed); + +class RdbmsCatalogueUtils { +public: + static bool diskSystemExists(rdbms::Conn &conn, const std::string &name); + static void checkCommentOrReasonMaxLength(const std::optional<std::string>& str, log::Logger* log); + static bool storageClassExists(rdbms::Conn &conn, const std::string &storageClassName); + static bool virtualOrganizationExists(rdbms::Conn &conn, const std::string &voName); + static bool mediaTypeExists(rdbms::Conn &conn, const std::string &name); + static bool diskInstanceExists(rdbms::Conn &conn, const std::string &name); + static bool tapePoolExists(rdbms::Conn &conn, const std::string &tapePoolName); + static bool logicalLibraryExists(rdbms::Conn &conn, const std::string &logicalLibraryName); + static bool tapeExists(rdbms::Conn &conn, const std::string &vid); + static bool archiveFileIdExists(rdbms::Conn &conn, const uint64_t archiveFileId); + static bool mountPolicyExists(rdbms::Conn &conn, const std::string &mountPolicyName); + static bool archiveRouteExists(rdbms::Conn &conn, const std::string &storageClassName, const uint32_t copyNb); + static bool requesterActivityMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterName, const std::string &activityRegex); + static bool diskFileIdExists(rdbms::Conn &conn, const std::string &diskInstanceName, const std::string &diskFileId); + static bool diskFileUserExists(rdbms::Conn &conn, const std::string &diskInstanceName, uint32_t diskFileOwnerUid); + static bool diskFileGroupExists(rdbms::Conn &conn, const std::string &diskInstanceName, uint32_t diskFileGid); + static bool requesterMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterName); + static bool requesterGroupMountRuleExists(rdbms::Conn &conn, const std::string &diskInstanceName, + const std::string &requesterGroupName); + + static bool isSetAndEmpty(const std::optional<std::string> &optionalStr); + static bool isSetAndEmpty(const std::optional<std::vector<std::string>> &optionalStrList); + + /** + * Set the DIRTY flag to true + * @param conn the database connection + * @param vid the vid in which we want to set it as dirty + */ + static void setTapeDirty(rdbms::Conn &conn, const std::string &vid); + static void setTapeDirty(rdbms::Conn& conn, const uint64_t & archiveFileId); + static void updateTape(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq, + const uint64_t compressedBytesWritten, const uint64_t filesWritten, const std::string &tapeDrive); + static std::string generateTapeStateModifiedBy(const common::dataStructures::SecurityIdentity & admin); +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskInstanceCatalogue.cpp b/catalogue/rdbms/RdbmsDiskInstanceCatalogue.cpp new file mode 100644 index 0000000000..4da97ff49e --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskInstanceCatalogue.cpp @@ -0,0 +1,219 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsDiskInstanceCatalogue::RdbmsDiskInstanceCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool) + : m_log(log), m_connPool(connPool) {} + +void RdbmsDiskInstanceCatalogue::createDiskInstance(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create disk system because the name is an empty string"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create disk system because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::diskInstanceExists(conn, name)) { + throw exception::UserError(std::string("Cannot create disk instance ") + name + + " because a disk instance with the same name identifier already exists"); + } + + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO DISK_INSTANCE(" + "DISK_INSTANCE_NAME," + + "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(" + ":DISK_INSTANCE_NAME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_INSTANCE_NAME", name); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceCatalogue::deleteDiskInstance(const std::string &name) { + try { + const char *const delete_sql = + "DELETE " + "FROM " + "DISK_INSTANCE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DISK_INSTANCE_NAME", name); + stmt.executeNonQuery(); + + // The delete statement will effect no rows and will not raise an error if + // either the tape does not exist or if it still has tape files + if(0 == stmt.getNbAffectedRows()) { + if(RdbmsCatalogueUtils::diskInstanceExists(conn, name)) { + throw UserSpecifiedANonEmptyDiskInstanceAfterDelete(std::string("Cannot delete disk instance ") + name + " for unknown reason"); + } else { + throw UserSpecifiedANonExistentDiskInstance(std::string("Cannot delete disk instance ") + name + " because it does not exist"); + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceCatalogue::modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot modify disk instance" + " because the disk instance name is an empty string"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot modify disk instance " + "because the new comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_INSTANCE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskInstance(std::string("Cannot modify disk instance ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::DiskInstance> RdbmsDiskInstanceCatalogue::getAllDiskInstances() const { + try { + std::list<common::dataStructures::DiskInstance> diskInstanceList; + std::string sql = + "SELECT " + "DISK_INSTANCE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + + "DISK_INSTANCE.USER_COMMENT AS USER_COMMENT," + + "DISK_INSTANCE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "DISK_INSTANCE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "DISK_INSTANCE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "DISK_INSTANCE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "DISK_INSTANCE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "DISK_INSTANCE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "DISK_INSTANCE"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::DiskInstance diskInstance; + diskInstance.name = rset.columnString("DISK_INSTANCE_NAME"); + diskInstance.comment = rset.columnString("USER_COMMENT"); + diskInstance.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + diskInstance.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + diskInstance.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + diskInstance.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + diskInstance.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + diskInstance.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + diskInstanceList.push_back(diskInstance); + } + return diskInstanceList; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp b/catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp new file mode 100644 index 0000000000..f17e4bd601 --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp @@ -0,0 +1,57 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/interfaces/DiskInstanceCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsDiskInstanceCatalogue : public DiskInstanceCatalogue { +public: + RdbmsDiskInstanceCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsDiskInstanceCatalogue() override = default; + + void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + void deleteDiskInstance(const std::string &name) override; + + void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.cpp b/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.cpp new file mode 100644 index 0000000000..51ecbadd43 --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.cpp @@ -0,0 +1,405 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> +#include <memory> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDiskInstanceCatalogue.hpp" +#include "catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp" +#include "common/dataStructures/DiskInstanceSpace.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsDiskInstanceSpaceCatalogue::RdbmsDiskInstanceSpaceCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool) + : m_log(log), m_connPool(connPool) {} + +void RdbmsDiskInstanceSpaceCatalogue::deleteDiskInstanceSpace(const std::string &name, + const std::string &diskInstance) { + try { + const char *const delete_sql = + "DELETE " + "FROM " + "DISK_INSTANCE_SPACE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.executeNonQuery(); + + // The delete statement will effect no rows and will not raise an error if + // either the tape does not exist or if it still has tape files + if(0 == stmt.getNbAffectedRows()) { + if(diskInstanceSpaceExists(conn, name, diskInstance)) { + throw UserSpecifiedANonEmptyDiskInstanceSpaceAfterDelete(std::string("Cannot delete disk instance space") + + name + " for unknown reason"); + } else { + throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot delete disk instance space ") + + name + " because it does not exist"); + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceSpaceCatalogue::createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot create disk instance space because the name is an empty string"); + } + if(freeSpaceQueryURL.empty()) { + throw UserSpecifiedAnEmptyStringFreeSpaceQueryURL("Cannot create disk instance space because the free space query URL is an empty string"); + } + if(0 == refreshInterval) { + throw UserSpecifiedAZeroRefreshInterval("Cannot create disk instance space because the refresh interval is zero"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create disk instance space because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + auto conn = m_connPool->getConn(); + if(!RdbmsCatalogueUtils::diskInstanceExists(conn, diskInstance)) { + throw exception::UserError(std::string("Cannot create disk instance space ") + name + + " for disk instance " + diskInstance + + " because the disk instance does not exist"); + } + + if (diskInstanceSpaceExists(conn, name, diskInstance)) { + throw exception::UserError(std::string("Cannot create disk instance space ") + name + + " for disk instance " + diskInstance + + " because a disk instance space with the same name and disk instance already exists"); + } + + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO DISK_INSTANCE_SPACE(" + "DISK_INSTANCE_NAME," + "DISK_INSTANCE_SPACE_NAME," + "FREE_SPACE_QUERY_URL," + "REFRESH_INTERVAL," + "LAST_REFRESH_TIME," + "FREE_SPACE," + + "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(" + ":DISK_INSTANCE_NAME," + ":DISK_INSTANCE_SPACE_NAME," + ":FREE_SPACE_QUERY_URL," + ":REFRESH_INTERVAL," + ":LAST_REFRESH_TIME," + ":FREE_SPACE," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.bindString(":FREE_SPACE_QUERY_URL", freeSpaceQueryURL); + stmt.bindUint64(":REFRESH_INTERVAL", refreshInterval); + stmt.bindUint64(":LAST_REFRESH_TIME", 0); + stmt.bindUint64(":FREE_SPACE", 0); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::DiskInstanceSpace> RdbmsDiskInstanceSpaceCatalogue::getAllDiskInstanceSpaces() const { + try { + std::list<common::dataStructures::DiskInstanceSpace> diskInstanceSpaceList; + std::string sql = + "SELECT " + "DISK_INSTANCE_SPACE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "DISK_INSTANCE_SPACE.DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME," + "DISK_INSTANCE_SPACE.FREE_SPACE_QUERY_URL AS FREE_SPACE_QUERY_URL," + "DISK_INSTANCE_SPACE.REFRESH_INTERVAL AS REFRESH_INTERVAL," + "DISK_INSTANCE_SPACE.LAST_REFRESH_TIME AS LAST_REFRESH_TIME," + "DISK_INSTANCE_SPACE.FREE_SPACE AS FREE_SPACE," + + "DISK_INSTANCE_SPACE.USER_COMMENT AS USER_COMMENT," + + "DISK_INSTANCE_SPACE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "DISK_INSTANCE_SPACE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "DISK_INSTANCE_SPACE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "DISK_INSTANCE_SPACE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "DISK_INSTANCE_SPACE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "DISK_INSTANCE_SPACE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "DISK_INSTANCE_SPACE"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::DiskInstanceSpace diskInstanceSpace; + diskInstanceSpace.name = rset.columnString("DISK_INSTANCE_SPACE_NAME"); + diskInstanceSpace.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + diskInstanceSpace.freeSpaceQueryURL = rset.columnString("FREE_SPACE_QUERY_URL"); + diskInstanceSpace.refreshInterval = rset.columnUint64("REFRESH_INTERVAL"); + diskInstanceSpace.freeSpace = rset.columnUint64("FREE_SPACE"); + diskInstanceSpace.lastRefreshTime = rset.columnUint64("LAST_REFRESH_TIME"); + diskInstanceSpace.comment = rset.columnString("USER_COMMENT"); + diskInstanceSpace.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + diskInstanceSpace.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + diskInstanceSpace.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + diskInstanceSpace.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + diskInstanceSpace.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + diskInstanceSpace.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + diskInstanceSpaceList.push_back(diskInstanceSpace); + } + return diskInstanceSpaceList; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &comment) { + try { + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot modify disk instance space " + "because the new comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_INSTANCE_SPACE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceRefreshInterval( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const uint64_t refreshInterval) { + try { + if(0 == refreshInterval) { + throw UserSpecifiedAZeroRefreshInterval("Cannot modify disk instance space " + "because the new refreshInterval is zero"); + } + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_INSTANCE_SPACE SET " + "REFRESH_INTERVAL = :REFRESH_INTERVAL," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":REFRESH_INTERVAL", refreshInterval); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_INSTANCE_SPACE SET " + "FREE_SPACE = :FREE_SPACE," + "LAST_REFRESH_TIME = :LAST_REFRESH_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":FREE_SPACE", freeSpace); + stmt.bindUint64(":LAST_REFRESH_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskInstanceSpaceCatalogue::modifyDiskInstanceSpaceQueryURL( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &freeSpaceQueryURL) { + try { + if(freeSpaceQueryURL.empty()) { + throw UserSpecifiedAnEmptyStringFreeSpaceQueryURL("Cannot modify disk instance space " + "because the new freeSpaceQueryURL is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_INSTANCE_SPACE SET " + "FREE_SPACE_QUERY_URL = :FREE_SPACE_QUERY_URL," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + "AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":FREE_SPACE_QUERY_URL", freeSpaceQueryURL); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskInstanceSpace(std::string("Cannot modify disk system ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsDiskInstanceSpaceCatalogue::diskInstanceSpaceExists(rdbms::Conn &conn, const std::string &name, + const std::string &diskInstance) const { + try { + const char *const sql = + "SELECT " + "DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME " + "FROM " + "DISK_INSTANCE_SPACE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME " + " AND " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", name); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp b/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp new file mode 100644 index 0000000000..6fa4cab41a --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskInstanceSpaceCatalogue.hpp @@ -0,0 +1,78 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct SecurityIdentity; +} +} + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsDiskInstanceSpaceCatalogue : public DiskInstanceSpaceCatalogue { +public: + RdbmsDiskInstanceSpaceCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsDiskInstanceSpaceCatalogue() override = default; + + void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) override; + + void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstance, + const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, + const std::string &comment) override; + + std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const override; + + void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &comment) override; + + void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) override; + + void modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) override; + + void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + + bool diskInstanceSpaceExists(rdbms::Conn &conn, const std::string &name, const std::string &diskInstance) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskSystemCatalogue.cpp b/catalogue/rdbms/RdbmsDiskSystemCatalogue.cpp new file mode 100644 index 0000000000..83c4209164 --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskSystemCatalogue.cpp @@ -0,0 +1,492 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/interfaces/DiskInstanceCatalogue.hpp" +#include "catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "disk/DiskSystem.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsDiskSystemCatalogue::RdbmsDiskSystemCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool) + : m_log(log), m_connPool(connPool) {} + +void RdbmsDiskSystemCatalogue::createDiskSystem(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, + const std::string &fileRegexp, const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot create disk system because the name is an empty string"); + } + if(fileRegexp.empty()) { + throw UserSpecifiedAnEmptyStringFileRegexp("Cannot create disk system because the file regexp is an empty string"); + } + if(diskInstanceName.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create disk system because the disk instance name is an empty string"); + } + if(diskInstanceSpaceName.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot create disk system because the disk instance space name is an empty string"); + } + if(0 == targetedFreeSpace) { + throw UserSpecifiedAZeroTargetedFreeSpace("Cannot create disk system because the targeted free space is zero"); + } + if (0 == sleepTime) { + throw UserSpecifiedAZeroSleepTime("Cannot create disk system because the sleep time is zero"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create disk system because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::diskSystemExists(conn, name)) { + throw exception::UserError(std::string("Cannot create disk system ") + name + + " because a disk system with the same name identifier already exists"); + } + + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO DISK_SYSTEM(" + "DISK_SYSTEM_NAME," + "DISK_INSTANCE_NAME," + "DISK_INSTANCE_SPACE_NAME," + "FILE_REGEXP," + "TARGETED_FREE_SPACE," + "SLEEP_TIME," + + "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(" + ":DISK_SYSTEM_NAME," + ":DISK_INSTANCE_NAME," + ":DISK_INSTANCE_SPACE_NAME," + ":FILE_REGEXP," + ":TARGETED_FREE_SPACE," + ":SLEEP_TIME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", diskInstanceSpaceName); + stmt.bindString(":FILE_REGEXP", fileRegexp); + stmt.bindUint64(":TARGETED_FREE_SPACE", targetedFreeSpace); + stmt.bindUint64(":SLEEP_TIME", sleepTime); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::deleteDiskSystem(const std::string &name) { + try { + const char *const delete_sql = + "DELETE " + "FROM " + "DISK_SYSTEM " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + // The delete statement will effect no rows and will not raise an error if + // either the tape does not exist or if it still has tape files + if(0 == stmt.getNbAffectedRows()) { + if(RdbmsCatalogueUtils::diskSystemExists(conn, name)) { + throw UserSpecifiedANonEmptyDiskSystemAfterDelete(std::string("Cannot delete disk system ") + name + " for unknown reason"); + } else { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot delete disk system ") + name + " because it does not exist"); + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +disk::DiskSystemList RdbmsDiskSystemCatalogue::getAllDiskSystems() const { + try { + disk::DiskSystemList diskSystemList; + const std::string sql = + "SELECT " + "DISK_SYSTEM.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," + "DISK_SYSTEM.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "DISK_SYSTEM.DISK_INSTANCE_SPACE_NAME AS DISK_INSTANCE_SPACE_NAME," + "DISK_SYSTEM.FILE_REGEXP AS FILE_REGEXP," + "DISK_SYSTEM.TARGETED_FREE_SPACE AS TARGETED_FREE_SPACE," + "DISK_SYSTEM.SLEEP_TIME AS SLEEP_TIME," + + "DISK_SYSTEM.USER_COMMENT AS USER_COMMENT," + + "DISK_SYSTEM.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "DISK_SYSTEM.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "DISK_SYSTEM.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "DISK_SYSTEM.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "DISK_SYSTEM.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "DISK_SYSTEM.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," + + "DISK_INSTANCE_SPACE.FREE_SPACE_QUERY_URL AS FREE_SPACE_QUERY_URL," + "DISK_INSTANCE_SPACE.REFRESH_INTERVAL AS REFRESH_INTERVAL," + "DISK_INSTANCE_SPACE.LAST_REFRESH_TIME AS LAST_REFRESH_TIME," + "DISK_INSTANCE_SPACE.FREE_SPACE AS FREE_SPACE " + "FROM " + "DISK_SYSTEM " + "INNER JOIN DISK_INSTANCE_SPACE ON " + "DISK_SYSTEM.DISK_INSTANCE_NAME = DISK_INSTANCE_SPACE.DISK_INSTANCE_NAME " + "AND " + "DISK_SYSTEM.DISK_INSTANCE_SPACE_NAME = DISK_INSTANCE_SPACE.DISK_INSTANCE_SPACE_NAME" + ; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + auto rset = stmt.executeQuery(); + while (rset.next()) { + disk::DiskSystem diskSystem; + diskSystem.name = rset.columnString("DISK_SYSTEM_NAME"); + diskSystem.fileRegexp = rset.columnString("FILE_REGEXP"); + diskSystem.targetedFreeSpace = rset.columnUint64("TARGETED_FREE_SPACE"); + diskSystem.sleepTime = rset.columnUint64("SLEEP_TIME"); + diskSystem.comment = rset.columnString("USER_COMMENT"); + diskSystem.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + diskSystem.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + diskSystem.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + diskSystem.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + diskSystem.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + diskSystem.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + diskSystem.diskInstanceSpace.freeSpaceQueryURL = rset.columnString("FREE_SPACE_QUERY_URL"); + diskSystem.diskInstanceSpace.refreshInterval = rset.columnUint64("REFRESH_INTERVAL"); + diskSystem.diskInstanceSpace.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + diskSystem.diskInstanceSpace.name = rset.columnString("DISK_INSTANCE_SPACE_NAME"); + diskSystem.diskInstanceSpace.lastRefreshTime = rset.columnUint64("LAST_REFRESH_TIME"); + diskSystem.diskInstanceSpace.freeSpace = rset.columnUint64("FREE_SPACE"); + diskSystemList.push_back(diskSystem); + } + return diskSystemList; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(fileRegexp.empty()) { + throw UserSpecifiedAnEmptyStringFileRegexp("Cannot modify disk system " + "because the new fileRegexp is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "FILE_REGEXP = :FILE_REGEXP," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":FILE_REGEXP", fileRegexp); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t targetedFreeSpace) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(0 == targetedFreeSpace) { + throw UserSpecifiedAZeroTargetedFreeSpace("Cannot modify disk system " + "because the new targeted free space has zero value"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "TARGETED_FREE_SPACE = :TARGETED_FREE_SPACE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":TARGETED_FREE_SPACE", targetedFreeSpace); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot modify disk system " + "because the new comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(sleepTime == 0) { + throw UserSpecifiedAZeroSleepTime("Cannot modify disk system " + "because the new sleep time is zero"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "SLEEP_TIME = :SLEEP_TIME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":SLEEP_TIME", sleepTime); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(diskInstanceName.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot modify disk system " + "because the new comment is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDiskSystemCatalogue::modifyDiskSystemDiskInstanceSpaceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceSpaceName) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringDiskSystemName("Cannot modify disk system" + " because the disk system name is an empty string"); + } + if(diskInstanceSpaceName.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceSpaceName("Cannot modify disk system " + "because the new comment is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE DISK_SYSTEM SET " + "DISK_INSTANCE_SPACE_NAME = :DISK_INSTANCE_SPACE_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_SPACE_NAME", diskInstanceSpaceName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_SYSTEM_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentDiskSystem(std::string("Cannot modify disk system ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsDiskSystemCatalogue::diskSystemExists(const std::string &name) const { + try { + auto conn = m_connPool->getConn(); + return RdbmsCatalogueUtils::diskSystemExists(conn, name); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp b/catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp new file mode 100644 index 0000000000..77b6aab19b --- /dev/null +++ b/catalogue/rdbms/RdbmsDiskSystemCatalogue.hpp @@ -0,0 +1,79 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/interfaces/DiskSystemCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace disk { +struct DiskSystemList; +} + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsDiskSystemCatalogue : public DiskSystemCatalogue { +public: + RdbmsDiskSystemCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsDiskSystemCatalogue() override = default; + + void createDiskSystem(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, const std::string &fileRegexp, + const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) override; + + void deleteDiskSystem(const std::string &name) override; + + disk::DiskSystemList getAllDiskSystems() const override; + + void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) override; + + void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t targetedFreeSpace) override; + + void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) override; + + void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName) override; + + void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceSpaceName) override; + + bool diskSystemExists(const std::string &name) const override; +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsDriveConfigCatalogue.cpp b/catalogue/rdbms/RdbmsDriveConfigCatalogue.cpp new file mode 100644 index 0000000000..29a081e16f --- /dev/null +++ b/catalogue/rdbms/RdbmsDriveConfigCatalogue.cpp @@ -0,0 +1,248 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/CatalogueExceptions.hpp" +#include "catalogue/CatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp" +#include "common/dataStructures/DesiredDriveState.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/dataStructures/TapeDriveStatistics.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsDriveConfigCatalogue::RdbmsDriveConfigCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool) + : m_log(log), m_connPool(connPool) { +} + +void RdbmsDriveConfigCatalogue::createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + try { + auto conn = m_connPool->getConn(); + const char *const sql = + "INSERT INTO DRIVE_CONFIG(" "\n" + "DRIVE_NAME," "\n" + "CATEGORY," "\n" + "KEY_NAME," "\n" + "VALUE," "\n" + "SOURCE)" "\n" + "VALUES(" "\n" + ":DRIVE_NAME," "\n" + ":CATEGORY," "\n" + ":KEY_NAME," "\n" + ":VALUE," "\n" + ":SOURCE" "\n" + ")"; + + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DRIVE_NAME", tapeDriveName); + stmt.bindString(":CATEGORY", category); + stmt.bindString(":KEY_NAME", keyName); + if (value.empty()) { + stmt.bindString(":VALUE", std::string("NULL")); + } else { + stmt.bindString(":VALUE", value); + } + if (source.empty()) { + stmt.bindString(":SOURCE", std::string("NULL")); + } else { + stmt.bindString(":SOURCE", source); + } + + stmt.executeNonQuery(); + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("driveName", tapeDriveName) + .add("category", category) + .add("keyName", keyName) + .add("value", value) + .add("source", source); + lc.log(log::INFO, "Catalogue - created drive configuration"); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<std::pair<std::string, std::string>> RdbmsDriveConfigCatalogue::getTapeDriveConfigNamesAndKeys() const { + try { + std::list<std::pair<std::string, std::string>> namesAndKeys; + const char *const sql = + "SELECT " + "DRIVE_NAME AS DRIVE_NAME," + "KEY_NAME AS KEY_NAME " + "FROM " + "DRIVE_CONFIG "; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + + while (rset.next()) { + const std::string driveName = rset.columnString("DRIVE_NAME"); + const std::string key = rset.columnString("KEY_NAME"); + namesAndKeys.push_back(std::make_pair(driveName, key)); + } + return namesAndKeys; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> RdbmsDriveConfigCatalogue::getTapeDriveConfigs() const { + try { + const char *const sql = + "SELECT " + "DRIVE_NAME AS DRIVE_NAME," + "CATEGORY AS CATEGORY," + "KEY_NAME AS KEY_NAME," + "VALUE AS VALUE," + "SOURCE AS SOURCE " + "FROM " + "DRIVE_CONFIG "; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> drivesConfigs; + while (rset.next()) { + const std::string tapeDriveName = rset.columnString("DRIVE_NAME"); + const std::string category = rset.columnString("CATEGORY"); + const std::string keyName = rset.columnString("KEY_NAME"); + std::string value = rset.columnString("VALUE"); + std::string source = rset.columnString("SOURCE"); + if (value == "NULL") value.clear(); + if (source == "NULL") source.clear(); + cta::catalogue::DriveConfigCatalogue::DriveConfig driveConfig = {tapeDriveName, category, keyName, value, source}; + drivesConfigs.push_back(driveConfig); + } + return drivesConfigs; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<std::tuple<std::string, std::string, std::string>> RdbmsDriveConfigCatalogue::getTapeDriveConfig( + const std::string &tapeDriveName, const std::string &keyName) const { + try { + const char *const sql = + "SELECT " + "DRIVE_NAME AS DRIVE_NAME," + "CATEGORY AS CATEGORY," + "KEY_NAME AS KEY_NAME," + "VALUE AS VALUE," + "SOURCE AS SOURCE " + "FROM " + "DRIVE_CONFIG " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME AND KEY_NAME = :KEY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DRIVE_NAME", tapeDriveName); + stmt.bindString(":KEY_NAME", keyName); + auto rset = stmt.executeQuery(); + if (rset.next()) { + const std::string category = rset.columnString("CATEGORY"); + std::string value = rset.columnString("VALUE"); + std::string source = rset.columnString("SOURCE"); + if (value == "NULL") value.clear(); + if (source == "NULL") source.clear(); + return std::make_tuple(category, value, source); + } + return std::nullopt; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveConfigCatalogue::modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + try { + const char *const sql = + "UPDATE DRIVE_CONFIG " + "SET " + "CATEGORY = :CATEGORY," + "VALUE = :VALUE," + "SOURCE = :SOURCE " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME AND KEY_NAME = :KEY_NAME"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DRIVE_NAME", tapeDriveName); + stmt.bindString(":CATEGORY", category); + stmt.bindString(":KEY_NAME", keyName); + if (value.empty()) { + stmt.bindString(":VALUE", std::string("NULL")); + } else { + stmt.bindString(":VALUE", value); + } + if (source.empty()) { + stmt.bindString(":SOURCE", std::string("NULL")); + } else { + stmt.bindString(":SOURCE", source); + } + + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::Exception(std::string("Cannot modify Config Drive with name: ") + tapeDriveName + + " and key" + keyName + " because it doesn't exist"); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveConfigCatalogue::deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) { + try { + const char *const delete_sql = + "DELETE " + "FROM " + "DRIVE_CONFIG " + "WHERE " + "DRIVE_NAME = :DELETE_DRIVE_NAME AND KEY_NAME = :DELETE_KEY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DELETE_DRIVE_NAME", tapeDriveName); + stmt.bindString(":DELETE_KEY_NAME", keyName); + stmt.executeNonQuery(); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp b/catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp new file mode 100644 index 0000000000..fc23fcc943 --- /dev/null +++ b/catalogue/rdbms/RdbmsDriveConfigCatalogue.hpp @@ -0,0 +1,65 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveConfigCatalogue.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { + +namespace rdbms { +class ConnPool; +} + +namespace catalogue { + +class RdbmsDriveConfigCatalogue : public DriveConfigCatalogue { +public: + RdbmsDriveConfigCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsDriveConfigCatalogue() override = default; + + void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::list<DriveConfig> getTapeDriveConfigs() const override; + + std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const override; + + void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) const override; + + void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) override; + +private: + log::Logger &m_log; + + std::shared_ptr<rdbms::ConnPool> m_connPool; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsDriveStateCatalogue.cpp b/catalogue/rdbms/RdbmsDriveStateCatalogue.cpp new file mode 100644 index 0000000000..ac70123ac3 --- /dev/null +++ b/catalogue/rdbms/RdbmsDriveStateCatalogue.cpp @@ -0,0 +1,1057 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <map> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/CatalogueExceptions.hpp" +#include "catalogue/CatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsDriveStateCatalogue.hpp" +#include "common/dataStructures/DesiredDriveState.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/dataStructures/TapeDriveStatistics.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsDriveStateCatalogue::RdbmsDriveStateCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool) + : m_log(log), m_connPool(connPool) { +} + +void RdbmsDriveStateCatalogue::createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) { + try { + auto conn = m_connPool->getConn(); + const char *const sql = + "INSERT INTO DRIVE_STATE(" "\n" + "DRIVE_NAME," "\n" + "HOST," "\n" + "LOGICAL_LIBRARY," "\n" + "SESSION_ID," "\n" + + "BYTES_TRANSFERED_IN_SESSION," "\n" + "FILES_TRANSFERED_IN_SESSION," "\n" + + "SESSION_START_TIME," "\n" + "SESSION_ELAPSED_TIME," "\n" + "MOUNT_START_TIME," "\n" + "TRANSFER_START_TIME," "\n" + "UNLOAD_START_TIME," "\n" + "UNMOUNT_START_TIME," "\n" + "DRAINING_START_TIME," "\n" + "DOWN_OR_UP_START_TIME," "\n" + "PROBE_START_TIME," "\n" + "CLEANUP_START_TIME," "\n" + "START_START_TIME," "\n" + "SHUTDOWN_TIME," "\n" + + "MOUNT_TYPE," "\n" + "DRIVE_STATUS," "\n" + "DESIRED_UP," "\n" + "DESIRED_FORCE_DOWN," "\n" + "REASON_UP_DOWN," "\n" + + "CURRENT_VID," "\n" + "CTA_VERSION," "\n" + "CURRENT_PRIORITY," "\n" + "CURRENT_ACTIVITY," "\n" + "CURRENT_TAPE_POOL," "\n" + "NEXT_MOUNT_TYPE," "\n" + "NEXT_VID," "\n" + "NEXT_TAPE_POOL," "\n" + "NEXT_PRIORITY," "\n" + "NEXT_ACTIVITY," "\n" + + "DEV_FILE_NAME," "\n" + "RAW_LIBRARY_SLOT," "\n" + + "CURRENT_VO," "\n" + "NEXT_VO," "\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" + + "DISK_SYSTEM_NAME," "\n" + "RESERVED_BYTES," "\n" + "RESERVATION_SESSION_ID)" "\n" + "VALUES(" "\n" + ":DRIVE_NAME," "\n" + ":HOST," "\n" + ":LOGICAL_LIBRARY," "\n" + ":SESSION_ID," "\n" + + ":BYTES_TRANSFERED_IN_SESSION," "\n" + ":FILES_TRANSFERED_IN_SESSION," "\n" + + ":SESSION_START_TIME," "\n" + ":SESSION_ELAPSED_TIME," "\n" + ":MOUNT_START_TIME," "\n" + ":TRANSFER_START_TIME," "\n" + ":UNLOAD_START_TIME," "\n" + ":UNMOUNT_START_TIME," "\n" + ":DRAINING_START_TIME," "\n" + ":DOWN_OR_UP_START_TIME," "\n" + ":PROBE_START_TIME," "\n" + ":CLEANUP_START_TIME," "\n" + ":START_START_TIME," "\n" + ":SHUTDOWN_TIME," "\n" + + ":MOUNT_TYPE," "\n" + ":DRIVE_STATUS," "\n" + ":DESIRED_UP," "\n" + ":DESIRED_FORCE_DOWN," "\n" + ":REASON_UP_DOWN," "\n" + + ":CURRENT_VID," "\n" + ":CTA_VERSION," "\n" + ":CURRENT_PRIORITY," "\n" + ":CURRENT_ACTIVITY," "\n" + ":CURRENT_TAPE_POOL," "\n" + ":NEXT_MOUNT_TYPE," "\n" + ":NEXT_VID," "\n" + ":NEXT_TAPE_POOL," "\n" + ":NEXT_PRIORITY," "\n" + ":NEXT_ACTIVITY," "\n" + + ":DEV_FILE_NAME," "\n" + ":RAW_LIBRARY_SLOT," "\n" + + ":CURRENT_VO," "\n" + ":NEXT_VO," "\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" + + ":DISK_SYSTEM_NAME," "\n" + ":RESERVED_BYTES," "\n" + ":RESERVATION_SESSION_ID" "\n" + ")"; + + auto stmt = conn.createStmt(sql); + + settingSqlTapeDriveValues(&stmt, tapeDrive); + + stmt.executeNonQuery(); + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("driveName", tapeDrive.driveName) + .add("host", tapeDrive.host) + .add("logicalLibrary", tapeDrive.logicalLibrary) + .add("sessionId", tapeDrive.sessionId ? tapeDrive.sessionId.value() : 0) + + .add("bytesTransferedInSession", tapeDrive.bytesTransferedInSession + ? tapeDrive.bytesTransferedInSession.value() : 0) + .add("filesTransferedInSession", tapeDrive.filesTransferedInSession + ? tapeDrive.filesTransferedInSession.value() : 0) + + .add("sessionStartTime", tapeDrive.sessionStartTime ? tapeDrive.sessionStartTime.value() : 0) + .add("sessionElapsedTime", tapeDrive.sessionElapsedTime ? tapeDrive.sessionElapsedTime.value() : 0) + .add("mountStartTime", tapeDrive.mountStartTime ? tapeDrive.mountStartTime.value() : 0) + .add("transferStartTime", tapeDrive.transferStartTime + ? tapeDrive.transferStartTime.value() : 0) + .add("unloadStartTime", tapeDrive.unloadStartTime ? tapeDrive.unloadStartTime.value() : 0) + .add("unmountStartTime", tapeDrive.unmountStartTime ? tapeDrive.unmountStartTime.value() : 0) + .add("drainingStartTime", tapeDrive.drainingStartTime + ? tapeDrive.drainingStartTime.value() : 0) + .add("downOrUpStartTime", tapeDrive.downOrUpStartTime + ? tapeDrive.downOrUpStartTime.value() : 0) + .add("probeStartTime", tapeDrive.probeStartTime ? tapeDrive.probeStartTime.value() : 0) + .add("cleanupStartTime", tapeDrive.cleanupStartTime ? tapeDrive.cleanupStartTime.value() : 0) + .add("startStartTime", tapeDrive.startStartTime ? tapeDrive.startStartTime.value() : 0) + .add("shutdownTime", tapeDrive.shutdownTime ? tapeDrive.shutdownTime.value() : 0) + + .add("mountType", common::dataStructures::toString(tapeDrive.mountType)) + .add("driveStatus", common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus)) + + .add("desiredUp", tapeDrive.desiredUp ? 1 : 0) + .add("desiredForceDown", tapeDrive.desiredForceDown ? 1 : 0) + .add("reasonUpDown", tapeDrive.reasonUpDown ? tapeDrive.reasonUpDown.value() : "") + + .add("currentVo", tapeDrive.currentVo ? tapeDrive.currentVo.value() : "") + .add("nextVo", tapeDrive.nextVo ? tapeDrive.nextVo.value() : "") + .add("userComment", tapeDrive.userComment ? tapeDrive.userComment.value() : "") + + .add("creationLog_username", tapeDrive.creationLog + ? tapeDrive.creationLog.value().username : "") + .add("creationLog_host", tapeDrive.creationLog ? tapeDrive.creationLog.value().host : "") + .add("creationLog_time", tapeDrive.creationLog ? tapeDrive.creationLog.value().time : 0) + .add("lastModificationLog_username", tapeDrive.lastModificationLog + ? tapeDrive.lastModificationLog.value().username : "") + .add("lastModificationLog_username", tapeDrive.lastModificationLog + ? tapeDrive.lastModificationLog.value().host : "") + .add("lastModificationLog_username", tapeDrive.lastModificationLog + ? tapeDrive.lastModificationLog.value().time : 0) + + .add("diskSystemName", tapeDrive.diskSystemName ? tapeDrive.diskSystemName.value() : "") + .add("reservedBytes", tapeDrive.reservedBytes ? tapeDrive.reservedBytes.value() : 0) + .add("reservationSessionId", tapeDrive.reservationSessionId ? tapeDrive.reservationSessionId.value() : 0); + + lc.log(log::INFO, "Catalogue - created tape drive"); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveStateCatalogue::settingSqlTapeDriveValues(cta::rdbms::Stmt *stmt, + const common::dataStructures::TapeDrive &tapeDrive) const { + auto setOptionalString = [&stmt](const std::string& sqlField, const std::optional<std::string>& optionalField) { + if (optionalField && !optionalField.value().empty()) { + stmt->bindString(sqlField, optionalField.value()); + } else { + stmt->bindString(sqlField, std::nullopt); + } + }; + auto setOptionalTime = [&stmt](const std::string &sqlField, const std::optional<time_t>& optionalField) { + if (optionalField) { + stmt->bindUint64(sqlField, optionalField.value()); + } else { + stmt->bindUint64(sqlField, std::nullopt); + } + }; + + stmt->bindString(":DRIVE_NAME", tapeDrive.driveName); + stmt->bindString(":HOST", tapeDrive.host); + stmt->bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); + stmt->bindUint64(":SESSION_ID", tapeDrive.sessionId); + + stmt->bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession); + stmt->bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession); + + setOptionalTime(":SESSION_START_TIME", tapeDrive.sessionStartTime); + setOptionalTime(":SESSION_ELAPSED_TIME", tapeDrive.sessionElapsedTime); + setOptionalTime(":MOUNT_START_TIME", tapeDrive.mountStartTime); + setOptionalTime(":TRANSFER_START_TIME", tapeDrive.transferStartTime); + setOptionalTime(":UNLOAD_START_TIME", tapeDrive.unloadStartTime); + setOptionalTime(":UNMOUNT_START_TIME", tapeDrive.unmountStartTime); + setOptionalTime(":DRAINING_START_TIME", tapeDrive.drainingStartTime); + setOptionalTime(":DOWN_OR_UP_START_TIME", tapeDrive.downOrUpStartTime); + setOptionalTime(":PROBE_START_TIME", tapeDrive.probeStartTime); + setOptionalTime(":CLEANUP_START_TIME", tapeDrive.cleanupStartTime); + setOptionalTime(":START_START_TIME", tapeDrive.startStartTime); + setOptionalTime(":SHUTDOWN_TIME", tapeDrive.shutdownTime); + + stmt->bindString(":MOUNT_TYPE", common::dataStructures::toString(tapeDrive.mountType)); + stmt->bindString(":DRIVE_STATUS", common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus)); + + stmt->bindBool(":DESIRED_UP", tapeDrive.desiredUp); + stmt->bindBool(":DESIRED_FORCE_DOWN", tapeDrive.desiredForceDown); + setOptionalString(":REASON_UP_DOWN", tapeDrive.reasonUpDown); + + setOptionalString(":CURRENT_VID", tapeDrive.currentVid); + setOptionalString(":CTA_VERSION", tapeDrive.ctaVersion); + stmt->bindUint64(":CURRENT_PRIORITY", tapeDrive.currentPriority); + setOptionalString(":CURRENT_ACTIVITY", tapeDrive.currentActivity); + setOptionalString(":CURRENT_TAPE_POOL", tapeDrive.currentTapePool); + stmt->bindString(":NEXT_MOUNT_TYPE", common::dataStructures::toString(tapeDrive.nextMountType)); + setOptionalString(":NEXT_VID", tapeDrive.nextVid); + setOptionalString(":NEXT_TAPE_POOL", tapeDrive.nextTapePool); + stmt->bindUint64(":NEXT_PRIORITY", tapeDrive.nextPriority); + setOptionalString(":NEXT_ACTIVITY", tapeDrive.nextActivity); + + setOptionalString(":DEV_FILE_NAME", tapeDrive.devFileName); + setOptionalString(":RAW_LIBRARY_SLOT", tapeDrive.rawLibrarySlot); + + setOptionalString(":CURRENT_VO", tapeDrive.currentVo); + setOptionalString(":NEXT_VO", tapeDrive.nextVo); + setOptionalString(":USER_COMMENT", tapeDrive.userComment); + + auto setEntryLog = [stmt, setOptionalString, setOptionalTime](const std::string &field, + const std::optional<std::string> &username, const std::optional<std::string> &host, const std::optional<time_t> &time) { + setOptionalString(field + "_USER_NAME", username); + setOptionalString(field + "_HOST_NAME", host); + setOptionalTime(field + "_TIME", time); + }; + + if (tapeDrive.creationLog) { + setEntryLog(":CREATION_LOG", tapeDrive.creationLog.value().username, + tapeDrive.creationLog.value().host, tapeDrive.creationLog.value().time); + } else { + setEntryLog(":CREATION_LOG", std::nullopt, std::nullopt, std::nullopt); + } + + if (tapeDrive.lastModificationLog) { + setEntryLog(":LAST_UPDATE", tapeDrive.lastModificationLog.value().username, + tapeDrive.lastModificationLog.value().host, tapeDrive.lastModificationLog.value().time); + } else { + setEntryLog(":LAST_UPDATE", std::nullopt, std::nullopt, std::nullopt); + } + + setOptionalString(":DISK_SYSTEM_NAME", tapeDrive.diskSystemName); + stmt->bindUint64(":RESERVED_BYTES", tapeDrive.reservedBytes); + stmt->bindUint64(":RESERVATION_SESSION_ID", tapeDrive.reservationSessionId); +} + +void RdbmsDriveStateCatalogue::deleteTapeDrive(const std::string &tapeDriveName) { + try { + const char *const delete_sql = + "DELETE FROM " + "DRIVE_STATE " + "WHERE " + "DRIVE_NAME = :DELETE_DRIVE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DELETE_DRIVE_NAME", tapeDriveName); + stmt.executeNonQuery(); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<std::string> RdbmsDriveStateCatalogue::getTapeDriveNames() const { + try { + std::list<std::string> tapeDriveNames; + const char *const sql = + "SELECT " + "DRIVE_NAME AS DRIVE_NAME " + "FROM " + "DRIVE_STATE "; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + + while (rset.next()) { + const std::string driveName = rset.columnString("DRIVE_NAME"); + tapeDriveNames.push_back(driveName); + } + return tapeDriveNames; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::TapeDrive RdbmsDriveStateCatalogue::gettingSqlTapeDriveValues(cta::rdbms::Rset* rset) const { + common::dataStructures::TapeDrive tapeDrive; + auto getOptionalTime = [](const std::optional<uint64_t> &time) -> std::optional<time_t> { + if (!time) return std::nullopt; + return time.value(); + }; + tapeDrive.driveName = rset->columnString("DRIVE_NAME"); + tapeDrive.host = rset->columnString("HOST"); + tapeDrive.logicalLibrary = rset->columnString("LOGICAL_LIBRARY"); + tapeDrive.sessionId = rset->columnOptionalUint64("SESSION_ID"); + tapeDrive.logicalLibraryDisabled = rset->columnOptionalBool("IS_DISABLED") ? rset->columnOptionalBool("IS_DISABLED").value() : false; + + tapeDrive.bytesTransferedInSession = rset->columnOptionalUint64("BYTES_TRANSFERED_IN_SESSION"); + tapeDrive.filesTransferedInSession = rset->columnOptionalUint64("FILES_TRANSFERED_IN_SESSION"); + + tapeDrive.sessionStartTime = getOptionalTime(rset->columnOptionalUint64("SESSION_START_TIME")); + tapeDrive.sessionElapsedTime = getOptionalTime(rset->columnOptionalUint64("SESSION_ELAPSED_TIME")); + tapeDrive.mountStartTime = getOptionalTime(rset->columnOptionalUint64("MOUNT_START_TIME")); + tapeDrive.transferStartTime = getOptionalTime(rset->columnOptionalUint64("TRANSFER_START_TIME")); + tapeDrive.unloadStartTime = getOptionalTime(rset->columnOptionalUint64("UNLOAD_START_TIME")); + tapeDrive.unmountStartTime = getOptionalTime(rset->columnOptionalUint64("UNMOUNT_START_TIME")); + tapeDrive.drainingStartTime = getOptionalTime(rset->columnOptionalUint64("DRAINING_START_TIME")); + tapeDrive.downOrUpStartTime = getOptionalTime(rset->columnOptionalUint64("DOWN_OR_UP_START_TIME")); + tapeDrive.probeStartTime = getOptionalTime(rset->columnOptionalUint64("PROBE_START_TIME")); + tapeDrive.cleanupStartTime = getOptionalTime(rset->columnOptionalUint64("CLEANUP_START_TIME")); + tapeDrive.startStartTime = getOptionalTime(rset->columnOptionalUint64("START_START_TIME")); + tapeDrive.shutdownTime = getOptionalTime(rset->columnOptionalUint64("SHUTDOWN_TIME")); + + tapeDrive.mountType = common::dataStructures::strToMountType(rset->columnString("MOUNT_TYPE")); + tapeDrive.driveStatus = common::dataStructures::TapeDrive::stringToState(rset->columnString("DRIVE_STATUS")); + tapeDrive.desiredUp = rset->columnBool("DESIRED_UP"); + tapeDrive.desiredForceDown = rset->columnBool("DESIRED_FORCE_DOWN"); + tapeDrive.reasonUpDown = rset->columnOptionalString("REASON_UP_DOWN"); + + tapeDrive.currentVid = rset->columnOptionalString("CURRENT_VID"); + tapeDrive.ctaVersion = rset->columnOptionalString("CTA_VERSION"); + tapeDrive.currentPriority = rset->columnOptionalUint64("CURRENT_PRIORITY"); + tapeDrive.currentActivity = rset->columnOptionalString("CURRENT_ACTIVITY"); + tapeDrive.currentTapePool = rset->columnOptionalString("CURRENT_TAPE_POOL"); + tapeDrive.nextMountType = common::dataStructures::strToMountType(rset->columnString("NEXT_MOUNT_TYPE")); + tapeDrive.nextVid = rset->columnOptionalString("NEXT_VID"); + tapeDrive.nextTapePool = rset->columnOptionalString("NEXT_TAPE_POOL"); + tapeDrive.nextPriority = rset->columnOptionalUint64("NEXT_PRIORITY"); + tapeDrive.nextActivity = rset->columnOptionalString("NEXT_ACTIVITY"); + + tapeDrive.devFileName = rset->columnOptionalString("DEV_FILE_NAME"); + tapeDrive.rawLibrarySlot = rset->columnOptionalString("RAW_LIBRARY_SLOT"); + + tapeDrive.currentVo = rset->columnOptionalString("CURRENT_VO"); + tapeDrive.nextVo = rset->columnOptionalString("NEXT_VO"); + + tapeDrive.diskSystemName = rset->columnOptionalString("DISK_SYSTEM_NAME"); + tapeDrive.reservedBytes = rset->columnOptionalUint64("RESERVED_BYTES"); + tapeDrive.reservationSessionId = rset->columnOptionalUint64("RESERVATION_SESSION_ID"); + + tapeDrive.userComment = rset->columnOptionalString("USER_COMMENT"); + auto setOptionEntryLog = [&rset](const std::string &username, const std::string &host, + const std::string &time) -> std::optional<common::dataStructures::EntryLog> { + if (!rset->columnOptionalString(username)) { + return std::nullopt; + } else { + return common::dataStructures::EntryLog( + rset->columnString(username), + rset->columnString(host), + rset->columnUint64(time)); + } + }; + tapeDrive.creationLog = setOptionEntryLog("CREATION_LOG_USER_NAME", "CREATION_LOG_HOST_NAME", + "CREATION_LOG_TIME"); + tapeDrive.lastModificationLog = setOptionEntryLog("LAST_UPDATE_USER_NAME", "LAST_UPDATE_HOST_NAME", + "LAST_UPDATE_TIME"); + + // Log warning for operators that tape drive logical library does not exist (cta/CTA#1163) + if (!rset->columnOptionalBool("IS_DISABLED")) { + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("driveName", tapeDrive.driveName) + .add("logicalLibrary", tapeDrive.logicalLibrary); + lc.log(log::WARNING, "RdbmsCatalogue::gettingSqlTapeDriveValues(): Logical library for tape drive does not exist in the catalogue"); + } + return tapeDrive; +} + +std::list<common::dataStructures::TapeDrive> RdbmsDriveStateCatalogue::getTapeDrives() const { + try { + std::list<common::dataStructures::TapeDrive> tapeDrives; + const char *const sql = + "SELECT " + "DRIVE_STATE.DRIVE_NAME AS DRIVE_NAME," + "DRIVE_STATE.HOST AS HOST," + "DRIVE_STATE.LOGICAL_LIBRARY AS LOGICAL_LIBRARY," + "DRIVE_STATE.SESSION_ID AS SESSION_ID," + + "DRIVE_STATE.BYTES_TRANSFERED_IN_SESSION AS BYTES_TRANSFERED_IN_SESSION," + "DRIVE_STATE.FILES_TRANSFERED_IN_SESSION AS FILES_TRANSFERED_IN_SESSION," + + "DRIVE_STATE.SESSION_START_TIME AS SESSION_START_TIME," + "DRIVE_STATE.SESSION_ELAPSED_TIME AS SESSION_ELAPSED_TIME," + "DRIVE_STATE.MOUNT_START_TIME AS MOUNT_START_TIME," + "DRIVE_STATE.TRANSFER_START_TIME AS TRANSFER_START_TIME," + "DRIVE_STATE.UNLOAD_START_TIME AS UNLOAD_START_TIME," + "DRIVE_STATE.UNMOUNT_START_TIME AS UNMOUNT_START_TIME," + "DRIVE_STATE.DRAINING_START_TIME AS DRAINING_START_TIME," + "DRIVE_STATE.DOWN_OR_UP_START_TIME AS DOWN_OR_UP_START_TIME," + "DRIVE_STATE.PROBE_START_TIME AS PROBE_START_TIME," + "DRIVE_STATE.CLEANUP_START_TIME AS CLEANUP_START_TIME," + "DRIVE_STATE.START_START_TIME AS START_START_TIME," + "DRIVE_STATE.SHUTDOWN_TIME AS SHUTDOWN_TIME," + + "DRIVE_STATE.MOUNT_TYPE AS MOUNT_TYPE," + "DRIVE_STATE.DRIVE_STATUS AS DRIVE_STATUS," + "DRIVE_STATE.DESIRED_UP AS DESIRED_UP," + "DRIVE_STATE.DESIRED_FORCE_DOWN AS DESIRED_FORCE_DOWN," + "DRIVE_STATE.REASON_UP_DOWN AS REASON_UP_DOWN," + + "DRIVE_STATE.CURRENT_VID AS CURRENT_VID," + "DRIVE_STATE.CTA_VERSION AS CTA_VERSION," + "DRIVE_STATE.CURRENT_PRIORITY AS CURRENT_PRIORITY," + "DRIVE_STATE.CURRENT_ACTIVITY AS CURRENT_ACTIVITY," + "DRIVE_STATE.CURRENT_TAPE_POOL AS CURRENT_TAPE_POOL," + "DRIVE_STATE.NEXT_MOUNT_TYPE AS NEXT_MOUNT_TYPE," + "DRIVE_STATE.NEXT_VID AS NEXT_VID," + "DRIVE_STATE.NEXT_TAPE_POOL AS NEXT_TAPE_POOL," + "DRIVE_STATE.NEXT_PRIORITY AS NEXT_PRIORITY," + "DRIVE_STATE.NEXT_ACTIVITY AS NEXT_ACTIVITY," + + "DRIVE_STATE.DEV_FILE_NAME AS DEV_FILE_NAME," + "DRIVE_STATE.RAW_LIBRARY_SLOT AS RAW_LIBRARY_SLOT," + + "DRIVE_STATE.CURRENT_VO AS CURRENT_VO," + "DRIVE_STATE.NEXT_VO AS NEXT_VO," + "DRIVE_STATE.USER_COMMENT AS USER_COMMENT," + + "DRIVE_STATE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "DRIVE_STATE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "DRIVE_STATE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "DRIVE_STATE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "DRIVE_STATE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "DRIVE_STATE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," + + "DRIVE_STATE.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," + "DRIVE_STATE.RESERVED_BYTES AS RESERVED_BYTES," + "DRIVE_STATE.RESERVATION_SESSION_ID AS RESERVATION_SESSION_ID," + "LOGICAL_LIBRARY.IS_DISABLED AS IS_DISABLED " + "FROM " + "DRIVE_STATE " + "LEFT JOIN " + "LOGICAL_LIBRARY " + "ON " + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = DRIVE_STATE.LOGICAL_LIBRARY " + "ORDER BY " + "DRIVE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + + while (rset.next()) { + auto tapeDrive = gettingSqlTapeDriveValues(&rset); + tapeDrives.push_back(tapeDrive); + } + return tapeDrives; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<common::dataStructures::TapeDrive> RdbmsDriveStateCatalogue::getTapeDrive( + const std::string &tapeDriveName) const { + try { + const char *const sql = + "SELECT " + "DRIVE_STATE.DRIVE_NAME AS DRIVE_NAME," + "DRIVE_STATE.HOST AS HOST," + "DRIVE_STATE.LOGICAL_LIBRARY AS LOGICAL_LIBRARY," + "DRIVE_STATE.SESSION_ID AS SESSION_ID," + + "DRIVE_STATE.BYTES_TRANSFERED_IN_SESSION AS BYTES_TRANSFERED_IN_SESSION," + "DRIVE_STATE.FILES_TRANSFERED_IN_SESSION AS FILES_TRANSFERED_IN_SESSION," + + "DRIVE_STATE.SESSION_START_TIME AS SESSION_START_TIME," + "DRIVE_STATE.SESSION_ELAPSED_TIME AS SESSION_ELAPSED_TIME," + "DRIVE_STATE.MOUNT_START_TIME AS MOUNT_START_TIME," + "DRIVE_STATE.TRANSFER_START_TIME AS TRANSFER_START_TIME," + "DRIVE_STATE.UNLOAD_START_TIME AS UNLOAD_START_TIME," + "DRIVE_STATE.UNMOUNT_START_TIME AS UNMOUNT_START_TIME," + "DRIVE_STATE.DRAINING_START_TIME AS DRAINING_START_TIME," + "DRIVE_STATE.DOWN_OR_UP_START_TIME AS DOWN_OR_UP_START_TIME," + "DRIVE_STATE.PROBE_START_TIME AS PROBE_START_TIME," + "DRIVE_STATE.CLEANUP_START_TIME AS CLEANUP_START_TIME," + "DRIVE_STATE.START_START_TIME AS START_START_TIME," + "DRIVE_STATE.SHUTDOWN_TIME AS SHUTDOWN_TIME," + + "DRIVE_STATE.MOUNT_TYPE AS MOUNT_TYPE," + "DRIVE_STATE.DRIVE_STATUS AS DRIVE_STATUS," + "DRIVE_STATE.DESIRED_UP AS DESIRED_UP," + "DRIVE_STATE.DESIRED_FORCE_DOWN AS DESIRED_FORCE_DOWN," + "DRIVE_STATE.REASON_UP_DOWN AS REASON_UP_DOWN," + + "DRIVE_STATE.CURRENT_VID AS CURRENT_VID," + "DRIVE_STATE.CTA_VERSION AS CTA_VERSION," + "DRIVE_STATE.CURRENT_PRIORITY AS CURRENT_PRIORITY," + "DRIVE_STATE.CURRENT_ACTIVITY AS CURRENT_ACTIVITY," + "DRIVE_STATE.CURRENT_TAPE_POOL AS CURRENT_TAPE_POOL," + "DRIVE_STATE.NEXT_MOUNT_TYPE AS NEXT_MOUNT_TYPE," + "DRIVE_STATE.NEXT_VID AS NEXT_VID," + "DRIVE_STATE.NEXT_TAPE_POOL AS NEXT_TAPE_POOL," + "DRIVE_STATE.NEXT_PRIORITY AS NEXT_PRIORITY," + "DRIVE_STATE.NEXT_ACTIVITY AS NEXT_ACTIVITY," + + "DRIVE_STATE.DEV_FILE_NAME AS DEV_FILE_NAME," + "DRIVE_STATE.RAW_LIBRARY_SLOT AS RAW_LIBRARY_SLOT," + + "DRIVE_STATE.CURRENT_VO AS CURRENT_VO," + "DRIVE_STATE.NEXT_VO AS NEXT_VO," + "DRIVE_STATE.USER_COMMENT AS USER_COMMENT," + + "DRIVE_STATE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "DRIVE_STATE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "DRIVE_STATE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "DRIVE_STATE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "DRIVE_STATE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "DRIVE_STATE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME," + + "DRIVE_STATE.DISK_SYSTEM_NAME AS DISK_SYSTEM_NAME," + "DRIVE_STATE.RESERVED_BYTES AS RESERVED_BYTES," + "DRIVE_STATE.RESERVATION_SESSION_ID AS RESERVATION_SESSION_ID," + "LOGICAL_LIBRARY.IS_DISABLED AS IS_DISABLED " + "FROM " + "DRIVE_STATE " + "LEFT JOIN " + "LOGICAL_LIBRARY " + "ON " + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = DRIVE_STATE.LOGICAL_LIBRARY " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DRIVE_NAME", tapeDriveName); + auto rset = stmt.executeQuery(); + + if (rset.next()) { + return gettingSqlTapeDriveValues(&rset); + } + return std::nullopt; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveStateCatalogue::setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) { + try { + CatalogueUtils::checkCommentOrReasonMaxLength(desiredState.reason, m_log); + std::string sql = + "UPDATE DRIVE_STATE SET " + "DESIRED_UP = :DESIRED_UP," + "DESIRED_FORCE_DOWN = :DESIRED_FORCE_DOWN,"; + if (desiredState.reason) { + sql += "REASON_UP_DOWN = "; + sql += desiredState.reason.value().empty() ? "''," : ":REASON_UP_DOWN,"; + } + + // Remove last ',' character + sql.erase(sql.find_last_of(','), 1); + sql += " WHERE " + "DRIVE_NAME = :DRIVE_NAME"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql.c_str()); + + stmt.bindString(":DRIVE_NAME", tapeDriveName); + stmt.bindBool(":DESIRED_UP", desiredState.up); + stmt.bindBool(":DESIRED_FORCE_DOWN", desiredState.forceDown); + if (desiredState.reason && !desiredState.reason.value().empty()) { + stmt.bindString(":REASON_UP_DOWN", desiredState.reason.value()); + } + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify Tape Drive: ") + tapeDriveName + + " because it doesn't exist"); + } + } catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveStateCatalogue::setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) { + try { + const char* const sql = + "UPDATE DRIVE_STATE " + "SET " + "USER_COMMENT = :USER_COMMENT " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + auto bindOptionalStringIfSet = [&stmt](const std::string& sqlField, + const std::optional<std::string>& optionalString) { + if (optionalString) { + if (optionalString.value().empty()) { + stmt.bindString(sqlField, std::nullopt); + } else { + stmt.bindString(sqlField, optionalString.value()); + } + } + }; + + stmt.bindString(":DRIVE_NAME", tapeDriveName); + bindOptionalStringIfSet(":USER_COMMENT", comment); + + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify Tape Drive: ") + tapeDriveName + + " because it doesn't exist"); + } + } catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveStateCatalogue::updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) { + try { + const char *const sql = + "UPDATE DRIVE_STATE " + "SET " + "HOST = :HOST," + "LOGICAL_LIBRARY = :LOGICAL_LIBRARY," + "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," + "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," + "SESSION_ELAPSED_TIME = :REPORT_TIME-SESSION_START_TIME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME AND DRIVE_STATUS = 'TRANSFERING'"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DRIVE_NAME", tapeDriveName); + stmt.bindString(":HOST", host); + stmt.bindString(":LOGICAL_LIBRARY", logicalLibrary); + stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", statistics.bytesTransferedInSession); + stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", statistics.filesTransferedInSession); + stmt.bindUint64(":REPORT_TIME", statistics.reportTime); + stmt.bindString(":LAST_UPDATE_USER_NAME", statistics.lastModificationLog.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", statistics.lastModificationLog.host); + stmt.bindUint64(":LAST_UPDATE_TIME", statistics.lastModificationLog.time); + + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + log::LogContext lc(m_log); + lc.log(log::DEBUG, "RdbmsCatalogue::updateTapeDriveStatistics(): It didn't update statistics"); + } + } catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsDriveStateCatalogue::updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) { + try { + const std::string driveStatusStr = common::dataStructures::TapeDrive::stateToString(tapeDrive.driveStatus); + + // Case 1 : Drive status stays the same + std::string sql = + "UPDATE DRIVE_STATE SET " + "HOST = :HOST," + "LOGICAL_LIBRARY = :LOGICAL_LIBRARY,"; + + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Transferring) { + sql += + "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," + "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," + "SESSION_ELAPSED_TIME = CASE WHEN SESSION_START_TIME IS NULL THEN 0 ELSE :REPORT_TIME - SESSION_START_TIME END,"; + } + sql += + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME AND DRIVE_STATUS = :DRIVE_STATUS"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql.c_str()); + + stmt.bindString(":DRIVE_NAME", tapeDrive.driveName); + stmt.bindString(":HOST", tapeDrive.host); + stmt.bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); + stmt.bindString(":DRIVE_STATUS", driveStatusStr); + stmt.bindString(":LAST_UPDATE_USER_NAME", tapeDrive.lastModificationLog.value().username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", tapeDrive.lastModificationLog.value().host); + stmt.bindUint64(":LAST_UPDATE_TIME", tapeDrive.lastModificationLog.value().time); + + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Transferring) { + stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession.value()); + stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession.value()); + stmt.bindUint64(":REPORT_TIME", tapeDrive.transferStartTime.value()); + } + stmt.executeNonQuery(); + + // If the update succeeded, we are done. Otherwise proceed to Case 2. + if (stmt.getNbAffectedRows() > 0) return; + + // Case 2 : Drive status is changing + sql = + "UPDATE DRIVE_STATE SET " + "HOST = :HOST," + "LOGICAL_LIBRARY = :LOGICAL_LIBRARY," + "SESSION_ID = :SESSION_ID," + "BYTES_TRANSFERED_IN_SESSION = :BYTES_TRANSFERED_IN_SESSION," + "FILES_TRANSFERED_IN_SESSION = :FILES_TRANSFERED_IN_SESSION," + "TRANSFER_START_TIME = :TRANSFER_START_TIME," + "SESSION_ELAPSED_TIME = :SESSION_ELAPSED_TIME," + "UNLOAD_START_TIME = :UNLOAD_START_TIME," + "UNMOUNT_START_TIME = :UNMOUNT_START_TIME," + "DRAINING_START_TIME = :DRAINING_START_TIME," + "DOWN_OR_UP_START_TIME = :DOWN_OR_UP_START_TIME," + "PROBE_START_TIME = :PROBE_START_TIME," + "CLEANUP_START_TIME = :CLEANUP_START_TIME," + "SHUTDOWN_TIME = :SHUTDOWN_TIME," + "MOUNT_TYPE = :MOUNT_TYPE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME,"; + + if (tapeDrive.driveStatus != common::dataStructures::DriveStatus::Transferring) { + if (tapeDrive.driveStatus != common::dataStructures::DriveStatus::Mounting) { + sql += "SESSION_START_TIME = :SESSION_START_TIME,"; + } + sql += "MOUNT_START_TIME = :MOUNT_START_TIME,"; + } + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Starting) { + sql += "START_START_TIME = :START_START_TIME,"; + } + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Down) { + sql += "DESIRED_UP = :DESIRED_UP," + "DESIRED_FORCE_DOWN = :DESIRED_FORCE_DOWN,"; + } + // If the drive is a state incompatible with space reservation, make sure there is none: + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Up) { + sql += "DISK_SYSTEM_NAME = NULL,"; + sql += "RESERVED_BYTES = NULL,"; + sql += "RESERVATION_SESSION_ID = NULL,"; + sql += "DRIVE_STATUS = CASE WHEN DESIRED_UP = '0' THEN 'DOWN' ELSE 'UP' END,"; + } else { + sql += "DRIVE_STATUS = '" + driveStatusStr + "',"; + } + if (tapeDrive.reasonUpDown) { + sql += "REASON_UP_DOWN = :REASON_UP_DOWN,"; + } + if (tapeDrive.currentVid) { + sql += "CURRENT_VID = :CURRENT_VID,"; + } + if (tapeDrive.currentActivity) { + sql += "CURRENT_ACTIVITY = :CURRENT_ACTIVITY,"; + } + if (tapeDrive.currentTapePool) { + sql += "CURRENT_TAPE_POOL = :CURRENT_TAPE_POOL,"; + } + if (tapeDrive.currentVo) { + sql += "CURRENT_VO = :CURRENT_VO,"; + } + if (tapeDrive.userComment) { + sql += "USER_COMMENT = :USER_COMMENT,"; + } + // Remove last ',' character + sql.erase(sql.find_last_of(','), 1); + sql += + " WHERE " + "DRIVE_NAME = :DRIVE_NAME"; + + stmt.reset(); + stmt = conn.createStmt(sql.c_str()); + + auto setOptionalTime = [&stmt](const std::string& sqlField, const std::optional<time_t>& optionalField) { + if (optionalField) { + stmt.bindUint64(sqlField, optionalField.value()); + } else { + stmt.bindUint64(sqlField, std::nullopt); + } + }; + auto bindOptionalStringIfSet = [&stmt](const std::string& sqlField, const std::optional<std::string>& optionalString) { + if (optionalString) { + if (optionalString.value().empty()) { + stmt.bindString(sqlField, std::nullopt); + } else { + stmt.bindString(sqlField, optionalString.value()); + } + } + }; + + stmt.bindString(":HOST", tapeDrive.host); + stmt.bindString(":LOGICAL_LIBRARY", tapeDrive.logicalLibrary); + stmt.bindUint64(":SESSION_ID", tapeDrive.sessionId); + stmt.bindUint64(":BYTES_TRANSFERED_IN_SESSION", tapeDrive.bytesTransferedInSession); + stmt.bindUint64(":FILES_TRANSFERED_IN_SESSION", tapeDrive.filesTransferedInSession); + setOptionalTime(":TRANSFER_START_TIME", tapeDrive.transferStartTime); + setOptionalTime(":SESSION_ELAPSED_TIME", tapeDrive.sessionElapsedTime); + setOptionalTime(":UNLOAD_START_TIME", tapeDrive.unloadStartTime); + setOptionalTime(":UNMOUNT_START_TIME", tapeDrive.unmountStartTime); + setOptionalTime(":DRAINING_START_TIME", tapeDrive.drainingStartTime); + setOptionalTime(":DOWN_OR_UP_START_TIME", tapeDrive.downOrUpStartTime); + setOptionalTime(":PROBE_START_TIME", tapeDrive.probeStartTime); + setOptionalTime(":CLEANUP_START_TIME", tapeDrive.cleanupStartTime); + setOptionalTime(":SHUTDOWN_TIME", tapeDrive.shutdownTime); + stmt.bindString(":MOUNT_TYPE", toString(tapeDrive.mountType)); + stmt.bindString(":LAST_UPDATE_USER_NAME", tapeDrive.lastModificationLog.value().username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", tapeDrive.lastModificationLog.value().host); + stmt.bindUint64(":LAST_UPDATE_TIME", tapeDrive.lastModificationLog.value().time); + + if (tapeDrive.driveStatus != common::dataStructures::DriveStatus::Transferring) { + if (tapeDrive.driveStatus != common::dataStructures::DriveStatus::Mounting) { + setOptionalTime(":SESSION_START_TIME", tapeDrive.sessionStartTime); + } + setOptionalTime(":MOUNT_START_TIME", tapeDrive.mountStartTime); + } + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Starting) { + setOptionalTime(":START_START_TIME", tapeDrive.startStartTime); + } + if (tapeDrive.driveStatus == common::dataStructures::DriveStatus::Down) { + stmt.bindBool(":DESIRED_UP", tapeDrive.desiredUp); + stmt.bindBool(":DESIRED_FORCE_DOWN", tapeDrive.desiredForceDown); + } + bindOptionalStringIfSet(":REASON_UP_DOWN", tapeDrive.reasonUpDown); + bindOptionalStringIfSet(":CURRENT_VID", tapeDrive.currentVid); + bindOptionalStringIfSet(":CURRENT_ACTIVITY", tapeDrive.currentActivity); + bindOptionalStringIfSet(":CURRENT_TAPE_POOL", tapeDrive.currentTapePool); + bindOptionalStringIfSet(":CURRENT_VO", tapeDrive.currentVo); + bindOptionalStringIfSet(":USER_COMMENT", tapeDrive.userComment); + stmt.bindString(":DRIVE_NAME", tapeDrive.driveName); + + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot update status for drive ") + tapeDrive.driveName + ". Drive not found."); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getDiskSpaceReservations +//------------------------------------------------------------------------------ +std::map<std::string, uint64_t> RdbmsDriveStateCatalogue::getDiskSpaceReservations() const { + std::map<std::string, uint64_t> ret; + const auto tdNames = getTapeDriveNames(); + for (const auto& driveName : tdNames) { + const auto tdStatus = getTapeDrive(driveName); + if (tdStatus.value().diskSystemName) { + // no need to check key, operator[] initializes missing values at zero for scalar types + ret[tdStatus.value().diskSystemName.value()] += tdStatus.value().reservedBytes.value(); + } + } + return ret; +} + +//------------------------------------------------------------------------------ +// reserveDiskSpace +//------------------------------------------------------------------------------ +void RdbmsDriveStateCatalogue::reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + if (diskSpaceReservation.empty()) return; + + try { + { + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::DEBUG, "In RetrieveMount::reserveDiskSpace(): reservation request."); + } + + // Normally the disk system name will not change. It can change in some rare circumstances, e.g. the tape server is + // assigned to a new VO. + // + // The disk system name is allowed to be updated when RESERVED_BYTES is zero (initial disk reservation, or previous + // disk reservations have been released). Otherwise, to update RESERVED_BYTES, the disk system name has to match. + const char* const sql = + "UPDATE DRIVE_STATE SET " + "RESERVED_BYTES = RESERVED_BYTES + :BYTES_TO_ADD " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME " + "AND DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME " + "AND RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID "; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DRIVE_NAME", driveName); + stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); + stmt.bindUint64(":BYTES_TO_ADD", diskSpaceReservation.begin()->second); + stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); + stmt.executeNonQuery(); + + // If the reservation does not match the <driveName, diskSystem> pair in the DRIVE_STATE table, + // log an error and drop the previous reservation + if (stmt.getNbAffectedRows() != 1) { + { + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::INFO, "In RetrieveMount::releaseDiskSpace(): creating reservation for new mount"); + } + const char* const sql_reset = + "UPDATE DRIVE_STATE SET " + "DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME," + "RESERVED_BYTES = :BYTES_TO_ADD," + "RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME"; + stmt.reset(); + stmt = conn.createStmt(sql_reset); + stmt.bindString(":DRIVE_NAME", driveName); + stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); + stmt.bindUint64(":BYTES_TO_ADD", diskSpaceReservation.begin()->second); + stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); + stmt.executeNonQuery(); + if (stmt.getNbAffectedRows() != 1) { + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::ERR, "In RetrieveMount::releaseDiskSpace(): failed to create disk reservation for new mount."); + } + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// releaseDiskSpace +//------------------------------------------------------------------------------ +void RdbmsDriveStateCatalogue::releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + if (diskSpaceReservation.empty()) return; + + try { + { + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::DEBUG, "In RetrieveMount::releaseDiskSpace(): reservation release request."); + } + + // If the amount being released exceeds the amount of the reservation, set the reservation to zero + const char* const sql = + "UPDATE DRIVE_STATE SET " + "RESERVED_BYTES = CASE WHEN RESERVED_BYTES > :BYTES_TO_SUBTRACT1 THEN RESERVED_BYTES-:BYTES_TO_SUBTRACT2 ELSE 0 END " + "WHERE " + "DRIVE_NAME = :DRIVE_NAME " + "AND DISK_SYSTEM_NAME = :DISK_SYSTEM_NAME " + "AND RESERVATION_SESSION_ID = :RESERVATION_SESSION_ID"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DRIVE_NAME", driveName); + stmt.bindString(":DISK_SYSTEM_NAME", diskSpaceReservation.begin()->first); + stmt.bindUint64(":BYTES_TO_SUBTRACT1", diskSpaceReservation.begin()->second); + stmt.bindUint64(":BYTES_TO_SUBTRACT2", diskSpaceReservation.begin()->second); + stmt.bindUint64(":RESERVATION_SESSION_ID", mountId); + stmt.executeNonQuery(); + if (stmt.getNbAffectedRows() != 1) { + // If the reservation does not match the <driveName, diskSystem> pair in the DRIVE_STATE table, log an error and carry on + log::ScopedParamContainer params(lc); + params.add("driveName", driveName) + .add("diskSystem", diskSpaceReservation.begin()->first) + .add("reservationBytes", diskSpaceReservation.begin()->second) + .add("mountId", mountId); + lc.log(log::ERR, "In RetrieveMount::releaseDiskSpace(): reservation release request failed, driveName, diskSystem and mountId do not match."); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsDriveStateCatalogue.hpp b/catalogue/rdbms/RdbmsDriveStateCatalogue.hpp new file mode 100644 index 0000000000..697b8dbc08 --- /dev/null +++ b/catalogue/rdbms/RdbmsDriveStateCatalogue.hpp @@ -0,0 +1,92 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveStateCatalogue.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { + +// namespace log { +// class Logger; +// } + +namespace rdbms { +class ConnPool; +class Login; +class Rset; +class Stmt; +} + +namespace catalogue { + +class RdbmsDriveStateCatalogue : public DriveStateCatalogue { +public: + RdbmsDriveStateCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsDriveStateCatalogue() override = default; + + void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) override; + + std::list<std::string> getTapeDriveNames() const override; + + std::list<common::dataStructures::TapeDrive> getTapeDrives() const override; + + std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const override; + + void setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) override; + + void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) override; + + void updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) override; + + void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) override; + + void deleteTapeDrive(const std::string &tapeDriveName) override; + + std::map<std::string, uint64_t> getDiskSpaceReservations() const override; + + void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + + void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + +private: + log::Logger &m_log; + + std::shared_ptr<rdbms::ConnPool> m_connPool; + + void settingSqlTapeDriveValues(cta::rdbms::Stmt *stmt, const common::dataStructures::TapeDrive &tapeDrive) const; + + common::dataStructures::TapeDrive gettingSqlTapeDriveValues(cta::rdbms::Rset* rset) const; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.cpp b/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.cpp new file mode 100644 index 0000000000..8da3d6387e --- /dev/null +++ b/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.cpp @@ -0,0 +1,389 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> +#include <utility> + +#include "catalogue/ArchiveFileRow.hpp" +#include "catalogue/ArchiveFileRowWithoutTimestamps.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueGetFileRecycleLogItor.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsFileRecycleLogCatalogue::RdbmsFileRecycleLogCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) { +} + +FileRecycleLogItor RdbmsFileRecycleLogCatalogue::getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria) const { + try { + auto conn = m_rdbmsCatalogue->m_archiveFileListingConnPool->getConn(); + checkRecycleTapeFileSearchCriteria(conn, searchCriteria); + const auto tempDiskFxidsTableName = m_rdbmsCatalogue->createAndPopulateTempTableFxid( + conn, searchCriteria.diskFileIds); + auto impl = new RdbmsCatalogueGetFileRecycleLogItor(m_log, std::move(conn), searchCriteria, tempDiskFxidsTableName); + return FileRecycleLogItor(impl); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) { + try { + auto fileRecycleLogitor = getFileRecycleLogItor(searchCriteria); + auto conn = m_connPool->getConn(); + log::LogContext lc(m_log); + restoreEntryInRecycleLog(conn, fileRecycleLogitor, newFid, lc); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::restoreArchiveFileInRecycleLog(rdbms::Conn &conn, + const cta::common::dataStructures::FileRecycleLog &fileRecycleLog, const std::string &newFid, log::LogContext & lc) { + cta::catalogue::ArchiveFileRowWithoutTimestamps row; + row.diskFileId = newFid; + row.archiveFileId = fileRecycleLog.archiveFileId; + row.checksumBlob = fileRecycleLog.checksumBlob; + row.diskFileOwnerUid = fileRecycleLog.diskFileUid; + row.diskFileGid = fileRecycleLog.diskFileGid; + row.diskInstance = fileRecycleLog.diskInstanceName; + row.size = fileRecycleLog.sizeInBytes; + row.storageClassName = fileRecycleLog.storageClassName; + static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get())->insertArchiveFile(conn, row); +} + +void RdbmsFileRecycleLogCatalogue::checkRecycleTapeFileSearchCriteria(cta::rdbms::Conn &conn, + const RecycleTapeFileSearchCriteria & searchCriteria) const { + if (searchCriteria.vid) { + if (!RdbmsCatalogueUtils::tapeExists(conn, searchCriteria.vid.value())) { + throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist"); + } + } +} + +void RdbmsFileRecycleLogCatalogue::restoreFileCopyInRecycleLog(rdbms::Conn & conn, + const common::dataStructures::FileRecycleLog &fileRecycleLog, log::LogContext & lc) const { + try { + utils::Timer timer; + log::TimingList timingList; + cta::common::dataStructures::TapeFile tapeFile; + tapeFile.vid = fileRecycleLog.vid; + tapeFile.fSeq = fileRecycleLog.fSeq; + tapeFile.copyNb = fileRecycleLog.copyNb; + tapeFile.blockId = fileRecycleLog.blockId; + tapeFile.fileSize = fileRecycleLog.sizeInBytes; + tapeFile.creationTime = fileRecycleLog.tapeFileCreationTime; + + static_cast<RdbmsTapeFileCatalogue*>(m_rdbmsCatalogue->TapeFile().get())->insertTapeFile(conn, tapeFile, + fileRecycleLog.archiveFileId); + timingList.insertAndReset("insertTapeFileTime", timer); + + deleteTapeFileCopyFromRecycleBin(conn, fileRecycleLog); + timingList.insertAndReset("deleteTapeFileCopyFromRecycleBinTime", timer); + + log::ScopedParamContainer spc(lc); + spc.add("vid", tapeFile.vid); + spc.add("archiveFileId", fileRecycleLog.archiveFileId); + spc.add("fSeq", tapeFile.fSeq); + spc.add("copyNb", tapeFile.copyNb); + spc.add("fileSize", tapeFile.fileSize); + timingList.addToLog(spc); + lc.log(log::INFO, "In RdbmsFileRecycleLogCatalogue::restoreFileCopyInRecycleLog: " + "File restored from the recycle log."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::copyTapeFilesToFileRecycleLog(rdbms::Conn & conn, + const common::dataStructures::ArchiveFile &archiveFile, const std::string &reason) const { + try { + for(auto &tapeFile: archiveFile.tapeFiles) { + //Create one file recycle log entry per tape file + InsertFileRecycleLog fileRecycleLog; + fileRecycleLog.vid = tapeFile.vid; + fileRecycleLog.fSeq = tapeFile.fSeq; + fileRecycleLog.blockId = tapeFile.blockId; + fileRecycleLog.copyNb = tapeFile.copyNb; + fileRecycleLog.tapeFileCreationTime = tapeFile.creationTime; + fileRecycleLog.archiveFileId = archiveFile.archiveFileID; + fileRecycleLog.diskFilePath = archiveFile.diskFileInfo.path; + fileRecycleLog.reasonLog = "(Deleted using cta-admin tf rm) " + reason; + fileRecycleLog.recycleLogTime = time(nullptr); + insertFileInFileRecycleLog(conn, fileRecycleLog); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) { + try { + auto conn = m_connPool->getConn(); + deleteFilesFromRecycleLog(conn,vid,lc); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::deleteFilesFromRecycleLog(rdbms::Conn & conn, const std::string& vid, log::LogContext& lc) { + try { + const char *const deleteFilesFromRecycleLogSql = + "DELETE FROM " + "FILE_RECYCLE_LOG " + "WHERE " + "VID=:VID"; + + cta::utils::Timer t; + log::TimingList tl; + auto selectFileStmt = conn.createStmt(deleteFilesFromRecycleLogSql); + selectFileStmt.bindString(":VID",vid); + selectFileStmt.executeNonQuery(); + uint64_t nbAffectedRows = selectFileStmt.getNbAffectedRows(); + if(nbAffectedRows){ + tl.insertAndReset("deleteFilesFromRecycleLogTime",t); + log::ScopedParamContainer spc(lc); + spc.add("vid",vid); + spc.add("nbFileRecycleLogDeleted",nbAffectedRows); + tl.addToLog(spc); + lc.log(cta::log::INFO,"In RdbmsCatalogue::deleteFilesFromRecycleLog(), file recycle log entries have been deleted."); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +//------------------------------------------------------------------------------ +// deleteTapeFileCopyFromRecycleBin +//------------------------------------------------------------------------------ +void RdbmsFileRecycleLogCatalogue::deleteTapeFileCopyFromRecycleBin(cta::rdbms::Conn & conn, + const common::dataStructures::FileRecycleLog fileRecycleLog) const { + try { + const char *const deleteTapeFilesSql = + "DELETE FROM " + "FILE_RECYCLE_LOG " + "WHERE FILE_RECYCLE_LOG.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID AND FILE_RECYCLE_LOG.VID = :VID AND " + "FILE_RECYCLE_LOG.FSEQ = :FSEQ AND FILE_RECYCLE_LOG.COPY_NB = :COPY_NB AND " + "FILE_RECYCLE_LOG.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME"; + + auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); + deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID", fileRecycleLog.archiveFileId); + deleteTapeFilesStmt.bindString(":VID", fileRecycleLog.vid); + deleteTapeFilesStmt.bindUint64(":FSEQ", fileRecycleLog.fSeq); + deleteTapeFilesStmt.bindUint64(":COPY_NB", fileRecycleLog.copyNb); + deleteTapeFilesStmt.bindString(":DISK_INSTANCE_NAME", fileRecycleLog.diskInstanceName); + deleteTapeFilesStmt.executeNonQuery(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsFileRecycleLogCatalogue::insertFileInFileRecycleLog(rdbms::Conn& conn, + const InsertFileRecycleLog& fileRecycleLog) const { + try{ + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(fileRecycleLog.reasonLog, &m_log); + uint64_t fileRecycleLogId = getNextFileRecyleLogId(conn); + const char *const sql = + "INSERT INTO FILE_RECYCLE_LOG(" + "FILE_RECYCLE_LOG_ID," + "VID," + "FSEQ," + "BLOCK_ID," + "COPY_NB," + "TAPE_FILE_CREATION_TIME," + "ARCHIVE_FILE_ID," + "DISK_INSTANCE_NAME," + "DISK_FILE_ID," + "DISK_FILE_ID_WHEN_DELETED," + "DISK_FILE_UID," + "DISK_FILE_GID," + "SIZE_IN_BYTES," + "CHECKSUM_BLOB," + "CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + "ARCHIVE_FILE_CREATION_TIME," + "RECONCILIATION_TIME," + "COLLOCATION_HINT," + "DISK_FILE_PATH," + "REASON_LOG," + "RECYCLE_LOG_TIME" + ") SELECT " + ":FILE_RECYCLE_LOG_ID," + ":VID," + ":FSEQ," + ":BLOCK_ID," + ":COPY_NB," + ":TAPE_FILE_CREATION_TIME," + ":ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID_2," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "ARCHIVE_FILE.STORAGE_CLASS_ID AS STORAGE_CLASS_ID," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "ARCHIVE_FILE.COLLOCATION_HINT AS COLLOCATION_HINT," + ":DISK_FILE_PATH," + ":REASON_LOG," + ":RECYCLE_LOG_TIME " + "FROM " + "ARCHIVE_FILE " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID_2"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":FILE_RECYCLE_LOG_ID",fileRecycleLogId); + stmt.bindString(":VID",fileRecycleLog.vid); + stmt.bindUint64(":FSEQ",fileRecycleLog.fSeq); + stmt.bindUint64(":BLOCK_ID",fileRecycleLog.blockId); + stmt.bindUint8(":COPY_NB",fileRecycleLog.copyNb); + stmt.bindUint64(":TAPE_FILE_CREATION_TIME",fileRecycleLog.tapeFileCreationTime); + stmt.bindString(":DISK_FILE_PATH",fileRecycleLog.diskFilePath); + stmt.bindUint64(":ARCHIVE_FILE_ID",fileRecycleLog.archiveFileId); + stmt.bindString(":REASON_LOG",fileRecycleLog.reasonLog); + stmt.bindUint64(":RECYCLE_LOG_TIME",fileRecycleLog.recycleLogTime); + stmt.bindUint64(":ARCHIVE_FILE_ID_2",fileRecycleLog.archiveFileId); + stmt.executeNonQuery(); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// copyArchiveFileToFileRecycleLog +//------------------------------------------------------------------------------ +void RdbmsFileRecycleLogCatalogue::copyArchiveFileToFileRecycleLog(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest & request) { + try{ + if(!request.archiveFile){ + throw cta::exception::Exception("No archiveFile object has been set in the DeleteArchiveRequest object."); + } + const common::dataStructures::ArchiveFile & archiveFile = request.archiveFile.value(); + + for(auto &tapeFile: archiveFile.tapeFiles){ + //Create one file recycle log entry per tape file + InsertFileRecycleLog fileRecycleLog; + fileRecycleLog.vid = tapeFile.vid; + fileRecycleLog.fSeq = tapeFile.fSeq; + fileRecycleLog.blockId = tapeFile.blockId; + fileRecycleLog.copyNb = tapeFile.copyNb; + fileRecycleLog.tapeFileCreationTime = tapeFile.creationTime; + fileRecycleLog.archiveFileId = archiveFile.archiveFileID; + fileRecycleLog.diskFilePath = request.diskFilePath; + fileRecycleLog.reasonLog = InsertFileRecycleLog::getDeletionReasonLog(request.requester.name,request.diskInstance); + fileRecycleLog.recycleLogTime = time(nullptr); + insertFileInFileRecycleLog(conn,fileRecycleLog); + } + + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<InsertFileRecycleLog> RdbmsFileRecycleLogCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog( + rdbms::Conn & conn,const common::dataStructures::TapeFile & tapefile, const uint64_t archiveFileId){ + std::list<InsertFileRecycleLog> fileRecycleLogsToInsert; + try { + //First, get the file to insert on the FILE_RECYCLE_LOG table + { + const char *const sql = + "SELECT " + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," + "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " + "FROM " + "TAPE_FILE " + "WHERE " + "TAPE_FILE.COPY_NB=:COPY_NB AND TAPE_FILE.ARCHIVE_FILE_ID=:ARCHIVE_FILE_ID AND (TAPE_FILE.VID<>:VID OR TAPE_FILE.FSEQ<>:FSEQ)"; + + auto stmt = conn.createStmt(sql); + stmt.bindUint8(":COPY_NB",tapefile.copyNb); + stmt.bindUint64(":ARCHIVE_FILE_ID",archiveFileId); + stmt.bindString(":VID",tapefile.vid); + stmt.bindUint64(":FSEQ",tapefile.fSeq); + + auto rset = stmt.executeQuery(); + while(rset.next()){ + cta::catalogue::InsertFileRecycleLog fileRecycleLog; + fileRecycleLog.vid = rset.columnString("VID"); + fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); + fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); + fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); + fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); + fileRecycleLog.recycleLogTime = time(nullptr); + fileRecycleLogsToInsert.push_back(fileRecycleLog); + } + } + { + for(auto & fileRecycleLog: fileRecycleLogsToInsert){ + insertFileInFileRecycleLog(conn, fileRecycleLog); + } + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + return fileRecycleLogsToInsert; +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp b/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..260019f9a7 --- /dev/null +++ b/catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp @@ -0,0 +1,178 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct ArchiveFile; +struct DeleteArchiveRequest; +struct TapeFile; +} // namespace dataStructures +} // namespace common + +namespace log { +class TimingList; +} + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace utils { +class Timer; +} + +namespace catalogue { + +class InsertFileRecycleLog; +class RdbmsCatalogue; + +class RdbmsFileRecycleLogCatalogue : public FileRecycleLogCatalogue { +public: + ~RdbmsFileRecycleLogCatalogue() override = default; + + FileRecycleLogItor getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const override; + + void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) override; + + void deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) override; + +protected: + RdbmsFileRecycleLogCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + /** + * Copy the fileRecycleLog to the ARCHIVE_FILE with a new eos fxid + * @param conn the database connection + * @param fileRecycleLog the fileRecycleLog we want to restore + * @param newFid the new eos file id of the archive file + * @param lc the log context + */ + void restoreArchiveFileInRecycleLog(rdbms::Conn &conn, + const cta::common::dataStructures::FileRecycleLog &fileRecycleLog, + const std::string &newFid, log::LogContext & lc); + + // TapeFile + friend class OracleTapeFileCatalogue; + friend class PostgresTapeFileCatalogue; + friend class SqliteTapeFileCatalogue; + // ArchiveFile + friend class OracleArchiveFileCatalogue; + friend class PostgresArchiveFileCatalogue; + friend class SqliteArchiveFileCatalogue; + /** + * Copies the TAPE_FILE entries to the recycle-bin tables + * @param conn the database connection + * @param file the archiveFile whose tapefiles we want to copy + * @param reason The reason for deleting the tape file copy + */ + void copyTapeFilesToFileRecycleLog(rdbms::Conn & conn, const common::dataStructures::ArchiveFile &file, + const std::string &reason) const; + + void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, + log::LogContext & lc) const; + + + /** + * Copy the files in fileRecycleLogItor to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entries + * @param conn the database connection + * @param fileRecycleLogItor the collection of fileRecycleLogs we want to restore + * @param lc the log context + */ + virtual void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, + const std::string &newFid, log::LogContext & lc) = 0; + + friend class RdbmsTapeFileCatalogue; + + /** + * Returns a unique file recycle log ID that can be used by a new entry of file recycle log 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 file recycle log ID that can be used by a new entry of file recycle log within + * the catalogue. + */ + virtual uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) const = 0; + +protected: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + +private: + /** + * 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(cta::rdbms::Conn &conn, + const RecycleTapeFileSearchCriteria & searchCriteria) const; + + void deleteTapeFileCopyFromRecycleBin(cta::rdbms::Conn & conn, + const common::dataStructures::FileRecycleLog fileRecycleLog) const; + + friend class RdbmsTapeCatalogue; + void deleteFilesFromRecycleLog(rdbms::Conn & conn, const std::string& vid, log::LogContext& lc); + + /** + * Insert the file passed in parameter in the FILE_RECYCLE_LOG table + * @param conn the database connection + * @param fileRecycleLog the file to insert on the FILE_RECYCLE_LOG table + */ + void insertFileInFileRecycleLog(rdbms::Conn & conn, const InsertFileRecycleLog & fileRecycleLog) const; + + /** + * Copies the ARCHIVE_FILE and TAPE_FILE entries to the recycle-bin tables + * @param conn the database connection + * @param request the request that contains the necessary informations to identify the archiveFile to copy to the recycle-bin + */ + void copyArchiveFileToFileRecycleLog(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest & request); + + /** + * In the case we insert a TAPE_FILE that already has a copy on the catalogue (same copyNb), + * this TAPE_FILE will go to the FILE_RECYCLE_LOG table. + * + * This case happens always during the repacking of a tape: the new TAPE_FILE created + * will replace the old one, the old one will then be moved to the FILE_RECYCLE_LOG table + * + * @param conn The database connection. + * @returns the list of inserted fileRecycleLog + */ + std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn, + const common::dataStructures::TapeFile &tapeFile, const uint64_t archiveFileId); +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.cpp b/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.cpp new file mode 100644 index 0000000000..8be68dea41 --- /dev/null +++ b/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.cpp @@ -0,0 +1,361 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <optional> +#include <string> + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp" +#include "common/dataStructures/LogicalLibrary.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "common/log/Logger.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsLogicalLibraryCatalogue::RdbmsLogicalLibraryCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsLogicalLibraryCatalogue::createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool isDisabled, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::logicalLibraryExists(conn, name)) { + throw exception::UserError(std::string("Cannot create logical library ") + name + + " because a logical library with the same name already exists"); + } + const uint64_t logicalLibraryId = getNextLogicalLibraryId(conn); + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO LOGICAL_LIBRARY(" + "LOGICAL_LIBRARY_ID," + "LOGICAL_LIBRARY_NAME," + "IS_DISABLED," + + "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(" + ":LOGICAL_LIBRARY_ID," + ":LOGICAL_LIBRARY_NAME," + ":IS_DISABLED," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindUint64(":LOGICAL_LIBRARY_ID", logicalLibraryId); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.bindBool(":IS_DISABLED", isDisabled); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsLogicalLibraryCatalogue::deleteLogicalLibrary(const std::string &name) { + try { + const char *const sql = + "DELETE FROM LOGICAL_LIBRARY " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME AND " + "NOT EXISTS (" + "SELECT " + "TAPE.LOGICAL_LIBRARY_ID " + "FROM " + "TAPE " + "WHERE " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID)"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.executeNonQuery(); + + // The delete statement will effect no rows and will not raise an error if + // either the logical library does not exist or if it still contains tapes + if(0 == stmt.getNbAffectedRows()) { + if(RdbmsCatalogueUtils::logicalLibraryExists(conn, name)) { + throw UserSpecifiedANonEmptyLogicalLibrary(std::string("Cannot delete logical library ") + name + + " because it contains one or more tapes"); + } else { + throw UserSpecifiedANonExistentLogicalLibrary(std::string("Cannot delete logical library ") + name + + " because it does not exist"); + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::LogicalLibrary> RdbmsLogicalLibraryCatalogue::getLogicalLibraries() const { + try { + std::list<common::dataStructures::LogicalLibrary> libs; + const char *const sql = + "SELECT " + "LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "IS_DISABLED AS IS_DISABLED," + + "USER_COMMENT AS USER_COMMENT," + "DISABLED_REASON AS DISABLED_REASON," + + "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 " + "FROM " + "LOGICAL_LIBRARY " + "ORDER BY " + "LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::LogicalLibrary lib; + + lib.name = rset.columnString("LOGICAL_LIBRARY_NAME"); + lib.isDisabled = rset.columnBool("IS_DISABLED"); + lib.comment = rset.columnString("USER_COMMENT"); + lib.disabledReason = rset.columnOptionalString("DISABLED_REASON"); + lib.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + lib.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + lib.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + lib.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + lib.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + lib.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + libs.push_back(lib); + } + + return libs; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsLogicalLibraryCatalogue::modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + try { + if(currentName.empty()) { + throw UserSpecifiedAnEmptyStringLogicalLibraryName( + "Cannot modify logical library because the logical library name is an empty string"); + } + + if(newName.empty()) { + throw UserSpecifiedAnEmptyStringLogicalLibraryName( + "Cannot modify logical library because the new name is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE LOGICAL_LIBRARY SET " + "LOGICAL_LIBRARY_NAME = :NEW_LOGICAL_LIBRARY_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "LOGICAL_LIBRARY_NAME = :CURRENT_LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":NEW_LOGICAL_LIBRARY_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_LOGICAL_LIBRARY_NAME", currentName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify logical library ") + currentName + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsLogicalLibraryCatalogue::modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE LOGICAL_LIBRARY SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsLogicalLibraryCatalogue::modifyLogicalLibraryDisabledReason( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &disabledReason) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(disabledReason, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE LOGICAL_LIBRARY SET " + "DISABLED_REASON = :DISABLED_REASON," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISABLED_REASON", + disabledReason.empty() ? std::nullopt : std::optional<std::string>(disabledReason)); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsLogicalLibraryCatalogue::setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool disabledValue) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE LOGICAL_LIBRARY SET " + "IS_DISABLED = :IS_DISABLED," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindBool(":IS_DISABLED", disabledValue); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify logical library ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<uint64_t> RdbmsLogicalLibraryCatalogue::getLogicalLibraryId(rdbms::Conn &conn, + const std::string &name) const { + try { + const char *const sql = + "SELECT " + "LOGICAL_LIBRARY_ID AS LOGICAL_LIBRARY_ID " + "FROM " + "LOGICAL_LIBRARY " + "WHERE " + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":LOGICAL_LIBRARY_NAME", name); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + return std::nullopt; + } + return rset.columnUint64("LOGICAL_LIBRARY_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp b/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..feec140f93 --- /dev/null +++ b/catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp @@ -0,0 +1,93 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> + +#include "catalogue/interfaces/LogicalLibraryCatalogue.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace log { +class Logger; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsLogicalLibraryCatalogue: public LogicalLibraryCatalogue { +public: + ~RdbmsLogicalLibraryCatalogue() override = default; + + void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool isDisabled, const std::string &comment) override; + + void deleteLogicalLibrary(const std::string &name) override; + + std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const override; + + void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; + + void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &disabledReason) override; + + void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool disabledValue) override; + +protected: + RdbmsLogicalLibraryCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + /** + * Returns a unique logical library ID that can be used by a new logical + * library 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 logical library ID that can be used by a new logical + * library storage class within the catalogue. + */ + virtual uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) const = 0; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue *m_rdbmsCatalogue; + + friend class RdbmsTapeCatalogue; + std::optional<uint64_t> getLogicalLibraryId(rdbms::Conn &conn, const std::string &name) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsMediaTypeCatalogue.cpp b/catalogue/rdbms/RdbmsMediaTypeCatalogue.cpp new file mode 100644 index 0000000000..55fe09a493 --- /dev/null +++ b/catalogue/rdbms/RdbmsMediaTypeCatalogue.cpp @@ -0,0 +1,624 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsMediaTypeCatalogue::RdbmsMediaTypeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsMediaTypeCatalogue::createMediaType(const common::dataStructures::SecurityIdentity &admin, + const MediaType &mediaType) { + try { + if (mediaType.name.empty()) { + throw UserSpecifiedAnEmptyStringMediaTypeName("Cannot create media type because the media type name is an" + " empty string"); + } + + if (mediaType.cartridge.empty()) { + throw UserSpecifiedAnEmptyStringCartridge(std::string("Cannot create media type ") + mediaType.name + + " because the cartridge is an empty string"); + } + + if (mediaType.comment.empty()) { + throw UserSpecifiedAnEmptyStringComment(std::string("Cannot create media type ") + mediaType.name + + " because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(mediaType.comment, &m_log); + if (mediaType.capacityInBytes == 0){ + throw UserSpecifiedAZeroCapacity(std::string("Cannot create media type ") + mediaType.name + + " because the capacity is zero"); + } + auto conn = m_connPool->getConn(); + if (RdbmsCatalogueUtils::mediaTypeExists(conn, mediaType.name)) { + throw exception::UserError(std::string("Cannot create media type ") + mediaType.name + + " because it already exists"); + } + const uint64_t mediaTypeId = getNextMediaTypeId(conn); + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO MEDIA_TYPE(" + "MEDIA_TYPE_ID," + "MEDIA_TYPE_NAME," + "CARTRIDGE," + "CAPACITY_IN_BYTES," + "PRIMARY_DENSITY_CODE," + "SECONDARY_DENSITY_CODE," + "NB_WRAPS," + "MIN_LPOS," + "MAX_LPOS," + + "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(" + ":MEDIA_TYPE_ID," + ":MEDIA_TYPE_NAME," + ":CARTRIDGE," + ":CAPACITY_IN_BYTES," + ":PRIMARY_DENSITY_CODE," + ":SECONDARY_DENSITY_CODE," + ":NB_WRAPS," + ":MIN_LPOS," + ":MAX_LPOS," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindUint64(":MEDIA_TYPE_ID", mediaTypeId); + stmt.bindString(":MEDIA_TYPE_NAME", mediaType.name); + stmt.bindString(":CARTRIDGE", mediaType.cartridge); + stmt.bindUint64(":CAPACITY_IN_BYTES", mediaType.capacityInBytes); + stmt.bindUint8(":PRIMARY_DENSITY_CODE", mediaType.primaryDensityCode); + stmt.bindUint8(":SECONDARY_DENSITY_CODE", mediaType.secondaryDensityCode); + stmt.bindUint32(":NB_WRAPS", mediaType.nbWraps); + stmt.bindUint64(":MIN_LPOS", mediaType.minLPos); + stmt.bindUint64(":MAX_LPOS", mediaType.maxLPos); + + stmt.bindString(":USER_COMMENT", mediaType.comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::deleteMediaType(const std::string &name) { + try { + auto conn = m_connPool->getConn(); + + if(mediaTypeIsUsedByTapes(conn, name)) { + throw UserSpecifiedMediaTypeUsedByTapes(std::string("The ") + name + + " media type is being used by one or more tapes"); + } + + const char *const sql = + "DELETE FROM" "\n" + "MEDIA_TYPE" "\n" + "WHERE" "\n" + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":MEDIA_TYPE_NAME", name); + + stmt.executeNonQuery(); + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<MediaTypeWithLogs> RdbmsMediaTypeCatalogue::getMediaTypes() const { + try { + std::list<MediaTypeWithLogs> mediaTypes; + const char *const sql = + "SELECT" "\n" + "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME," "\n" + "CARTRIDGE AS CARTRIDGE," "\n" + "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," "\n" + "PRIMARY_DENSITY_CODE AS PRIMARY_DENSITY_CODE," "\n" + "SECONDARY_DENSITY_CODE AS SECONDARY_DENSITY_CODE," "\n" + "NB_WRAPS AS NB_WRAPS," "\n" + "MIN_LPOS AS MIN_LPOS," "\n" + "MAX_LPOS AS MAX_LPOS," "\n" + + "USER_COMMENT AS USER_COMMENT," "\n" + + "CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," "\n" + "CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," "\n" + "CREATION_LOG_TIME AS CREATION_LOG_TIME," "\n" + + "LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," "\n" + "LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," "\n" + "LAST_UPDATE_TIME AS LAST_UPDATE_TIME" "\n" + "FROM" "\n" + "MEDIA_TYPE" "\n" + "ORDER BY" "\n" + "MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + MediaTypeWithLogs mediaType; + + mediaType.name = rset.columnString("MEDIA_TYPE_NAME"); + mediaType.cartridge = rset.columnString("CARTRIDGE"); + mediaType.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + mediaType.primaryDensityCode = rset.columnOptionalUint8("PRIMARY_DENSITY_CODE"); + mediaType.secondaryDensityCode = rset.columnOptionalUint8("SECONDARY_DENSITY_CODE"); + mediaType.nbWraps = rset.columnOptionalUint32("NB_WRAPS"); + mediaType.minLPos = rset.columnOptionalUint64("MIN_LPOS"); + mediaType.maxLPos = rset.columnOptionalUint64("MAX_LPOS"); + mediaType.comment = rset.columnString("USER_COMMENT"); + mediaType.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + mediaType.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + mediaType.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + mediaType.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + mediaType.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + mediaType.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + mediaTypes.push_back(mediaType); + } + + return mediaTypes; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +MediaType RdbmsMediaTypeCatalogue::getMediaTypeByVid(const std::string & vid) const { + try { + std::list<MediaTypeWithLogs> mediaTypes; + const char *const sql = + "SELECT" "\n" + "MEDIA_TYPE_NAME AS MEDIA_TYPE_NAME," "\n" + "CARTRIDGE AS CARTRIDGE," "\n" + "CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," "\n" + "PRIMARY_DENSITY_CODE AS PRIMARY_DENSITY_CODE," "\n" + "SECONDARY_DENSITY_CODE AS SECONDARY_DENSITY_CODE," "\n" + "NB_WRAPS AS NB_WRAPS," "\n" + "MIN_LPOS AS MIN_LPOS," "\n" + "MAX_LPOS AS MAX_LPOS," "\n" + + "MEDIA_TYPE.USER_COMMENT AS USER_COMMENT " "\n" + "FROM" "\n" + "MEDIA_TYPE " "\n" + "INNER JOIN TAPE " "\n" + "ON MEDIA_TYPE.MEDIA_TYPE_ID = TAPE.MEDIA_TYPE_ID " "\n" + "WHERE " "\n" + "TAPE.VID = :VID" "\n"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID",vid); + auto rset = stmt.executeQuery(); + if(rset.next()){ + MediaType mediaType; + + mediaType.name = rset.columnString("MEDIA_TYPE_NAME"); + mediaType.cartridge = rset.columnString("CARTRIDGE"); + mediaType.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + mediaType.primaryDensityCode = rset.columnOptionalUint8("PRIMARY_DENSITY_CODE"); + mediaType.secondaryDensityCode = rset.columnOptionalUint8("SECONDARY_DENSITY_CODE"); + mediaType.nbWraps = rset.columnOptionalUint32("NB_WRAPS"); + mediaType.minLPos = rset.columnOptionalUint64("MIN_LPOS"); + mediaType.maxLPos = rset.columnOptionalUint64("MAX_LPOS"); + mediaType.comment = rset.columnString("USER_COMMENT"); + + return mediaType; + } else { + throw exception::Exception("The tape vid "+vid+" does not exist."); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "MEDIA_TYPE_NAME = :NEW_MEDIA_TYPE_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :CURRENT_MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + if(newName != currentName){ + if(RdbmsCatalogueUtils::mediaTypeExists(conn, newName)){ + throw exception::UserError(std::string("Cannot modify the media type name ") + currentName +". The new name : " + + newName + " already exists in the database."); + } + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":NEW_MEDIA_TYPE_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_MEDIA_TYPE_NAME", currentName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + currentName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &cartridge) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "CARTRIDGE = :CARTRIDGE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":CARTRIDGE", cartridge); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t capacityInBytes) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "CAPACITY_IN_BYTES = :CAPACITY_IN_BYTES," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":CAPACITY_IN_BYTES", capacityInBytes); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t primaryDensityCode) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "PRIMARY_DENSITY_CODE = :PRIMARY_DENSITY_CODE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint8(":PRIMARY_DENSITY_CODE", primaryDensityCode); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t secondaryDensityCode) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "SECONDARY_DENSITY_CODE = :SECONDARY_DENSITY_CODE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint8(":SECONDARY_DENSITY_CODE", secondaryDensityCode); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint32_t> &nbWraps) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "NB_WRAPS = :NB_WRAPS," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint32(":NB_WRAPS", nbWraps); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &minLPos) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "MIN_LPOS = :MIN_LPOS," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":MIN_LPOS", minLPos); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &maxLPos) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "MAX_LPOS = :MAX_LPOS," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":MAX_LPOS", maxLPos); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMediaTypeCatalogue::modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MEDIA_TYPE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MEDIA_TYPE_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify media type ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsMediaTypeCatalogue::mediaTypeIsUsedByTapes(rdbms::Conn &conn, const std::string &name) const { + try { + const char *const sql = + "SELECT " + "MEDIA_TYPE.MEDIA_TYPE_NAME " + "FROM " + "TAPE " + "INNER JOIN " + "MEDIA_TYPE " + "ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "WHERE " + "MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":MEDIA_TYPE_NAME", name); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<uint64_t> RdbmsMediaTypeCatalogue::getMediaTypeId(rdbms::Conn &conn, const std::string &name) const { + try { + const char *const sql = + "SELECT " + "MEDIA_TYPE.MEDIA_TYPE_ID AS MEDIA_TYPE_ID " + "FROM " + "MEDIA_TYPE " + "WHERE " + "MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":MEDIA_TYPE_NAME", name); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + return std::nullopt; + } + return rset.columnUint64("MEDIA_TYPE_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp b/catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp new file mode 100644 index 0000000000..94ad4e3946 --- /dev/null +++ b/catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp @@ -0,0 +1,91 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/MediaTypeCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsMediaTypeCatalogue : public MediaTypeCatalogue { +public: + ~RdbmsMediaTypeCatalogue() override = default; + + void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) override; + + void deleteMediaType(const std::string &name) override; + + std::list<MediaTypeWithLogs> getMediaTypes() const override; + + MediaType getMediaTypeByVid(const std::string & vid) const override; + + void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &cartridge) override; + + void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t capacityInBytes) override; + + void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint8_t primaryDensityCode) override; + + void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t secondaryDensityCode) override; + + void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint32_t> &nbWraps) override; + + void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &minLPos) override; + + void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &maxLPos) override; + + void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + +protected: + RdbmsMediaTypeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue); + + virtual uint64_t getNextMediaTypeId(rdbms::Conn &conn) const = 0; +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + bool mediaTypeIsUsedByTapes(rdbms::Conn &conn, const std::string &name) const; + + friend class RdbmsTapeCatalogue; + std::optional<uint64_t> getMediaTypeId(rdbms::Conn &conn, const std::string &name) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsMountPolicyCatalogue.cpp b/catalogue/rdbms/RdbmsMountPolicyCatalogue.cpp new file mode 100644 index 0000000000..b494941223 --- /dev/null +++ b/catalogue/rdbms/RdbmsMountPolicyCatalogue.cpp @@ -0,0 +1,861 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/MountPolicy.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/Logger.hpp" +#include "common/utils/Regex.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsMountPolicyCatalogue::RdbmsMountPolicyCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsMountPolicyCatalogue::createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) { + std::string name = mountPolicy.name; + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(mountPolicy.comment, &m_log); + auto conn = m_connPool->getConn(); + if (RdbmsCatalogueUtils::mountPolicyExists(conn, name)) { + throw exception::UserError(std::string("Cannot create mount policy ") + name + + " because a mount policy with the same name already exists"); + } + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO MOUNT_POLICY(" + "MOUNT_POLICY_NAME," + + "ARCHIVE_PRIORITY," + "ARCHIVE_MIN_REQUEST_AGE," + + "RETRIEVE_PRIORITY," + "RETRIEVE_MIN_REQUEST_AGE," + + "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(" + ":MOUNT_POLICY_NAME," + + ":ARCHIVE_PRIORITY," + ":ARCHIVE_MIN_REQUEST_AGE," + + ":RETRIEVE_PRIORITY," + ":RETRIEVE_MIN_REQUEST_AGE," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":MOUNT_POLICY_NAME", name); + + stmt.bindUint64(":ARCHIVE_PRIORITY", mountPolicy.archivePriority); + stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", mountPolicy.minArchiveRequestAge); + + stmt.bindUint64(":RETRIEVE_PRIORITY", mountPolicy.retrievePriority); + stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", mountPolicy.minRetrieveRequestAge); + + stmt.bindString(":USER_COMMENT", mountPolicy.comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +void RdbmsMountPolicyCatalogue::deleteMountPolicy(const std::string &name) { + try { + const char *const sql = "DELETE FROM MOUNT_POLICY WHERE MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete mount policy ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +std::list<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getMountPolicies() const { + try { + auto conn = m_connPool->getConn(); + return getMountPolicies(conn); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getMountPolicies(rdbms::Conn & conn) const { +try { + std::list<common::dataStructures::MountPolicy> policies; + const char *const sql = + "SELECT " + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + + "RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + + "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 " + "FROM " + "MOUNT_POLICY " + "ORDER BY " + "MOUNT_POLICY_NAME"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + + policy.comment = rset.columnString("USER_COMMENT"); + + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + policies.push_back(policy); + } + return policies; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getMountPolicy(const std::string &mountPolicyName) const { + try { + auto conn = m_connPool->getConn(); + return getMountPolicy(conn, mountPolicyName); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getMountPolicy(rdbms::Conn &conn, const std::string &mountPolicyName) const { + try { + const char *const sql = + "SELECT " + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + + "RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + + "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 " + "FROM " + "MOUNT_POLICY " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); + auto rset = stmt.executeQuery(); + if (rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + + policy.comment = rset.columnString("USER_COMMENT"); + + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + return policy; + } + return std::nullopt; + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getCachedMountPolicies() const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + return getMountPolicies(conn); + }; + return m_rdbmsCatalogue->m_allMountPoliciesCache.getCachedValue("all",getNonCachedValue).value; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsMountPolicyCatalogue::modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MOUNT_POLICY SET " + "ARCHIVE_PRIORITY = :ARCHIVE_PRIORITY," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_PRIORITY", archivePriority); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +void RdbmsMountPolicyCatalogue::modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minArchiveRequestAge) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MOUNT_POLICY SET " + "ARCHIVE_MIN_REQUEST_AGE = :ARCHIVE_MIN_REQUEST_AGE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_MIN_REQUEST_AGE", minArchiveRequestAge); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +void RdbmsMountPolicyCatalogue::modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MOUNT_POLICY SET " + "RETRIEVE_PRIORITY = :RETRIEVE_PRIORITY," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":RETRIEVE_PRIORITY", retrievePriority); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +void RdbmsMountPolicyCatalogue::modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MOUNT_POLICY SET " + "RETRIEVE_MIN_REQUEST_AGE = :RETRIEVE_MIN_REQUEST_AGE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":RETRIEVE_MIN_REQUEST_AGE", minRetrieveRequestAge); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +void RdbmsMountPolicyCatalogue::modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE MOUNT_POLICY SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":MOUNT_POLICY_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify mount policy ") + name + " because they do not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); + m_rdbmsCatalogue->m_allMountPoliciesCache.invalidate(); +} + +//------------------------------------------------------------------------------ +// getRequesterGroupMountPolicy +//------------------------------------------------------------------------------ +std::optional<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getRequesterGroupMountPolicy( + rdbms::Conn &conn, const Group &group) const { + try { + const char *const sql = + "SELECT " + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "MOUNT_POLICY " + "INNER JOIN " + "REQUESTER_GROUP_MOUNT_RULE " + "ON " + "MOUNT_POLICY.MOUNT_POLICY_NAME = REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", group.diskInstanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", group.groupName); + auto rset = stmt.executeQuery(); + if(rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + + policy.comment = rset.columnString("USER_COMMENT"); + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + return policy; + } else { + return std::nullopt; + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<common::dataStructures::MountPolicy> RdbmsMountPolicyCatalogue::getRequesterMountPolicy(rdbms::Conn &conn, + const User &user) const { + try { + const char *const sql = + "SELECT " + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "MOUNT_POLICY " + "INNER JOIN " + "REQUESTER_MOUNT_RULE " + "ON " + "MOUNT_POLICY.MOUNT_POLICY_NAME = REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", user.diskInstanceName); + stmt.bindString(":REQUESTER_NAME", user.username); + auto rset = stmt.executeQuery(); + if(rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + + policy.comment = rset.columnString("USER_COMMENT"); + + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + + common::dataStructures::EntryLog updateLog; + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + return policy; + } else { + return std::nullopt; + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +RequesterAndGroupMountPolicies RdbmsMountPolicyCatalogue::getMountPolicies( + rdbms::Conn &conn, + const std::string &diskInstanceName, + const std::string &requesterName, + const std::string &requesterGroupName, + const std::string &activity) const { + try { + const char *const sql = + "SELECT " + "'ACTIVITY' AS RULE_TYPE," + "REQUESTER_ACTIVITY_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," + "REQUESTER_ACTIVITY_MOUNT_RULE.ACTIVITY_REGEX AS ACTIVITY_REGEX," + + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "REQUESTER_ACTIVITY_MOUNT_RULE " + "INNER JOIN " + "MOUNT_POLICY " + "ON " + "REQUESTER_ACTIVITY_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_ACTIVITY_MOUNT_RULE.DISK_INSTANCE_NAME = :ACTIVITY_DISK_INSTANCE_NAME AND " + "REQUESTER_ACTIVITY_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_ACTIVITY_NAME " + "UNION " + "SELECT " + "'REQUESTER' AS RULE_TYPE," + "REQUESTER_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," + "'' AS ACTIVITY_REGEX," + + + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "REQUESTER_MOUNT_RULE " + "INNER JOIN " + "MOUNT_POLICY " + "ON " + "REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :REQUESTER_DISK_INSTANCE_NAME AND " + "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME " + "UNION " + "SELECT " + "'REQUESTER_GROUP' AS RULE_TYPE," + "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME AS ASSIGNEE," + "'' AS ACTIVITY_REGEX," + + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "REQUESTER_GROUP_MOUNT_RULE " + "INNER JOIN " + "MOUNT_POLICY " + "ON " + "REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :GROUP_DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":ACTIVITY_DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_ACTIVITY_NAME", requesterName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + auto rset = stmt.executeQuery(); + + RequesterAndGroupMountPolicies policies; + while(rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + policy.comment = rset.columnString("USER_COMMENT"); + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + if(rset.columnString("RULE_TYPE") == "ACTIVITY") { + auto activityRegexString = rset.columnString("ACTIVITY_REGEX"); + cta::utils::Regex activityRegex(activityRegexString); + if (activityRegex.has_match(activity)) { + policies.requesterActivityMountPolicies.push_back(policy); + } + } else if(rset.columnString("RULE_TYPE") == "REQUESTER") { + policies.requesterMountPolicies.push_back(policy); + } else { + policies.requesterGroupMountPolicies.push_back(policy); + } + } + + return policies; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +RequesterAndGroupMountPolicies RdbmsMountPolicyCatalogue::getMountPolicies( + rdbms::Conn &conn, + const std::string &diskInstanceName, + const std::string &requesterName, + const std::string &requesterGroupName) const { + try { + const char *const sql = + "SELECT " + "'REQUESTER' AS RULE_TYPE," + "REQUESTER_MOUNT_RULE.REQUESTER_NAME AS ASSIGNEE," + + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "REQUESTER_MOUNT_RULE " + "INNER JOIN " + "MOUNT_POLICY " + "ON " + "REQUESTER_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_MOUNT_RULE.DISK_INSTANCE_NAME = :REQUESTER_DISK_INSTANCE_NAME AND " + "REQUESTER_MOUNT_RULE.REQUESTER_NAME = :REQUESTER_NAME " + "UNION " + "SELECT " + "'REQUESTER_GROUP' AS RULE_TYPE," + "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME AS ASSIGNEE," + + "MOUNT_POLICY.MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "MOUNT_POLICY.ARCHIVE_PRIORITY AS ARCHIVE_PRIORITY," + "MOUNT_POLICY.ARCHIVE_MIN_REQUEST_AGE AS ARCHIVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.RETRIEVE_PRIORITY AS RETRIEVE_PRIORITY," + "MOUNT_POLICY.RETRIEVE_MIN_REQUEST_AGE AS RETRIEVE_MIN_REQUEST_AGE," + "MOUNT_POLICY.USER_COMMENT AS USER_COMMENT," + "MOUNT_POLICY.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "MOUNT_POLICY.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "MOUNT_POLICY.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "MOUNT_POLICY.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "MOUNT_POLICY.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "MOUNT_POLICY.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "REQUESTER_GROUP_MOUNT_RULE " + "INNER JOIN " + "MOUNT_POLICY " + "ON " + "REQUESTER_GROUP_MOUNT_RULE.MOUNT_POLICY_NAME = MOUNT_POLICY.MOUNT_POLICY_NAME " + "WHERE " + "REQUESTER_GROUP_MOUNT_RULE.DISK_INSTANCE_NAME = :GROUP_DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_MOUNT_RULE.REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":REQUESTER_DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":GROUP_DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + auto rset = stmt.executeQuery(); + + RequesterAndGroupMountPolicies policies; + while(rset.next()) { + common::dataStructures::MountPolicy policy; + + policy.name = rset.columnString("MOUNT_POLICY_NAME"); + policy.archivePriority = rset.columnUint64("ARCHIVE_PRIORITY"); + policy.archiveMinRequestAge = rset.columnUint64("ARCHIVE_MIN_REQUEST_AGE"); + policy.retrievePriority = rset.columnUint64("RETRIEVE_PRIORITY"); + policy.retrieveMinRequestAge = rset.columnUint64("RETRIEVE_MIN_REQUEST_AGE"); + policy.comment = rset.columnString("USER_COMMENT"); + policy.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + policy.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + policy.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + policy.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + policy.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + policy.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + if(rset.columnString("RULE_TYPE") == "REQUESTER") { + policies.requesterMountPolicies.push_back(policy); + } else { + policies.requesterGroupMountPolicies.push_back(policy); + } + } + + return policies; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp b/catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp new file mode 100644 index 0000000000..6076acffba --- /dev/null +++ b/catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp @@ -0,0 +1,153 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> + +#include "catalogue/interfaces/MountPolicyCatalogue.hpp" +#include "catalogue/RequesterAndGroupMountPolicies.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsMountPolicyCatalogue : public MountPolicyCatalogue { +public: + RdbmsMountPolicyCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + ~RdbmsMountPolicyCatalogue() override = default; + + void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) override; + + std::list<common::dataStructures::MountPolicy> getMountPolicies() const override; + + std::optional<common::dataStructures::MountPolicy> getMountPolicy( + const std::string &mountPolicyName) const override; + + std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const override; + + void deleteMountPolicy(const std::string &name) override; + + void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) override; + + void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minArchiveRequestAge) override; + + void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) override; + + void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) override; + + void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + friend class RdbmsArchiveFileCatalogue; + friend class RdbmsRequesterMountRuleCatalogue; + friend class RdbmsRequesterGroupMountRuleCatalogue; + + std::optional<common::dataStructures::MountPolicy> getMountPolicy(rdbms::Conn &conn, + const std::string &mountPolicyName) const; + + std::list<common::dataStructures::MountPolicy> getMountPolicies(rdbms::Conn & conn) const; + + /** + * Returns the specified requester mount-policy or std::nullopt if one does not + * exist. + * + * @param conn The database connection. + * @param user The fully qualified user, in other words the name of the disk + * instance and the name of the group. + * @return The mount policy or std::nullopt if one does not exists. + */ + std::optional<common::dataStructures::MountPolicy> getRequesterMountPolicy(rdbms::Conn &conn, const User &user) const; + + /** + * Returns the specified requester-group mount-policy or nullptr if one does + * not exist. + * + * @param conn The database connection. + * @param group The fully qualified group, in other words the name of the disk + * instance and the name of the group. + * @return The mount policy or std::nullopt if one does not exists. + */ + std::optional<common::dataStructures::MountPolicy> getRequesterGroupMountPolicy(rdbms::Conn &conn, + const Group &group) const; + + friend class RdbmsTapeFileCatalogue; + /** + * Returns the mount policies for the specified requester and requester group. + * + * @param conn The database connection. + * @param diskInstanceName The name of the disk instance to which the + * requester and requester group belong. + * @param requesterName The name of the requester which is only guaranteed to + * be unique within its disk instance. + * @param requesterGroupName The name of the requester group which is only + * guaranteed to be unique within its disk instance. + * @return The mount policies. + */ + RequesterAndGroupMountPolicies getMountPolicies( + rdbms::Conn &conn, + const std::string &diskInstanceName, + const std::string &requesterName, + const std::string &requesterGroupName) const; + + + /** + * Returns the mount policies for the specified requester, requester group and requester activity. + * + * @param conn The database connection. + * @param diskInstanceName The name of the disk instance to which the + * requester and requester group belong. + * @param requesterName The name of the requester which is only guaranteed to + * be unique within its disk instance. + * @param requesterGroupName The name of the requester group which is only + * guaranteed to be unique within its disk instance. + * @param activity The name of the activity to match the requester activity + * mount rules against + * @return The mount policies. + */ + RequesterAndGroupMountPolicies getMountPolicies( + rdbms::Conn &conn, + const std::string &diskInstanceName, + const std::string &requesterName, + const std::string &requesterGroupName, + const std::string &activity) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.cpp b/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.cpp new file mode 100644 index 0000000000..e086d471f6 --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.cpp @@ -0,0 +1,282 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsRequesterActivityMountRuleCatalogue::RdbmsRequesterActivityMountRuleCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsRequesterActivityMountRuleCatalogue::modifyRequesterActivityMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_ACTIVITY_MOUNT_RULE SET " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME AND " + "ACTIVITY_REGEX = :ACTIVITY_REGEX"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":ACTIVITY_REGEX", activityRegex); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester activity mount rule ") + instanceName + ":" + + requesterName + "for activities matching " + activityRegex + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterActivityMountRuleCatalogue::modifyRequesterActivityMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_ACTIVITY_MOUNT_RULE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME AND " + "ACTIVITY_REGEX = :ACTIVITY_REGEX"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":ACTIVITY_REGEX", activityRegex); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester activity mount rule ") + instanceName + ":" + + requesterName + "for activities matching " + activityRegex + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterActivityMountRuleCatalogue::createRequesterActivityMountRule( + const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstanceName, const std::string &requesterName, + const std::string &activityRegex, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::requesterActivityMountRuleExists(conn, diskInstanceName, requesterName, activityRegex)) { + throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + + " because that requester-activity mount rule already exists"); + } + if(!RdbmsCatalogueUtils::mountPolicyExists(conn, mountPolicyName)) { + throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + + " because mount-policy " + mountPolicyName + " does not exist"); + } + if(!RdbmsCatalogueUtils::diskInstanceExists(conn, diskInstanceName)) { + throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + " for activities matching " + activityRegex + + " because disk-instance " + diskInstanceName + " does not exist"); + } + + const uint64_t now = time(nullptr); + const char *const sql = + "INSERT INTO REQUESTER_ACTIVITY_MOUNT_RULE(" + "DISK_INSTANCE_NAME," + "REQUESTER_NAME," + "MOUNT_POLICY_NAME," + "ACTIVITY_REGEX," + + "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(" + ":DISK_INSTANCE_NAME," + ":REQUESTER_NAME," + ":MOUNT_POLICY_NAME," + ":ACTIVITY_REGEX," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); + stmt.bindString(":ACTIVITY_REGEX", activityRegex); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); +} + +std::list<common::dataStructures::RequesterActivityMountRule> + RdbmsRequesterActivityMountRuleCatalogue::getRequesterActivityMountRules() const { + try { + std::list<common::dataStructures::RequesterActivityMountRule> rules; + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "REQUESTER_NAME AS REQUESTER_NAME," + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + "ACTIVITY_REGEX AS ACTIVITY_REGEX," + + "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 " + "FROM " + "REQUESTER_ACTIVITY_MOUNT_RULE " + "ORDER BY " + "DISK_INSTANCE_NAME, REQUESTER_NAME, ACTIVITY_REGEX, MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while(rset.next()) { + common::dataStructures::RequesterActivityMountRule rule; + + rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + rule.name = rset.columnString("REQUESTER_NAME"); + rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); + rule.activityRegex = rset.columnString("ACTIVITY_REGEX"); + rule.comment = rset.columnString("USER_COMMENT"); + rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + rules.push_back(rule); + } + + return rules; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterActivityMountRuleCatalogue::deleteRequesterActivityMountRule(const std::string &diskInstanceName, + const std::string &requesterName, const std::string &activityRegex) { + try { + const char *const sql = + "DELETE FROM " + "REQUESTER_ACTIVITY_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME AND " + "ACTIVITY_REGEX = :ACTIVITY_REGEX"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":ACTIVITY_REGEX", activityRegex); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete mount rule for requester ") + diskInstanceName + ":" + + requesterName + " and activity regex " + activityRegex + " because the rule does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp b/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp new file mode 100644 index 0000000000..8b9d89b30d --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterActivityMountRuleCatalogue.hpp @@ -0,0 +1,66 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsRequesterActivityMountRuleCatalogue : public RequesterActivityMountRuleCatalogue { +public: + RdbmsRequesterActivityMountRuleCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + ~RdbmsRequesterActivityMountRuleCatalogue() override = default; + + void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &mountPolicy) override; + + void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) override; + + void createRequesterActivityMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &activityRegex, const std::string &comment) override; + + std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const override; + + void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, + const std::string &activityRegex) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.cpp b/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.cpp new file mode 100644 index 0000000000..a5f6036177 --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.cpp @@ -0,0 +1,279 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp" +#include "common/dataStructures/RequesterGroupMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsRequesterGroupMountRuleCatalogue::RdbmsRequesterGroupMountRuleCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsRequesterGroupMountRuleCatalogue::modifyRequesterGroupMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &mountPolicy) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_GROUP_MOUNT_RULE SET " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" + + requesterGroupName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterGroupMountRuleCatalogue::modifyRequesterGroupMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_GROUP_MOUNT_RULE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester group mount rule ") + instanceName + ":" + + requesterGroupName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterGroupMountRuleCatalogue::createRequesterGroupMountRule( + const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, + const std::string &diskInstanceName, + const std::string &requesterGroupName, + const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + auto conn = m_connPool->getConn(); + { + const auto group = Group(diskInstanceName, requesterGroupName); + const auto mountPolicyCatalogue = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + const auto mountPolicy = mountPolicyCatalogue->getRequesterGroupMountPolicy(conn, group); + if (mountPolicy) { + throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + + " to requester-group " + diskInstanceName + ":" + requesterGroupName + + " because a rule already exists assigning the requester-group to mount-policy " + + mountPolicy->name); + } + } + if(!RdbmsCatalogueUtils::mountPolicyExists(conn, mountPolicyName)) { + throw exception::UserError(std::string("Cannot assign mount-policy ") + mountPolicyName + " to requester-group " + + diskInstanceName + ":" + requesterGroupName + " because mount-policy " + mountPolicyName + " does not exist"); + } + if(!RdbmsCatalogueUtils::diskInstanceExists(conn, diskInstanceName)) { + throw exception::UserError(std::string("Cannot assign mount-policy ") + mountPolicyName + " to requester-group " + + diskInstanceName + ":" + requesterGroupName + " because disk-instance " + diskInstanceName + " does not exist"); + } + + const uint64_t now = time(nullptr); + const char *const sql = + "INSERT INTO REQUESTER_GROUP_MOUNT_RULE(" + "DISK_INSTANCE_NAME," + "REQUESTER_GROUP_NAME," + "MOUNT_POLICY_NAME," + + "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(" + ":DISK_INSTANCE_NAME," + ":REQUESTER_GROUP_NAME," + ":MOUNT_POLICY_NAME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); +} + +std::list<common::dataStructures::RequesterGroupMountRule> + RdbmsRequesterGroupMountRuleCatalogue::getRequesterGroupMountRules() const { + try { + std::list<common::dataStructures::RequesterGroupMountRule> rules; + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "REQUESTER_GROUP_NAME AS REQUESTER_GROUP_NAME," + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "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 " + "FROM " + "REQUESTER_GROUP_MOUNT_RULE " + "ORDER BY " + "DISK_INSTANCE_NAME, REQUESTER_GROUP_NAME, MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while(rset.next()) { + common::dataStructures::RequesterGroupMountRule rule; + + rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + rule.name = rset.columnString("REQUESTER_GROUP_NAME"); + rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); + + rule.comment = rset.columnString("USER_COMMENT"); + rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + rules.push_back(rule); + } + + return rules; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterGroupMountRuleCatalogue::deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) { + try { + const char *const sql = + "DELETE FROM " + "REQUESTER_GROUP_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_GROUP_NAME = :REQUESTER_GROUP_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_GROUP_NAME", requesterGroupName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete the mount rule for requester group ") + diskInstanceName + + ":" + requesterGroupName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_groupMountPolicyCache.invalidate(); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp b/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp new file mode 100644 index 0000000000..267f2c12b9 --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterGroupMountRuleCatalogue.hpp @@ -0,0 +1,65 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsRequesterGroupMountRuleCatalogue : public RequesterGroupMountRuleCatalogue { +public: + RdbmsRequesterGroupMountRuleCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + ~RdbmsRequesterGroupMountRuleCatalogue() override = default; + + void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) override; + + void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) override; + + void createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstanceName, const std::string &requesterGroupName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const override; + + + void deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.cpp b/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.cpp new file mode 100644 index 0000000000..90f2dfe967 --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.cpp @@ -0,0 +1,273 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsRequesterMountRuleCatalogue::RdbmsRequesterMountRuleCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsRequesterMountRuleCatalogue::modifyRequesterMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &mountPolicy) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_MOUNT_RULE SET " + "MOUNT_POLICY_NAME = :MOUNT_POLICY_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicy); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" + + requesterName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterMountRuleCatalogue::modifyRequesteMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE REQUESTER_MOUNT_RULE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":DISK_INSTANCE_NAME", instanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify requester mount rule ") + instanceName + ":" + + requesterName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterMountRuleCatalogue::createRequesterMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstanceName, const std::string &requesterName, + const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const auto user = User(diskInstanceName, requesterName); + auto conn = m_connPool->getConn(); + const auto mountPolicyCatalogue = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + const auto mountPolicy = mountPolicyCatalogue->getRequesterMountPolicy(conn, user); + if(mountPolicy) { + throw exception::UserError(std::string("Cannot create rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + + " because the requester is already assigned to mount-policy " + mountPolicy->name); + } + if(!RdbmsCatalogueUtils::mountPolicyExists(conn, mountPolicyName)) { + throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + " because mount-policy " + mountPolicyName + + " does not exist"); + } + if(!RdbmsCatalogueUtils::diskInstanceExists(conn, diskInstanceName)) { + throw exception::UserError(std::string("Cannot create a rule to assign mount-policy ") + mountPolicyName + + " to requester " + diskInstanceName + ":" + requesterName + " because disk-instance " + diskInstanceName + + " does not exist"); + } + + const uint64_t now = time(nullptr); + const char *const sql = + "INSERT INTO REQUESTER_MOUNT_RULE(" + "DISK_INSTANCE_NAME," + "REQUESTER_NAME," + "MOUNT_POLICY_NAME," + + "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(" + ":DISK_INSTANCE_NAME," + ":REQUESTER_NAME," + ":MOUNT_POLICY_NAME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.bindString(":MOUNT_POLICY_NAME", mountPolicyName); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); +} + +std::list<common::dataStructures::RequesterMountRule> RdbmsRequesterMountRuleCatalogue::getRequesterMountRules() const { + try { + std::list<common::dataStructures::RequesterMountRule> rules; + const char *const sql = + "SELECT " + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "REQUESTER_NAME AS REQUESTER_NAME," + "MOUNT_POLICY_NAME AS MOUNT_POLICY_NAME," + + "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 " + "FROM " + "REQUESTER_MOUNT_RULE " + "ORDER BY " + "DISK_INSTANCE_NAME, REQUESTER_NAME, MOUNT_POLICY_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while(rset.next()) { + common::dataStructures::RequesterMountRule rule; + + rule.diskInstance = rset.columnString("DISK_INSTANCE_NAME"); + rule.name = rset.columnString("REQUESTER_NAME"); + rule.mountPolicy = rset.columnString("MOUNT_POLICY_NAME"); + rule.comment = rset.columnString("USER_COMMENT"); + rule.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + rule.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + rule.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + rule.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + rule.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + rule.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + rules.push_back(rule); + } + + return rules; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsRequesterMountRuleCatalogue::deleteRequesterMountRule(const std::string &diskInstanceName, + const std::string &requesterName) { + try { + const char *const sql = + "DELETE FROM " + "REQUESTER_MOUNT_RULE " + "WHERE " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME AND " + "REQUESTER_NAME = :REQUESTER_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstanceName); + stmt.bindString(":REQUESTER_NAME", requesterName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete mount rule for requester ") + diskInstanceName + ":" + requesterName + + " because the rule does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + + m_rdbmsCatalogue->m_userMountPolicyCache.invalidate(); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp b/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp new file mode 100644 index 0000000000..b0264171d7 --- /dev/null +++ b/catalogue/rdbms/RdbmsRequesterMountRuleCatalogue.hpp @@ -0,0 +1,63 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterMountRuleCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsRequesterMountRuleCatalogue : public RequesterMountRuleCatalogue { +public: + RdbmsRequesterMountRuleCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + ~RdbmsRequesterMountRuleCatalogue() override = default; + + void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) override; + + void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &comment) override; + + void createRequesterMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const override; + + void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) override; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsSchemaCatalogue.cpp b/catalogue/rdbms/RdbmsSchemaCatalogue.cpp new file mode 100644 index 0000000000..889883c3f5 --- /dev/null +++ b/catalogue/rdbms/RdbmsSchemaCatalogue.cpp @@ -0,0 +1,124 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/RdbmsSchemaCatalogue.hpp" +#include "catalogue/SchemaVersion.hpp" +#include "common/Constants.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsSchemaCatalogue::RdbmsSchemaCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool): + m_log(log), m_connPool(connPool) {} + +SchemaVersion RdbmsSchemaCatalogue::getSchemaVersion() const { + try { + std::map<std::string, uint64_t> schemaVersion; + const char *const sql = + "SELECT " + "CTA_CATALOGUE.SCHEMA_VERSION_MAJOR AS SCHEMA_VERSION_MAJOR," + "CTA_CATALOGUE.SCHEMA_VERSION_MINOR AS SCHEMA_VERSION_MINOR," + "CTA_CATALOGUE.NEXT_SCHEMA_VERSION_MAJOR AS NEXT_SCHEMA_VERSION_MAJOR," + "CTA_CATALOGUE.NEXT_SCHEMA_VERSION_MINOR AS NEXT_SCHEMA_VERSION_MINOR," + "CTA_CATALOGUE.STATUS AS STATUS " + "FROM " + "CTA_CATALOGUE"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + + if(rset.next()) { + SchemaVersion::Builder schemaVersionBuilder; + schemaVersionBuilder.schemaVersionMajor(rset.columnUint64("SCHEMA_VERSION_MAJOR")) + .schemaVersionMinor(rset.columnUint64("SCHEMA_VERSION_MINOR")) + .status(rset.columnString("STATUS")); + auto schemaVersionMajorNext = rset.columnOptionalUint64("NEXT_SCHEMA_VERSION_MAJOR"); + auto schemaVersionMinorNext = rset.columnOptionalUint64("NEXT_SCHEMA_VERSION_MINOR"); + if(schemaVersionMajorNext && schemaVersionMinorNext){ + schemaVersionBuilder.nextSchemaVersionMajor(schemaVersionMajorNext.value()) + .nextSchemaVersionMinor(schemaVersionMinorNext.value()); + } + return schemaVersionBuilder.build(); + } else { + throw exception::Exception("CTA_CATALOGUE does not contain any row"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsSchemaCatalogue::verifySchemaVersion() { + try { + SchemaVersion schemaVersion = getSchemaVersion(); + if(auto [major, minor] = schemaVersion.getSchemaVersion<SchemaVersion::MajorMinor>(); + major != static_cast<uint64_t>(CTA_CATALOGUE_SCHEMA_VERSION_MAJOR)){ + std::ostringstream exceptionMsg; + exceptionMsg << "Catalogue schema MAJOR version differ : Database schema version is " + << major << "." << minor + << ", CTA schema version is " << CTA_CATALOGUE_SCHEMA_VERSION_MAJOR << "." + << CTA_CATALOGUE_SCHEMA_VERSION_MINOR; + throw WrongSchemaVersionException(exceptionMsg.str()); + } + if(schemaVersion.getStatus<SchemaVersion::Status>() == SchemaVersion::Status::UPGRADING){ + std::ostringstream exceptionMsg; + exceptionMsg << "Catalogue schema is in status " + schemaVersion.getStatus<std::string>() + + ", next schema version is " << schemaVersion.getSchemaVersionNext<std::string>(); + } + } catch (exception::UserError &) { + throw; + } catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// ping +//------------------------------------------------------------------------------ +void RdbmsSchemaCatalogue::ping() { + try { + verifySchemaVersion(); + } catch (WrongSchemaVersionException &){ + throw; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// getTableNames +//------------------------------------------------------------------------------ +std::list<std::string> RdbmsSchemaCatalogue::getTableNames() const { + auto conn = m_connPool->getConn(); + return conn.getTableNames(); +} + + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsSchemaCatalogue.hpp b/catalogue/rdbms/RdbmsSchemaCatalogue.hpp new file mode 100644 index 0000000000..8b6314d1b6 --- /dev/null +++ b/catalogue/rdbms/RdbmsSchemaCatalogue.hpp @@ -0,0 +1,60 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/SchemaCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class ConnPool; +} + +namespace catalogue { + +class RdbmsSchemaCatalogue : public SchemaCatalogue { +public: + RdbmsSchemaCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool); + ~RdbmsSchemaCatalogue() override = default; + + SchemaVersion getSchemaVersion() const override; + + void verifySchemaVersion() override; + + void ping() override; + + // This method is for unit tests only in InMemoryCatalogueTest.cpp, it's not defined in the interface + /** + * Returns the names of all the tables in the database schema in alphabetical + * order. + * + * @return The names of all the tables in the database schema in alphabetical + * order. + */ + std::list<std::string> getTableNames() const; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsStorageClassCatalogue.cpp b/catalogue/rdbms/RdbmsStorageClassCatalogue.cpp new file mode 100644 index 0000000000..738088a698 --- /dev/null +++ b/catalogue/rdbms/RdbmsStorageClassCatalogue.cpp @@ -0,0 +1,502 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <string> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "common/log/Logger.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +RdbmsStorageClassCatalogue::RdbmsStorageClassCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsStorageClassCatalogue::createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) { + try { + if(storageClass.name.empty()) { + throw UserSpecifiedAnEmptyStringStorageClassName("Cannot create storage class because the storage class name is" + " an empty string"); + } + + if (storageClass.comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create storage class because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(storageClass.comment, &m_log); + std::string vo = storageClass.vo.name; + + if(vo.empty()) { + throw UserSpecifiedAnEmptyStringVo("Cannot create storage class because the vo is an empty string"); + } + + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::storageClassExists(conn, storageClass.name)) { + throw exception::UserError(std::string("Cannot create storage class : ") + + storageClass.name + " because it already exists"); + } + if(!RdbmsCatalogueUtils::virtualOrganizationExists(conn,vo)) { + throw exception::UserError(std::string("Cannot create storage class : ") + + storageClass.name + " because the vo : " + vo + " does not exist"); + } + const uint64_t storageClassId = getNextStorageClassId(conn); + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO STORAGE_CLASS(" + "STORAGE_CLASS_ID," + "STORAGE_CLASS_NAME," + "NB_COPIES," + "VIRTUAL_ORGANIZATION_ID," + + "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(" + ":STORAGE_CLASS_ID," + ":STORAGE_CLASS_NAME," + ":NB_COPIES," + "(SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME = :VO)," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindUint64(":STORAGE_CLASS_ID", storageClassId); + stmt.bindString(":STORAGE_CLASS_NAME", storageClass.name); + stmt.bindUint64(":NB_COPIES", storageClass.nbCopies); + stmt.bindString(":VO",vo); + + stmt.bindString(":USER_COMMENT", storageClass.comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsStorageClassCatalogue::deleteStorageClass(const std::string &storageClassName) { + try { + auto conn = m_connPool->getConn(); + + if(storageClassIsUsedByArchiveRoutes(conn, storageClassName)) { + throw UserSpecifiedStorageClassUsedByArchiveRoutes(std::string("The ") + storageClassName + + " storage class is being used by one or more archive routes"); + } + + if(storageClassIsUsedByArchiveFiles(conn, storageClassName)) { + throw UserSpecifiedStorageClassUsedByArchiveFiles(std::string("The ") + storageClassName + + " storage class is being used by one or more archive files"); + } + + if(storageClassIsUsedByFileRecyleLogs(conn,storageClassName)){ + throw UserSpecifiedStorageClassUsedByFileRecycleLogs(std::string("The ") + storageClassName + + " storage class is being used by one or more file in the recycle logs"); + } + + const char *const sql = + "DELETE FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + + stmt.executeNonQuery(); + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete storage-class : ") + + storageClassName + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::StorageClass> RdbmsStorageClassCatalogue::getStorageClasses() const { + try { + std::list<common::dataStructures::StorageClass> storageClasses; + const char *const sql = + "SELECT " + "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "NB_COPIES AS NB_COPIES," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," + + "STORAGE_CLASS.USER_COMMENT AS USER_COMMENT," + + "STORAGE_CLASS.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "STORAGE_CLASS.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "STORAGE_CLASS.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "STORAGE_CLASS.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "STORAGE_CLASS.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "STORAGE_CLASS.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "STORAGE_CLASS " + "INNER JOIN " + "VIRTUAL_ORGANIZATION ON STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "ORDER BY " + "STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::StorageClass storageClass; + + storageClass.name = rset.columnString("STORAGE_CLASS_NAME"); + storageClass.nbCopies = rset.columnUint64("NB_COPIES"); + storageClass.vo.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); + storageClass.comment = rset.columnString("USER_COMMENT"); + storageClass.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + storageClass.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + storageClass.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + storageClass.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + storageClass.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + storageClass.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + storageClasses.push_back(storageClass); + } + + return storageClasses; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::StorageClass RdbmsStorageClassCatalogue::getStorageClass(const std::string &name) const { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "NB_COPIES AS NB_COPIES," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," + "VIRTUAL_ORGANIZATION.MAX_FILE_SIZE AS MAX_FILE_SIZE," + "STORAGE_CLASS.USER_COMMENT AS USER_COMMENT," + + "STORAGE_CLASS.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "STORAGE_CLASS.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "STORAGE_CLASS.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "STORAGE_CLASS.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "STORAGE_CLASS.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "STORAGE_CLASS.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "STORAGE_CLASS " + "INNER JOIN " + "VIRTUAL_ORGANIZATION ON STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", name); + auto rset = stmt.executeQuery(); + if (rset.isEmpty()) { + throw exception::UserError(std::string("Cannot get storage class : ") + name + + " because it does not exist"); + } + rset.next(); + common::dataStructures::StorageClass storageClass; + + storageClass.name = rset.columnString("STORAGE_CLASS_NAME"); + storageClass.nbCopies = rset.columnUint64("NB_COPIES"); + storageClass.vo.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); + storageClass.vo.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); + storageClass.comment = rset.columnString("USER_COMMENT"); + storageClass.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + storageClass.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + storageClass.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + storageClass.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + storageClass.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + storageClass.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + return storageClass; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsStorageClassCatalogue::modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE STORAGE_CLASS SET " + "NB_COPIES = :NB_COPIES," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":NB_COPIES", nbCopies); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":STORAGE_CLASS_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify storage class : ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsStorageClassCatalogue::modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE STORAGE_CLASS SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":STORAGE_CLASS_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify storage class : ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsStorageClassCatalogue::modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE STORAGE_CLASS SET " + "VIRTUAL_ORGANIZATION_ID = (SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME = :VO)," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + if(vo.empty()){ + throw UserSpecifiedAnEmptyStringVo(std::string("Cannot modify the vo of the storage class : ") + name + " because the vo is an empty string"); + } + if(!RdbmsCatalogueUtils::virtualOrganizationExists(conn,vo)){ + throw exception::UserError(std::string("Cannot modify storage class : ") + name + + " because the vo " + vo + " does not exist"); + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":VO", vo); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":STORAGE_CLASS_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify storage class : ") + name + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsStorageClassCatalogue::modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE STORAGE_CLASS SET " + "STORAGE_CLASS_NAME = :NEW_STORAGE_CLASS_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "STORAGE_CLASS_NAME = :CURRENT_STORAGE_CLASS_NAME"; + auto conn = m_connPool->getConn(); + if(newName != currentName){ + if(RdbmsCatalogueUtils::storageClassExists(conn,newName)){ + throw exception::UserError(std::string("Cannot modify the storage class name ") + currentName +". The new name : " + newName+" already exists in the database."); + } + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":NEW_STORAGE_CLASS_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_STORAGE_CLASS_NAME", currentName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify storage class : ") + currentName + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsStorageClassCatalogue::storageClassIsUsedByArchiveRoutes(rdbms::Conn &conn, + const std::string &storageClassName) const { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " + "FROM " + "ARCHIVE_ROUTE " + "INNER JOIN " + "STORAGE_CLASS " + "ON " + "ARCHIVE_ROUTE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsStorageClassCatalogue::storageClassIsUsedByArchiveFiles(rdbms::Conn &conn, + const std::string &storageClassName) const { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN " + "STORAGE_CLASS " + "ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsStorageClassCatalogue::storageClassIsUsedByFileRecyleLogs(rdbms::Conn &conn, + const std::string &storageClassName) const { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME " + "FROM " + "FILE_RECYCLE_LOG " + "INNER JOIN " + "STORAGE_CLASS " + "ON " + "FILE_RECYCLE_LOG.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":STORAGE_CLASS_NAME", storageClassName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsStorageClassCatalogue.hpp b/catalogue/rdbms/RdbmsStorageClassCatalogue.hpp new file mode 100644 index 0000000000..9591cc88a9 --- /dev/null +++ b/catalogue/rdbms/RdbmsStorageClassCatalogue.hpp @@ -0,0 +1,145 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/StorageClassCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +/** + * A fully qualified storage class, in other words the name of the disk + * instance and the name of the storage class. + */ +struct StorageClass { + + /** + * The name of the storage class which is only guaranteed to be unique + */ + std::string storageClassName; + + /** + * Constructor. + * + * @param sN The name of the storage class which is only guaranteed to be + * unique within its disk instance. + */ + explicit StorageClass(const std::string &s): storageClassName(s) {} + + /** + * Less than operator. + * + * @param rhs The argument on the right hand side of the operator. + * @return True if this object is less than the argument on the right hand + * side of the operator. + */ + bool operator<(const StorageClass &rhs) const { + return storageClassName < rhs.storageClassName; + } +}; // struct StorageClass + +class RdbmsCatalogue; + +class RdbmsStorageClassCatalogue : public StorageClassCatalogue { +public: + ~RdbmsStorageClassCatalogue() override = default; + + void createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) override; + + void deleteStorageClass(const std::string &storageClassName) override; + + std::list<common::dataStructures::StorageClass> getStorageClasses() const override; + + common::dataStructures::StorageClass getStorageClass(const std::string &name) const override; + + void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) override; + + void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; + +protected: + RdbmsStorageClassCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + /** + * Returns true if the specified storage class is currently being used by one + * or more archive routes. + * + * @param conn The database connection. + * @param storageClassName The name of the storage class. + */ + bool storageClassIsUsedByArchiveRoutes(rdbms::Conn &conn, const std::string &storageClassName) const; + + /** + * Returns true if the specified storage class is currently being used by one + * or more archive files. + * + * @param conn The database connection. + * @param storageClassName The name of the storage class. + */ + bool storageClassIsUsedByArchiveFiles(rdbms::Conn &conn, const std::string &storageClassName) const; + + /** + * Returns true if the specified storage class is currently being used by one + * or more files in the recycle log. + * + * @param conn The database connection. + * @param storageClassName The name of the storage class. + */ + bool storageClassIsUsedByFileRecyleLogs(rdbms::Conn & conn, const std::string & storageClassName) const; + + /** + * Returns a unique storage class ID that can be used by a new storage class + * 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 storage class ID that can be used by a new storage class + * within the catalogue. + */ + virtual uint64_t getNextStorageClassId(rdbms::Conn &conn) = 0; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsTapeCatalogue.cpp b/catalogue/rdbms/RdbmsTapeCatalogue.cpp new file mode 100644 index 0000000000..758e94b425 --- /dev/null +++ b/catalogue/rdbms/RdbmsTapeCatalogue.cpp @@ -0,0 +1,1879 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp" +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapePoolCatalogue.hpp" +#include "catalogue/TapeForWriting.hpp" +#include "catalogue/TapeSearchCriteria.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/Tape.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "common/log/Logger.hpp" +#include "common/log/TimingList.hpp" +#include "common/threading/Mutex.hpp" +#include "common/threading/MutexLocker.hpp" +#include "common/Timer.hpp" +#include "common/utils/utils.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsTapeCatalogue::RdbmsTapeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsTapeCatalogue::createTape(const common::dataStructures::SecurityIdentity &admin, + const CreateTapeAttributes & tape) { + // CTA hard code this field to FALSE + const bool isFromCastor = false; + try { + std::string vid = tape.vid; + std::string mediaTypeName = tape.mediaType; + std::string vendor = tape.vendor; + std::string logicalLibraryName = tape.logicalLibraryName; + std::string tapePoolName = tape.tapePoolName; + bool full = tape.full; + // Translate an empty comment string to a NULL database value + const std::optional<std::string> tapeComment = tape.comment && tape.comment->empty() ? std::nullopt : tape.comment; + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(tapeComment, &m_log); + const std::optional<std::string> stateReason = tape.stateReason + && cta::utils::trimString(tape.stateReason.value()).empty() ? std::nullopt : tape.stateReason; + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(stateReason, &m_log); + if(vid.empty()) { + throw UserSpecifiedAnEmptyStringVid("Cannot create tape because the VID is an empty string"); + } + + if(mediaTypeName.empty()) { + throw UserSpecifiedAnEmptyStringMediaType("Cannot create tape because the media type is an empty string"); + } + + if(vendor.empty()) { + throw UserSpecifiedAnEmptyStringVendor("Cannot create tape because the vendor is an empty string"); + } + + if(logicalLibraryName.empty()) { + throw UserSpecifiedAnEmptyStringLogicalLibraryName("Cannot create tape because the logical library name is an" + " empty string"); + } + + if(tapePoolName.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create tape because the tape pool name is an empty string"); + } + + std::string tapeState; + try { + tapeState = common::dataStructures::Tape::stateToString(tape.state); + } catch(cta::exception::Exception &ex) { + std::string errorMsg = "Cannot create tape because the state specified does not exist. Possible values for state are: " + + common::dataStructures::Tape::getAllPossibleStates(); + throw UserSpecifiedANonExistentTapeState(errorMsg); + } + + if(tape.state != common::dataStructures::Tape::ACTIVE){ + if(!stateReason){ + throw UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive("Cannot create tape because no reason has been " + "provided for the state " + tapeState); + } + } + + auto conn = m_connPool->getConn(); + if(RdbmsCatalogueUtils::tapeExists(conn, vid)) { + throw exception::UserError(std::string("Cannot create tape ") + vid + + " because a tape with the same volume identifier already exists"); + } + const auto logicLibCatalogue = static_cast<RdbmsLogicalLibraryCatalogue*>(m_rdbmsCatalogue->LogicalLibrary().get()); + const auto logicalLibraryId = logicLibCatalogue->getLogicalLibraryId(conn, logicalLibraryName); + if(!logicalLibraryId) { + throw exception::UserError(std::string("Cannot create tape ") + vid + " because logical library " + + logicalLibraryName + " does not exist"); + } + const auto tapePoolCatalogue = static_cast<RdbmsTapePoolCatalogue*>(m_rdbmsCatalogue->TapePool().get()); + const auto tapePoolId = tapePoolCatalogue->getTapePoolId(conn, tapePoolName); + if(!tapePoolId) { + throw exception::UserError(std::string("Cannot create tape ") + vid + " because tape pool " + + tapePoolName + " does not exist"); + } + const auto mediaTypeCatalogue = static_cast<RdbmsMediaTypeCatalogue*>(m_rdbmsCatalogue->MediaType().get()); + const auto mediaTypeId = mediaTypeCatalogue->getMediaTypeId(conn, mediaTypeName); + if(!mediaTypeId) { + throw exception::UserError(std::string("Cannot create tape ") + vid + " because media type " + + mediaTypeName + " does not exist"); + } + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO TAPE(" + "VID, " + "MEDIA_TYPE_ID, " + "VENDOR, " + "LOGICAL_LIBRARY_ID, " + "TAPE_POOL_ID, " + "DATA_IN_BYTES, " + "LAST_FSEQ, " + "IS_FULL, " + "IS_FROM_CASTOR, " + + "USER_COMMENT, " + + "TAPE_STATE, " + "STATE_REASON, " + "STATE_UPDATE_TIME, " + "STATE_MODIFIED_BY, " + + "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_ID, " + ":VENDOR, " + ":LOGICAL_LIBRARY_ID, " + ":TAPE_POOL_ID, " + ":DATA_IN_BYTES, " + ":LAST_FSEQ, " + ":IS_FULL, " + ":IS_FROM_CASTOR, " + + ":USER_COMMENT, " + + ":TAPE_STATE, " + ":STATE_REASON, " + ":STATE_UPDATE_TIME, " + ":STATE_MODIFIED_BY, " + + ":CREATION_LOG_USER_NAME, " + ":CREATION_LOG_HOST_NAME, " + ":CREATION_LOG_TIME, " + + ":LAST_UPDATE_USER_NAME, " + ":LAST_UPDATE_HOST_NAME, " + ":LAST_UPDATE_TIME" + ")"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":VID", vid); + stmt.bindUint64(":MEDIA_TYPE_ID", mediaTypeId.value()); + stmt.bindString(":VENDOR", vendor); + stmt.bindUint64(":LOGICAL_LIBRARY_ID", logicalLibraryId.value()); + stmt.bindUint64(":TAPE_POOL_ID", tapePoolId.value()); + stmt.bindUint64(":DATA_IN_BYTES", 0); + stmt.bindUint64(":LAST_FSEQ", 0); + stmt.bindBool(":IS_FULL", full); + stmt.bindBool(":IS_FROM_CASTOR", isFromCastor); + + stmt.bindString(":USER_COMMENT", tapeComment); + + std::string stateModifiedBy = RdbmsCatalogueUtils::generateTapeStateModifiedBy(admin); + stmt.bindString(":TAPE_STATE",cta::common::dataStructures::Tape::stateToString(tape.state)); + stmt.bindString(":STATE_REASON",stateReason); + stmt.bindUint64(":STATE_UPDATE_TIME",now); + stmt.bindString(":STATE_MODIFIED_BY", stateModifiedBy); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("mediaType", mediaTypeName) + .add("vendor", vendor) + .add("logicalLibraryName", logicalLibraryName) + .add("tapePoolName", tapePoolName) + .add("isFull", full ? 1 : 0) + .add("isFromCastor", isFromCastor ? 1 : 0) + .add("userComment", tape.comment ? tape.comment.value() : "") + .add("tapeState",cta::common::dataStructures::Tape::stateToString(tape.state)) + .add("stateReason",stateReason ? stateReason.value() : "") + .add("stateUpdateTime",now) + .add("stateModifiedBy",stateModifiedBy) + .add("creationLogUserName", admin.username) + .add("creationLogHostName", admin.host) + .add("creationLogTime", now); + lc.log(log::INFO, "Catalogue - user created tape"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::deleteTape(const std::string &vid) { + try { + const char *const delete_sql = + "DELETE " + "FROM " + "TAPE " + "WHERE " + "VID = :DELETE_VID AND " + "NOT EXISTS (SELECT VID FROM TAPE_FILE WHERE VID = :SELECT_VID) AND " + "NOT EXISTS (SELECT VID FROM FILE_RECYCLE_LOG WHERE VID = :SELECT_VID2)"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(delete_sql); + stmt.bindString(":DELETE_VID", vid); + stmt.bindString(":SELECT_VID", vid); + stmt.bindString(":SELECT_VID2", vid); + stmt.executeNonQuery(); + + // The delete statement will effect no rows and will not raise an error if + // either the tape does not exist or if it still has tape files or files in the recycle log + if(0 == stmt.getNbAffectedRows()) { + if(RdbmsCatalogueUtils::tapeExists(conn, vid)) { + throw UserSpecifiedANonEmptyTape(std::string("Cannot delete tape ") + vid + " because either it contains one or more files or the files that were in it are in the file recycle log."); + } else { + throw UserSpecifiedANonExistentTape(std::string("Cannot delete tape ") + vid + " because it does not exist"); + } + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::Tape> RdbmsTapeCatalogue::getTapes(const TapeSearchCriteria &searchCriteria) const { + try { + auto conn = m_connPool->getConn(); + return getTapes(conn, searchCriteria); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::VidToTapeMap RdbmsTapeCatalogue::getTapesByVid(const std::string& vid) const { + try { + const char* const sql = + "SELECT " + "TAPE.VID AS VID," + "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," + "TAPE.VENDOR AS VENDOR," + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," + "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," + "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," + "TAPE.LAST_FSEQ AS LAST_FSEQ," + "TAPE.IS_FULL AS IS_FULL," + "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," + "TAPE.LABEL_FORMAT AS LABEL_FORMAT," + "TAPE.LABEL_DRIVE AS LABEL_DRIVE," + "TAPE.LABEL_TIME AS LABEL_TIME," + "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," + "TAPE.LAST_READ_TIME AS LAST_READ_TIME," + "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," + "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," + "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," + "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," + "TAPE.USER_COMMENT AS USER_COMMENT," + "TAPE.TAPE_STATE AS TAPE_STATE," + "TAPE.STATE_REASON AS STATE_REASON," + "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," + "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," + "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "INNER JOIN LOGICAL_LIBRARY ON " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " + "INNER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "VID = :VID"; + + common::dataStructures::VidToTapeMap vidToTapeMap; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); + + if(vidToTapeMap.size() != 1) { + exception::Exception ex; + ex.getMessage() << "Not all tapes were found: expected=1 actual=" << vidToTapeMap.size(); + throw ex; + } + return vidToTapeMap; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::VidToTapeMap RdbmsTapeCatalogue::getTapesByVid(const std::set<std::string> &vids) const { + try { + common::dataStructures::VidToTapeMap vidToTapeMap; + + if(vids.empty()) return vidToTapeMap; + + static const std::string selectTapesBy100VidsSql = getSelectTapesBy100VidsSql(); + + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(selectTapesBy100VidsSql); + uint64_t vidNb = 1; + + for(const auto &vid: vids) { + // Bind the current tape VID + std::ostringstream paramName; + paramName << ":V" << vidNb; + stmt.bindString(paramName.str(), vid); + + // If the 100th tape VID has not yet been reached + if(100 > vidNb) { + vidNb++; + } else { // The 100th VID has been reached + vidNb = 1; + + // Execute the query and collect the results + executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); + + // Create a new statement + stmt = conn.createStmt(selectTapesBy100VidsSql); + } + } + + // If there is a statement under construction + if(1 != vidNb) { + // Bind the remaining parameters with last tape VID. This has no effect + // on the search results but makes the statement valid. + const std::string &lastVid = *vids.rbegin(); + while(100 >= vidNb) { + std::ostringstream paramName; + paramName << ":V" << vidNb; + stmt.bindString(paramName.str(), lastVid); + vidNb++; + } + + // Execute the query and collect the results + executeGetTapesByVidStmtAndCollectResults(stmt, vidToTapeMap); + } + + if(vids.size() != vidToTapeMap.size()) { + exception::Exception ex; + ex.getMessage() << "Not all tapes were found: expected=" << vids.size() << " actual=" << vidToTapeMap.size(); + throw ex; + } + + return vidToTapeMap; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::map<std::string, std::string> RdbmsTapeCatalogue::getVidToLogicalLibrary(const std::set<std::string> &vids) const { + try { + std::map<std::string, std::string> vidToLogicalLibrary; + + if(vids.empty()) return vidToLogicalLibrary; + + static const std::string sql = getSelectVidToLogicalLibraryBy100Sql(); + + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + uint64_t vidNb = 1; + + for(const auto &vid: vids) { + // Bind the current tape VID + std::ostringstream paramName; + paramName << ":V" << vidNb; + stmt.bindString(paramName.str(), vid); + + // If the 100th tape VID has not yet been reached + if(100 > vidNb) { + vidNb++; + } else { // The 100th VID has been reached + vidNb = 1; + + // Execute the query and collect the results + executeGetVidToLogicalLibraryBy100StmtAndCollectResults(stmt, vidToLogicalLibrary); + + // Create a new statement + stmt = conn.createStmt(sql); + } + } + + // If there is a statement under construction + if(1 != vidNb) { + // Bind the remaining parameters with last tape VID. This has no effect + // on the search results but makes the statement valid. + const std::string &lastVid = *vids.rbegin(); + while(100 >= vidNb) { + std::ostringstream paramName; + paramName << ":V" << vidNb; + stmt.bindString(paramName.str(), lastVid); + vidNb++; + } + + // Execute the query and collect the results + executeGetVidToLogicalLibraryBy100StmtAndCollectResults(stmt, vidToLogicalLibrary); + } + + if(vids.size() != vidToLogicalLibrary.size()) { + exception::Exception ex; + ex.getMessage() << "Not all tapes were found: expected=" << vids.size() << " actual=" << + vidToLogicalLibrary.size(); + throw ex; + } + + return vidToLogicalLibrary; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + cta::log::LogContext & lc) { + try{ + log::TimingList tl; + utils::Timer t; + auto conn = m_connPool->getConn(); + + TapeSearchCriteria searchCriteria; + searchCriteria.vid = vid; + const auto tapes = getTapes(conn, searchCriteria); + tl.insertAndReset("getTapesTime", t); + + if (tapes.empty()) { + throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it does not exist"); + } else if (tapes.front().state != common::dataStructures::Tape::State::ACTIVE + && tapes.front().state != common::dataStructures::Tape::State::DISABLED) { + throw exception::UserError(std::string("Cannot reclaim tape ") + vid + + " because it is not on ACTIVE or DISABLED state"); + } else if (!tapes.front().full) { + throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because it is not FULL"); + } + + // The tape exists and is full, we can try to reclaim it + if (this->getNbFilesOnTape(conn, vid) == 0) { + tl.insertAndReset("getNbFilesOnTape", t); + // There is no files on the tape, we can reclaim it : delete the files and reset the counters + static_cast<RdbmsFileRecycleLogCatalogue*>( + m_rdbmsCatalogue->FileRecycleLog().get())->deleteFilesFromRecycleLog(conn, vid, lc); + tl.insertAndReset("deleteFileFromRecycleLogTime", t); + resetTapeCounters(conn, admin, vid); + tl.insertAndReset("resetTapeCountersTime", t); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid); + spc.add("host", admin.host); + spc.add("username", admin.username); + tl.addToLog(spc); + lc.log(log::INFO, "In RdbmsCatalogue::reclaimTape(), tape reclaimed."); + } else { + throw exception::UserError(std::string("Cannot reclaim tape ") + vid + " because there is at least one tape" + " file in the catalogue that is on the tape"); + } + } catch (exception::UserError& ue) { + throw; + } + catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::checkTapeForLabel(const std::string &vid) { + try{ + auto conn = m_connPool->getConn(); + + TapeSearchCriteria searchCriteria; + searchCriteria.vid = vid; + const auto tapes = getTapes(conn, searchCriteria); + + if(tapes.empty()) { + throw exception::UserError(std::string("Cannot label tape ") + vid + + " because it does not exist"); + } + //The tape exists checks any files on it + const uint64_t nbFilesOnTape = getNbFilesOnTape(conn, vid); + if( 0 != nbFilesOnTape) { + throw exception::UserError(std::string("Cannot label tape ") + vid + + " because it has " + + std::to_string(nbFilesOnTape) + + " file(s)"); + } + } catch (exception::UserError& ue) { + throw; + } + catch (exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t RdbmsTapeCatalogue::getNbFilesOnTape(const std::string &vid) const { + try { + auto conn = m_connPool->getConn(); + return getNbFilesOnTape(conn, vid); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &mediaType) { + try { + auto conn = m_connPool->getConn(); + if(!RdbmsCatalogueUtils::mediaTypeExists(conn, mediaType)){ + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the media type " + mediaType + " does not exist"); + } + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "MEDIA_TYPE_ID = (SELECT MEDIA_TYPE_ID FROM MEDIA_TYPE WHERE MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE)," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":MEDIA_TYPE", mediaType); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("mediaType", mediaType) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - mediaType"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &vendor) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "VENDOR = :VENDOR," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VENDOR", vendor); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("vendor", vendor) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - vendor"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &logicalLibraryName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "LOGICAL_LIBRARY_ID = " + "(SELECT LOGICAL_LIBRARY_ID FROM LOGICAL_LIBRARY WHERE LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME)," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + if(!RdbmsCatalogueUtils::logicalLibraryExists(conn,logicalLibraryName)){ + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the logical library " + logicalLibraryName + " does not exist"); + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or logical library " + + logicalLibraryName + " does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("logicalLibraryName", logicalLibraryName) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - logicalLibraryName"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &tapePoolName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "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 " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + if(!RdbmsCatalogueUtils::tapePoolExists(conn,tapePoolName)){ + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because the tape pool " + tapePoolName + " does not exist"); + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because either it or tape pool " + + tapePoolName + " does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("tapePoolName", tapePoolName) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - tapePoolName"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &encryptionKeyName) { + try { + std::optional<std::string> optionalEncryptionKeyName; + if(!encryptionKeyName.empty()) { + optionalEncryptionKeyName = encryptionKeyName; + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "ENCRYPTION_KEY_NAME = :ENCRYPTION_KEY_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":ENCRYPTION_KEY_NAME", optionalEncryptionKeyName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("encryptionKeyName", optionalEncryptionKeyName ? optionalEncryptionKeyName.value() : "NULL") + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - encryptionKeyName"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &verificationStatus) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "VERIFICATION_STATUS = :VERIFICATION_STATUS," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + if (verificationStatus.empty()) { + stmt.bindString(":VERIFICATION_STATUS", std::nullopt); + } else { + stmt.bindString(":VERIFICATION_STATUS", verificationStatus); + } + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("verificationStatus", verificationStatus) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - verificationStatus"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, + const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) { + try { + using namespace common::dataStructures; + const time_t now = time(nullptr); + + const std::optional<std::string> stateReasonCopy = stateReason && cta::utils::trimString(stateReason.value()).empty() ? std::nullopt : stateReason; + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(stateReasonCopy, &m_log); + + std::string stateStr; + try { + stateStr = cta::common::dataStructures::Tape::stateToString(state); + } catch(cta::exception::Exception & ex){ + std::string errorMsg = "The state provided in parameter (" + std::to_string(state) + ") is not known or has not been initialized existing states are:" + common::dataStructures::Tape::getAllPossibleStates(); + throw UserSpecifiedANonExistentTapeState(errorMsg); + } + + std::string prevStateStr; + if (prev_state.has_value()) { + try { + prevStateStr = cta::common::dataStructures::Tape::stateToString(prev_state.value()); + } catch (cta::exception::Exception &ex) { + std::string errorMsg = "The previous state provided in parameter (" + std::to_string(prev_state.value()) + ") is not known or has not been initialized existing states are:" + common::dataStructures::Tape::getAllPossibleStates(); + throw UserSpecifiedANonExistentTapeState(errorMsg); + } + } + + //Check the reason is set for all the status except the ACTIVE one, this is the only state that allows the reason to be set to null. + if(state != Tape::State::ACTIVE){ + if(!stateReasonCopy){ + throw UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive(std::string("Cannot modify the state of the tape ") + vid + " to " + stateStr + " because the reason has not been provided."); + } + } + + std::string sql = + "UPDATE TAPE SET " + "TAPE_STATE = :TAPE_STATE," + "STATE_REASON = :STATE_REASON," + "STATE_UPDATE_TIME = :STATE_UPDATE_TIME," + "STATE_MODIFIED_BY = :STATE_MODIFIED_BY " + "WHERE " + "VID = :VID"; + + if (prev_state.has_value()) { + sql += " AND TAPE_STATE = :PREV_TAPE_STATE"; + } + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + + stmt.bindString(":TAPE_STATE", stateStr); + stmt.bindString(":STATE_REASON", stateReasonCopy); + stmt.bindUint64(":STATE_UPDATE_TIME", now); + stmt.bindString(":STATE_MODIFIED_BY", RdbmsCatalogueUtils::generateTapeStateModifiedBy(admin)); + stmt.bindString(":VID",vid); + if (prev_state.has_value()) { + stmt.bindString(":PREV_TAPE_STATE",prevStateStr); + } + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw UserSpecifiedANonExistentTape(std::string("Cannot modify the state of the tape ") + vid + + " because it does not exist or because a recent state change has been detected"); + } + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsTapeCatalogue::tapeExists(const std::string &vid) const { + try { + auto conn = m_connPool->getConn(); + return RdbmsCatalogueUtils::tapeExists(conn, vid); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool fullValue) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "IS_FULL = :IS_FULL," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindBool(":IS_FULL", fullValue); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("isFull", fullValue ? 1 : 0) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - isFull"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "DIRTY = :DIRTY," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindBool(":DIRTY", dirtyValue); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("dirty", dirtyValue ? 1 : 0) + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - dirty"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::noSpaceLeftOnTape(const std::string &vid) { + try { + const char *const sql = + "UPDATE TAPE SET " + "IS_FULL = '1' " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::Exception(std::string("Tape ") + vid + " does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("isFull", 1) + .add("method", "noSpaceLeftOnTape"); + lc.log(log::INFO, "Catalogue - system modified tape - isFull"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<TapeForWriting> RdbmsTapeCatalogue::getTapesForWriting(const std::string &logicalLibraryName) const { + try { + std::list<TapeForWriting> tapes; + const char *const sql = + "SELECT " + "TAPE.VID AS VID," + "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," + "TAPE.VENDOR AS VENDOR," + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," + "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," + "TAPE.LAST_FSEQ AS LAST_FSEQ," + "TAPE.LABEL_FORMAT AS LABEL_FORMAT " + "FROM " + "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "INNER JOIN LOGICAL_LIBRARY ON " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " + "INNER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "WHERE " +// "TAPE.LABEL_DRIVE IS NOT NULL AND " // Set when the tape has been labelled +// "TAPE.LABEL_TIME IS NOT NULL AND " // Set when the tape has been labelled + "TAPE.TAPE_STATE = :TAPE_STATE AND " + "TAPE.IS_FULL = '0' AND " + "TAPE.IS_FROM_CASTOR = '0' AND " + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME " + "ORDER BY TAPE.DATA_IN_BYTES DESC"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName); + stmt.bindString(":TAPE_STATE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); + auto rset = stmt.executeQuery(); + while (rset.next()) { + TapeForWriting tape; + tape.vid = rset.columnString("VID"); + tape.mediaType = rset.columnString("MEDIA_TYPE"); + tape.vendor = rset.columnString("VENDOR"); + tape.tapePool = rset.columnString("TAPE_POOL_NAME"); + tape.vo = rset.columnString("VO"); + tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); + tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); + tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), + "[RdbmsCatalogue::getTapesForWriting()]"); + + tapes.push_back(tape); + } + return tapes; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::Label::Format RdbmsTapeCatalogue::getTapeLabelFormat(const std::string& vid) const { + try { + const char *const sql = + "SELECT " + "TAPE.LABEL_FORMAT AS LABEL_FORMAT " + "FROM " + "TAPE " + "WHERE " + "VID = :VID"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if(rset.next()) { + return common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), + "[RdbmsCatalogue::getTapeLabelFormat()]"); + } else { + throw exception::Exception(std::string("No such tape with vid=") + vid); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeIsFromCastorInUnitTests(const std::string &vid) { + try { + const char *const sql = + "UPDATE TAPE SET " + "IS_FROM_CASTOR = '1' " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::Exception(std::string("Tape ") + vid + " does not exist"); + } + + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("isFromCastor", 1) + .add("method", "setTapeIsFromCastorInUnitTests"); + lc.log(log::INFO, "Catalogue - system modified tape - isFromCastor"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) { + try { + modifyTapeState(admin,vid,common::dataStructures::Tape::DISABLED,std::nullopt,reason); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string & reason) { + try { + modifyTapeState(admin,vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,reason); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeDirty(const std::string & vid) { + try { + auto conn = m_connPool->getConn(); + RdbmsCatalogueUtils::setTapeDirty(conn,vid); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::optional<std::string> &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("userComment", comment ? comment.value() : "") + .add("lastUpdateUserName", admin.username) + .add("lastUpdateHostName", admin.host) + .add("lastUpdateTime", now); + lc.log(log::INFO, "Catalogue - user modified tape - userComment"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::tapeLabelled(const std::string &vid, const std::string &drive) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "LABEL_DRIVE = :LABEL_DRIVE," + "LABEL_TIME = :LABEL_TIME " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":LABEL_DRIVE", drive); + stmt.bindUint64(":LABEL_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::tapeMountedForArchive(const std::string &vid, const std::string &drive) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "LAST_WRITE_DRIVE = :LAST_WRITE_DRIVE," + "LAST_WRITE_TIME = :LAST_WRITE_TIME, " + "WRITE_MOUNT_COUNT = WRITE_MOUNT_COUNT + 1 " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":LAST_WRITE_DRIVE", drive); + stmt.bindUint64(":LAST_WRITE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if (0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("lastWriteDrive", drive) + .add("lastWriteTime", now); + lc.log(log::INFO, "Catalogue - system modified tape - mountedForArchive"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::tapeMountedForRetrieve(const std::string &vid, const std::string &drive) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE SET " + "LAST_READ_DRIVE = :LAST_READ_DRIVE," + "LAST_READ_TIME = :LAST_READ_TIME, " + "READ_MOUNT_COUNT = READ_MOUNT_COUNT + 1 " + "WHERE " + "VID = :VID"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":LAST_READ_DRIVE", drive); + stmt.bindUint64(":LAST_READ_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape ") + vid + " because it does not exist"); + } + + log::LogContext lc(m_log); + log::ScopedParamContainer spc(lc); + spc.add("vid", vid) + .add("lastReadDrive", drive) + .add("lastReadTime", now); + lc.log(log::INFO, "Catalogue - system modified tape - mountedForRetrieve"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::Tape> RdbmsTapeCatalogue::getTapes(rdbms::Conn &conn, + const TapeSearchCriteria &searchCriteria) const { + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.vid)) + throw exception::UserError("VID cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.mediaType)) + throw exception::UserError("Media type cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.vendor)) + throw exception::UserError("Vendor cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.logicalLibrary)) + throw exception::UserError("Logical library cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.tapePool)) + throw exception::UserError("Tape pool cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.vo)) + throw exception::UserError("Virtual organisation cannot be an empty string"); + if(RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.diskFileIds)) + throw exception::UserError("Disk file ID list cannot be empty"); + + try { + if(searchCriteria.tapePool && !RdbmsCatalogueUtils::tapePoolExists(conn, searchCriteria.tapePool.value())) { + UserSpecifiedANonExistentTapePool ex; + ex.getMessage() << "Cannot list tapes because tape pool " + searchCriteria.tapePool.value() + " does not exist"; + throw ex; + } + + std::list<common::dataStructures::Tape> tapes; + std::string sql = + "SELECT " + "TAPE.VID AS VID," + "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," + "TAPE.VENDOR AS VENDOR," + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," + "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," + "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," + "TAPE.NB_MASTER_FILES AS NB_MASTER_FILES," + "TAPE.MASTER_DATA_IN_BYTES AS MASTER_DATA_IN_BYTES," + "TAPE.LAST_FSEQ AS LAST_FSEQ," + "TAPE.IS_FULL AS IS_FULL," + "TAPE.DIRTY AS DIRTY," + + "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," + + "TAPE.LABEL_FORMAT AS LABEL_FORMAT," + + "TAPE.LABEL_DRIVE AS LABEL_DRIVE," + "TAPE.LABEL_TIME AS LABEL_TIME," + + "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," + "TAPE.LAST_READ_TIME AS LAST_READ_TIME," + + "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," + "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," + + "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," + "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," + + "TAPE.VERIFICATION_STATUS AS VERIFICATION_STATUS," + + "TAPE.USER_COMMENT AS USER_COMMENT," + + "TAPE.TAPE_STATE AS TAPE_STATE," + "TAPE.STATE_REASON AS STATE_REASON," + "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," + "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," + + "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "INNER JOIN LOGICAL_LIBRARY ON " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " + "INNER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID"; + + if(searchCriteria.vid || + searchCriteria.mediaType || + searchCriteria.vendor || + searchCriteria.logicalLibrary || + searchCriteria.tapePool || + searchCriteria.vo || + searchCriteria.capacityInBytes || + searchCriteria.full || + searchCriteria.diskFileIds || + searchCriteria.state || + searchCriteria.fromCastor) { + sql += " WHERE"; + } + + bool addedAWhereConstraint = false; + + if(searchCriteria.vid) { + sql += " TAPE.VID = :VID"; + addedAWhereConstraint = true; + } + if(searchCriteria.mediaType) { + if(addedAWhereConstraint) sql += " AND "; + sql += " MEDIA_TYPE.MEDIA_TYPE_NAME = :MEDIA_TYPE"; + addedAWhereConstraint = true; + } + if(searchCriteria.vendor) { + if(addedAWhereConstraint) sql += " AND "; + sql += " TAPE.VENDOR = :VENDOR"; + addedAWhereConstraint = true; + } + if(searchCriteria.logicalLibrary) { + if(addedAWhereConstraint) sql += " AND "; + sql += " LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME = :LOGICAL_LIBRARY_NAME"; + addedAWhereConstraint = true; + } + if(searchCriteria.tapePool) { + if(addedAWhereConstraint) sql += " AND "; + sql += " TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + addedAWhereConstraint = true; + } + if(searchCriteria.vo) { + if(addedAWhereConstraint) sql += " AND "; + sql += " VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME = :VO"; + addedAWhereConstraint = true; + } + if(searchCriteria.capacityInBytes) { + if(addedAWhereConstraint) sql += " AND "; + sql += " MEDIA_TYPE.CAPACITY_IN_BYTES = :CAPACITY_IN_BYTES"; + addedAWhereConstraint = true; + } + if(searchCriteria.full) { + if(addedAWhereConstraint) sql += " AND "; + sql += " TAPE.IS_FULL = :IS_FULL"; + addedAWhereConstraint = true; + } + if(searchCriteria.diskFileIds) { + if(addedAWhereConstraint) sql += " AND "; + sql += " VID IN (" + "SELECT DISTINCT A.VID " + "FROM " + "TAPE_FILE A, ARCHIVE_FILE B " + "WHERE " + "A.ARCHIVE_FILE_ID = B.ARCHIVE_FILE_ID AND " + "B.DISK_FILE_ID IN (:DISK_FID0)" + //"B.DISK_FILE_ID IN (:DISK_FID0, :DISK_FID1, :DISK_FID2, :DISK_FID3, :DISK_FID4, :DISK_FID5, :DISK_FID6, :DISK_FID7, :DISK_FID8, :DISK_FID9)" + ")"; + addedAWhereConstraint = true; + } + + if(searchCriteria.state) { + if(addedAWhereConstraint) sql += " AND "; + sql += " TAPE.TAPE_STATE = :TAPE_STATE"; + addedAWhereConstraint = true; + } + if(searchCriteria.fromCastor) { + if(addedAWhereConstraint) sql += " AND "; + sql += " TAPE.IS_FROM_CASTOR = :FROM_CASTOR"; + addedAWhereConstraint = true; + } + + sql += " ORDER BY TAPE.VID"; + + auto stmt = conn.createStmt(sql); + + if(searchCriteria.vid) stmt.bindString(":VID", searchCriteria.vid.value()); + if(searchCriteria.mediaType) stmt.bindString(":MEDIA_TYPE", searchCriteria.mediaType.value()); + if(searchCriteria.vendor) stmt.bindString(":VENDOR", searchCriteria.vendor.value()); + if(searchCriteria.logicalLibrary) stmt.bindString(":LOGICAL_LIBRARY_NAME", searchCriteria.logicalLibrary.value()); + if(searchCriteria.tapePool) stmt.bindString(":TAPE_POOL_NAME", searchCriteria.tapePool.value()); + if(searchCriteria.vo) stmt.bindString(":VO", searchCriteria.vo.value()); + if(searchCriteria.capacityInBytes) stmt.bindUint64(":CAPACITY_IN_BYTES", searchCriteria.capacityInBytes.value()); + if(searchCriteria.full) stmt.bindBool(":IS_FULL", searchCriteria.full.value()); + if(searchCriteria.fromCastor) stmt.bindBool(":FROM_CASTOR", searchCriteria.fromCastor.value()); + try{ + if(searchCriteria.state) + stmt.bindString(":TAPE_STATE", cta::common::dataStructures::Tape::stateToString(searchCriteria.state.value())); + } catch(cta::exception::Exception &ex){ + throw cta::exception::UserError(std::string("The state provided does not exist. Possible values are: ") + + cta::common::dataStructures::Tape::getAllPossibleStates()); + } + + // Disk file ID lookup requires multiple queries + std::vector<std::string>::const_iterator diskFileId_it; + std::set<std::string> vidsInList; + if(searchCriteria.diskFileIds) diskFileId_it = searchCriteria.diskFileIds.value().begin(); + int num_queries = searchCriteria.diskFileIds ? searchCriteria.diskFileIds.value().size() : 1; + + for(int i = 0; i < num_queries; ++i) { + if(searchCriteria.diskFileIds) { + stmt.bindString(":DISK_FID0", *diskFileId_it++); + } + + auto rset = stmt.executeQuery(); + while (rset.next()) { + auto vid = rset.columnString("VID"); + if(vidsInList.count(vid) == 1) continue; + vidsInList.insert(vid); + + common::dataStructures::Tape tape; + + tape.vid = vid; + tape.mediaType = rset.columnString("MEDIA_TYPE"); + tape.vendor = rset.columnString("VENDOR"); + tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); + tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); + tape.vo = rset.columnString("VO"); + tape.encryptionKeyName = rset.columnOptionalString("ENCRYPTION_KEY_NAME"); + tape.capacityInBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + tape.dataOnTapeInBytes = rset.columnUint64("DATA_IN_BYTES"); + tape.nbMasterFiles = rset.columnUint64("NB_MASTER_FILES"); + tape.masterDataInBytes = rset.columnUint64("MASTER_DATA_IN_BYTES"); + tape.lastFSeq = rset.columnUint64("LAST_FSEQ"); + tape.full = rset.columnBool("IS_FULL"); + tape.dirty = rset.columnBool("DIRTY"); + tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); + + tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), + "[RdbmsCatalogue::getTapes()]"); + + 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.readMountCount = rset.columnUint64("READ_MOUNT_COUNT"); + tape.writeMountCount = rset.columnUint64("WRITE_MOUNT_COUNT"); + + tape.verificationStatus = rset.columnOptionalString("VERIFICATION_STATUS"); + + auto optionalComment = rset.columnOptionalString("USER_COMMENT"); + tape.comment = optionalComment ? optionalComment.value() : ""; + + tape.setState(rset.columnString("TAPE_STATE")); + tape.stateReason = rset.columnOptionalString("STATE_REASON"); + tape.stateUpdateTime = rset.columnUint64("STATE_UPDATE_TIME"); + tape.stateModifiedBy = rset.columnString("STATE_MODIFIED_BY"); + + tape.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + tape.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + tape.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + tape.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + tape.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + tape.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + tapes.push_back(tape); + } + } + if(searchCriteria.diskFileIds) { + // When searching by diskFileId, results are not guaranteed to be in sorted order + tapes.sort([](const common::dataStructures::Tape &a, const common::dataStructures::Tape &b) { return a.vid < b.vid; }); + } + + return tapes; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq) { + try { + threading::MutexLocker locker(m_rdbmsCatalogue->m_mutex); + + const uint64_t currentValue = getTapeLastFSeq(conn, vid); + if(lastFSeq != currentValue + 1) { + exception::Exception ex; + ex.getMessage() << "The last FSeq MUST be incremented by exactly one: currentValue=" << currentValue << + ",nextValue=" << lastFSeq; + throw ex; + } + const char *const sql = + "UPDATE TAPE SET " + "LAST_FSEQ = :LAST_FSEQ " + "WHERE " + "VID=:VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.bindUint64(":LAST_FSEQ", lastFSeq); + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::deleteTapeFiles(rdbms::Conn& conn, const std::string& vid) const { + try { + const char * const sql = + "DELETE FROM TAPE_FILE WHERE VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + RdbmsCatalogueUtils::setTapeDirty(conn,vid); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t RdbmsTapeCatalogue::getNbFilesOnTape(rdbms::Conn& conn, const std::string& vid) const { + try { + const char *const sql = + "SELECT COUNT(*) AS NB_FILES FROM TAPE_FILE " + "WHERE VID = :VID "; + + auto stmt = conn.createStmt(sql); + + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + rset.next(); + return rset.columnUint64("NB_FILES"); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeCatalogue::resetTapeCounters(rdbms::Conn& conn, const common::dataStructures::SecurityIdentity& admin, + const std::string& vid) const { + try { + const time_t now = time(nullptr); + const char * const sql = + "UPDATE TAPE SET " + "DATA_IN_BYTES = 0," + "MASTER_DATA_IN_BYTES = 0," + "LAST_FSEQ = 0," + "NB_MASTER_FILES = 0," + "NB_COPY_NB_1 = 0," + "COPY_NB_1_IN_BYTES = 0," + "NB_COPY_NB_GT_1 = 0," + "COPY_NB_GT_1_IN_BYTES = 0," + "IS_FULL = '0'," + "IS_FROM_CASTOR = '0'," + "VERIFICATION_STATUS = :VERIFICATION_STATUS," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME," + "DIRTY = '0' " + "WHERE " + "VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VERIFICATION_STATUS", std::nullopt); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VID", vid); + stmt.executeNonQuery(); + } catch (exception::Exception &ex){ + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<common::dataStructures::TapeLog> RdbmsTapeCatalogue::getTapeLogFromRset(const rdbms::Rset &rset, + const std::string &driveColName, const std::string &timeColName) const { + try { + const std::optional<std::string> drive = rset.columnOptionalString(driveColName); + const std::optional<uint64_t> time = rset.columnOptionalUint64(timeColName); + + if(!drive && !time) { + return std::nullopt; + } + + if(drive && !time) { + throw exception::Exception(std::string("Database column ") + driveColName + " contains " + drive.value() + + " but column " + timeColName + " is nullptr"); + } + + if(time && !drive) { + throw exception::Exception(std::string("Database column ") + timeColName + " contains " + + std::to_string(time.value()) + " but column " + driveColName + " is nullptr"); + } + + common::dataStructures::TapeLog tapeLog; + tapeLog.drive = drive.value(); + tapeLog.time = time.value(); + + return tapeLog; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::string RdbmsTapeCatalogue::getSelectTapesBy100VidsSql() const { + std::stringstream sql; + + sql << + "SELECT " + "TAPE.VID AS VID," + "MEDIA_TYPE.MEDIA_TYPE_NAME AS MEDIA_TYPE," + "TAPE.VENDOR AS VENDOR," + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME," + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "TAPE.ENCRYPTION_KEY_NAME AS ENCRYPTION_KEY_NAME," + "MEDIA_TYPE.CAPACITY_IN_BYTES AS CAPACITY_IN_BYTES," + "TAPE.DATA_IN_BYTES AS DATA_IN_BYTES," + "TAPE.LAST_FSEQ AS LAST_FSEQ," + "TAPE.IS_FULL AS IS_FULL," + "TAPE.IS_FROM_CASTOR AS IS_FROM_CASTOR," + + "TAPE.LABEL_FORMAT AS LABEL_FORMAT," + + "TAPE.LABEL_DRIVE AS LABEL_DRIVE," + "TAPE.LABEL_TIME AS LABEL_TIME," + + "TAPE.LAST_READ_DRIVE AS LAST_READ_DRIVE," + "TAPE.LAST_READ_TIME AS LAST_READ_TIME," + + "TAPE.LAST_WRITE_DRIVE AS LAST_WRITE_DRIVE," + "TAPE.LAST_WRITE_TIME AS LAST_WRITE_TIME," + + "TAPE.READ_MOUNT_COUNT AS READ_MOUNT_COUNT," + "TAPE.WRITE_MOUNT_COUNT AS WRITE_MOUNT_COUNT," + + "TAPE.USER_COMMENT AS USER_COMMENT," + + "TAPE.TAPE_STATE AS TAPE_STATE," + "TAPE.STATE_REASON AS STATE_REASON," + "TAPE.STATE_UPDATE_TIME AS STATE_UPDATE_TIME," + "TAPE.STATE_MODIFIED_BY AS STATE_MODIFIED_BY," + + "TAPE.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "TAPE.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "TAPE.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "TAPE.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "TAPE.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "TAPE.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "INNER JOIN LOGICAL_LIBRARY ON " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " + "INNER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "VID IN (:V1"; + + for(uint32_t i=2; i<=100; i++) { + sql << ",:V" << i; + } + + sql << ")"; + + return sql.str(); +} + +void RdbmsTapeCatalogue::executeGetTapesByVidStmtAndCollectResults(rdbms::Stmt &stmt, + common::dataStructures::VidToTapeMap &vidToTapeMap) const { + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::Tape tape; + + tape.vid = rset.columnString("VID"); + tape.mediaType = rset.columnString("MEDIA_TYPE"); + tape.vendor = rset.columnString("VENDOR"); + tape.logicalLibraryName = rset.columnString("LOGICAL_LIBRARY_NAME"); + tape.tapePoolName = rset.columnString("TAPE_POOL_NAME"); + tape.vo = rset.columnString("VO"); + 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.full = rset.columnBool("IS_FULL"); + tape.isFromCastor = rset.columnBool("IS_FROM_CASTOR"); + + tape.labelFormat = common::dataStructures::Label::validateFormat(rset.columnOptionalUint8("LABEL_FORMAT"), + "[RdbmsCatalogue::executeGetTapesByVidsStmtAndCollectResults()]"); + + 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.readMountCount = rset.columnUint64("READ_MOUNT_COUNT"); + tape.writeMountCount = rset.columnUint64("WRITE_MOUNT_COUNT"); + auto optionalComment = rset.columnOptionalString("USER_COMMENT"); + tape.comment = optionalComment ? optionalComment.value() : ""; + + tape.setState(rset.columnString("TAPE_STATE")); + tape.stateReason = rset.columnOptionalString("STATE_REASON"); + tape.stateUpdateTime = rset.columnUint64("STATE_UPDATE_TIME"); + tape.stateModifiedBy = rset.columnString("STATE_MODIFIED_BY"); + + tape.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + tape.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + tape.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + tape.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + tape.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + tape.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + vidToTapeMap[tape.vid] = tape; + } +} + +std::string RdbmsTapeCatalogue::getSelectVidToLogicalLibraryBy100Sql() const { + std::stringstream sql; + + sql << + "SELECT " + "TAPE.VID AS VID, " + "LOGICAL_LIBRARY.LOGICAL_LIBRARY_NAME AS LOGICAL_LIBRARY_NAME " + "FROM " + "TAPE " + "INNER JOIN LOGICAL_LIBRARY ON " + "TAPE.LOGICAL_LIBRARY_ID = LOGICAL_LIBRARY.LOGICAL_LIBRARY_ID " + "WHERE " + "VID IN (:V1"; + + for(uint32_t i=2; i<=100; i++) { + sql << ",:V" << i; + } + + sql << ")"; + + return sql.str(); +} + +void RdbmsTapeCatalogue::executeGetVidToLogicalLibraryBy100StmtAndCollectResults(rdbms::Stmt &stmt, +std::map<std::string, std::string> &vidToLogicalLibrary) const { + auto rset = stmt.executeQuery(); + while (rset.next()) { + vidToLogicalLibrary[rset.columnString("VID")] = rset.columnString("LOGICAL_LIBRARY_NAME"); + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsTapeCatalogue.hpp b/catalogue/rdbms/RdbmsTapeCatalogue.hpp new file mode 100644 index 0000000000..134ebe0fb0 --- /dev/null +++ b/catalogue/rdbms/RdbmsTapeCatalogue.hpp @@ -0,0 +1,186 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/TapeCatalogue.hpp" +#include "common/log/Logger.hpp" +#include "common/threading/Mutex.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +class Rset; +class Stmt; +} + +namespace catalogue { + +class RdbmsCatalogue; +class TapeItemWritten; + +class RdbmsTapeCatalogue : public TapeCatalogue { +public: + ~RdbmsTapeCatalogue() override = default; + + void createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes & tape) override; + + void deleteTape(const std::string &vid) override; + + std::list<common::dataStructures::Tape> getTapes(const TapeSearchCriteria &searchCriteria) const override; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const override; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const override; + + std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const override; + + void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + cta::log::LogContext & lc) override; + + void checkTapeForLabel(const std::string &vid) override; + + void tapeLabelled(const std::string &vid, const std::string &drive) override; + + uint64_t getNbFilesOnTape(const std::string &vid) const override; + + void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &mediaType) override; + + void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &vendor) override; + + void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &logicalLibraryName) override; + + void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &tapePoolName) override; + + void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &encryptionKeyName) override; + + void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &verificationStatus) override; + + void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, + const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) override; + + bool tapeExists(const std::string &vid) const override; + + void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool fullValue) override; + + void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) override; + + void setTapeIsFromCastorInUnitTests(const std::string &vid) override; + + void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) override; + + void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) override; + + void setTapeDirty(const std::string & vid) override; + + void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::optional<std::string> &comment) override; + + void tapeMountedForArchive(const std::string &vid, const std::string &drive) override; + + void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) override; + + void noSpaceLeftOnTape(const std::string &vid) override; + + std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const override; + + common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const override; + +protected: + RdbmsTapeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue); + + /** + * 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. + */ + virtual uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const = 0; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + std::list<common::dataStructures::Tape> getTapes(rdbms::Conn &conn, const TapeSearchCriteria &searchCriteria) const; + + std::string getSelectTapesBy100VidsSql() const; + + void executeGetTapesByVidStmtAndCollectResults(rdbms::Stmt &stmt, + common::dataStructures::VidToTapeMap &vidToTapeMap) const; + + std::string getSelectVidToLogicalLibraryBy100Sql() const; + + void executeGetVidToLogicalLibraryBy100StmtAndCollectResults(rdbms::Stmt &stmt, + std::map<std::string, std::string> &vidToLogicalLibrary) const; + + /** + * Returns the number of any files contained in the tape identified by its vid + * @param conn the database connection + * @param vid the vid in which we will count the number of files + * @return the number of files on the tape + */ + uint64_t getNbFilesOnTape(rdbms::Conn &conn, const std::string &vid) const; + + /** + * Reset the counters of a tape + * @param conn the database connection + * @param admin the administrator + * @param vid the vid to reset the counters + */ + void resetTapeCounters(rdbms::Conn &conn, const common::dataStructures::SecurityIdentity &admin, + const std::string& vid) const; + + /** + * Delete all the tape files of the VID passed in parameter + * @param conn the database connection + * @param vid the vid in which we want to remove all the tape files + */ + void deleteTapeFiles(rdbms::Conn &conn, const std::string& vid) const; + + std::optional<common::dataStructures::TapeLog> getTapeLogFromRset(const rdbms::Rset &rset, + const std::string &driveColName, const std::string &timeColName) const; + + /** + * Sets the last FSeq of the specified tape to the specified value. + * + * @param conn The database connection. + * @param vid The volume identifier of the tape. + * @param lastFseq The new value of the last FSeq. + */ + void setTapeLastFSeq(rdbms::Conn &conn, const std::string &vid, const uint64_t lastFSeq); +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsTapeFileCatalogue.cpp b/catalogue/rdbms/RdbmsTapeFileCatalogue.cpp new file mode 100644 index 0000000000..9fdab495a0 --- /dev/null +++ b/catalogue/rdbms/RdbmsTapeFileCatalogue.cpp @@ -0,0 +1,343 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <algorithm> +#include <memory> +#include <string> +#include <utility> + +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsMountPolicyCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsTapeFileCatalogue::RdbmsTapeFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) { +} + +void RdbmsTapeFileCatalogue::deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) { + log::LogContext lc(m_log); + auto conn = m_connPool->getConn(); + copyTapeFileToFileRecyleLogAndDelete(conn, file, reason, lc); +} + +void RdbmsTapeFileCatalogue::copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, log::LogContext & lc) const { + try { + utils::Timer timer; + log::TimingList timingList; + copyTapeFileToFileRecyleLogAndDeleteTransaction(conn, file, reason, &timer, &timingList, lc); + timingList.insertAndReset("commitTime", timer); + log::ScopedParamContainer spc(lc); + spc.add("archiveFileId", file.archiveFileID); + spc.add("diskFileId", file.diskFileId); + spc.add("diskFilePath", file.diskFileInfo.path); + spc.add("diskInstance", file.diskInstance); + timingList.addToLog(spc); + lc.log(log::INFO, "In RdbmsFileRecycleLogCatalogue::copyArchiveFileToRecycleBinAndDelete: " + "ArchiveFile moved to the recycle-bin."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeFileCatalogue::checkTapeItemWrittenFieldsAreSet(const std::string& callingFunc, + const TapeItemWritten& event) const { + try { + if(event.vid.empty()) throw exception::Exception("vid is an empty string"); + if(0 == event.fSeq) throw exception::Exception("fSeq is 0"); + if(event.tapeDrive.empty()) throw exception::Exception("tapeDrive is an empty string"); + } catch (exception::Exception &ex) { + throw exception::Exception(callingFunc + " failed: TapeItemWrittenEvent is invalid: " + ex.getMessage().str()); + } +} + +void RdbmsTapeFileCatalogue::checkTapeFileWrittenFieldsAreSet(const std::string &callingFunc, + const TapeFileWritten &event) + const { + try { + if(event.diskInstance.empty()) throw exception::Exception("diskInstance is an empty string"); + if(event.diskFileId.empty()) throw exception::Exception("diskFileId is an empty string"); + if(0 == event.diskFileOwnerUid) throw exception::Exception("diskFileOwnerUid is 0"); + if(0 == event.size) throw exception::Exception("size is 0"); + if(event.checksumBlob.length() == 0) throw exception::Exception("checksumBlob is an empty string"); + if(event.storageClassName.empty()) throw exception::Exception("storageClassName is an empty string"); + if(event.vid.empty()) throw exception::Exception("vid is an empty string"); + if(0 == event.fSeq) throw exception::Exception("fSeq is 0"); + if(0 == event.blockId && event.fSeq != 1) throw exception::Exception("blockId is 0 and fSeq is not 1"); + if(0 == event.copyNb) throw exception::Exception("copyNb is 0"); + if(event.tapeDrive.empty()) throw exception::Exception("tapeDrive is an empty string"); + } catch (exception::Exception &ex) { + throw exception::Exception(callingFunc + " failed: TapeFileWrittenEvent is invalid: " + ex.getMessage().str()); + } +} + +//------------------------------------------------------------------------------ +// insertTapeFile +//------------------------------------------------------------------------------ +void RdbmsTapeFileCatalogue::insertTapeFile(rdbms::Conn &conn, const common::dataStructures::TapeFile &tapeFile, + const uint64_t archiveFileId) { + rdbms::AutoRollback autoRollback(conn); + try{ + const auto fileRecycleLogCatalogue = static_cast<RdbmsFileRecycleLogCatalogue*>( + m_rdbmsCatalogue->FileRecycleLog().get()); + std::list<InsertFileRecycleLog> insertedFilesRecycleLog + = fileRecycleLogCatalogue->insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn,tapeFile,archiveFileId); + { + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO TAPE_FILE(" + "VID," + "FSEQ," + "BLOCK_ID," + "LOGICAL_SIZE_IN_BYTES," + "COPY_NB," + "CREATION_TIME," + "ARCHIVE_FILE_ID)" + "VALUES(" + ":VID," + ":FSEQ," + ":BLOCK_ID," + ":LOGICAL_SIZE_IN_BYTES," + ":COPY_NB," + ":CREATION_TIME," + ":ARCHIVE_FILE_ID)"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":VID", tapeFile.vid); + stmt.bindUint64(":FSEQ", tapeFile.fSeq); + stmt.bindUint64(":BLOCK_ID", tapeFile.blockId); + stmt.bindUint64(":LOGICAL_SIZE_IN_BYTES", tapeFile.fileSize); + stmt.bindUint64(":COPY_NB", tapeFile.copyNb); + stmt.bindUint64(":CREATION_TIME", now); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + { + for(auto& fileRecycleLog: insertedFilesRecycleLog){ + const char *const sql = + "DELETE FROM " + "TAPE_FILE " + "WHERE " + "VID=:VID AND " + "FSEQ=:FSEQ"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID",fileRecycleLog.vid); + stmt.bindUint64(":FSEQ",fileRecycleLog.fSeq); + stmt.executeNonQuery(); + } + } + conn.commit(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeFileCatalogue::deleteTapeFiles(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest& request) const { + try { + //Delete the tape files after. + const char *const deleteTapeFilesSql = + "DELETE FROM " + "TAPE_FILE " + "WHERE TAPE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + + auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); + deleteTapeFilesStmt.bindUint64(":ARCHIVE_FILE_ID",request.archiveFileID); + deleteTapeFilesStmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapeFileCatalogue::deleteTapeFiles(rdbms::Conn & conn, + const common::dataStructures::ArchiveFile& file) const { + try { + for(auto &tapeFile: file.tapeFiles) { + + //Delete the tape file. + const char *const deleteTapeFilesSql = + "DELETE FROM " + "TAPE_FILE " + "WHERE " + "TAPE_FILE.VID = :VID AND " + "TAPE_FILE.FSEQ = :FSEQ"; + + auto deleteTapeFilesStmt = conn.createStmt(deleteTapeFilesSql); + deleteTapeFilesStmt.bindString(":VID", tapeFile.vid); + deleteTapeFilesStmt.bindUint64(":FSEQ", tapeFile.fSeq); + deleteTapeFilesStmt.executeNonQuery(); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::RetrieveFileQueueCriteria RdbmsTapeFileCatalogue::prepareToRetrieveFile( + const std::string &diskInstanceName, const uint64_t archiveFileId, + const common::dataStructures::RequesterIdentity &user, const std::optional<std::string>& activity, + log::LogContext &lc, const std::optional<std::string> &mountPolicyName) { + try { + cta::utils::Timer t; + common::dataStructures::RetrieveFileQueueCriteria criteria; + { + auto conn = m_connPool->getConn(); + const auto getConnTime = t.secs(utils::Timer::resetCounter); + const auto archiveFileCatalogue = static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + auto archiveFile = archiveFileCatalogue->getArchiveFileToRetrieveByArchiveFileId(conn, archiveFileId); + const auto getArchiveFileTime = t.secs(utils::Timer::resetCounter); + if(nullptr == archiveFile.get()) { + exception::UserError ex; + auto tapeFileStateList = archiveFileCatalogue->getTapeFileStateListForArchiveFileId(conn, archiveFileId); + if (tapeFileStateList.empty()) { + ex.getMessage() << "File with archive file ID " << archiveFileId << " does not exist in CTA namespace"; + throw ex; + } + const auto nonBrokenState = std::find_if(std::begin(tapeFileStateList), std::end(tapeFileStateList), + [](std::pair<std::string, std::string> state) { + return (state.second != "BROKEN") + && (state.second != "BROKEN_PENDING") + && (state.second != "EXPORTED") + && (state.second != "EXPORTED_PENDING"); + }); + + if (nonBrokenState != std::end(tapeFileStateList)) { + ex.getMessage() << "WARNING: File with archive file ID " << archiveFileId + << " exits in CTA namespace but is temporarily unavailable on " << nonBrokenState->second << " tape " + << nonBrokenState->first; + throw ex; + } + const auto brokenState = tapeFileStateList.front(); + //All tape files are on broken tapes, just generate an error about the first + ex.getMessage() << "ERROR: File with archive file ID " << archiveFileId + << " exits in CTA namespace but is permanently unavailable on " << brokenState.second << " tape " + << brokenState.first; + throw ex; + } + if (mountPolicyName) { + const auto mountPolicyCatalogue = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + std::optional<common::dataStructures::MountPolicy> mountPolicy = mountPolicyCatalogue->getMountPolicy(conn, mountPolicyName.value()); + if (mountPolicy) { + criteria.archiveFile = *archiveFile; + criteria.mountPolicy = mountPolicy.value(); + return criteria; + } else { + log::ScopedParamContainer spc(lc); + spc.add("mountPolicyName", mountPolicyName.value()) + .add("archiveFileId", archiveFileId); + lc.log(log::WARNING, "Catalogue::prepareToRetrieve Could not find specified mount policy, falling back to querying mount rules"); + } + } + + if(diskInstanceName != archiveFile->diskInstance) { + exception::UserError ue; + ue.getMessage() << "Cannot retrieve file because the disk instance of the request does not match that of the" + " archived file: archiveFileId=" << archiveFileId << + " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << archiveFile->diskInstance; + throw ue; + } + + t.reset(); + RequesterAndGroupMountPolicies mountPolicies; + const auto mountPolicyCatalogue = static_cast<RdbmsMountPolicyCatalogue*>(m_rdbmsCatalogue->MountPolicy().get()); + if (activity) { + mountPolicies = mountPolicyCatalogue->getMountPolicies(conn, diskInstanceName, user.name, user.group, activity.value()); + } else { + mountPolicies = mountPolicyCatalogue->getMountPolicies(conn, diskInstanceName, user.name, user.group); + } + + const auto getMountPoliciesTime = t.secs(utils::Timer::resetCounter); + + log::ScopedParamContainer spc(lc); + spc.add("getConnTime", getConnTime) + .add("getArchiveFileTime", getArchiveFileTime) + .add("getMountPoliciesTime", getMountPoliciesTime); + lc.log(log::INFO, "Catalogue::prepareToRetrieve internal timings"); + + // Requester activity mount policies overrule requester mount policies + // Requester mount policies overrule requester group mount policies + common::dataStructures::MountPolicy mountPolicy; + if (!mountPolicies.requesterActivityMountPolicies.empty()) { + //More than one may match the activity, so choose the one with highest retrieve priority + mountPolicy = *std::max_element(mountPolicies.requesterActivityMountPolicies.begin(), + mountPolicies.requesterActivityMountPolicies.end(), + [](const common::dataStructures::MountPolicy &p1, common::dataStructures::MountPolicy &p2) { + return p1.retrievePriority < p2.retrievePriority; + }); + } else if(!mountPolicies.requesterMountPolicies.empty()) { + mountPolicy = mountPolicies.requesterMountPolicies.front(); + } else if(!mountPolicies.requesterGroupMountPolicies.empty()) { + mountPolicy = mountPolicies.requesterGroupMountPolicies.front(); + } else { + mountPolicies = mountPolicyCatalogue->getMountPolicies(conn, diskInstanceName, "default", user.group); + + if(!mountPolicies.requesterMountPolicies.empty()) { + mountPolicy = mountPolicies.requesterMountPolicies.front(); + } else { + exception::UserError ue; + ue.getMessage() + << "Cannot retrieve file because there are no mount rules for the requester, activity or their group:" + << " archiveFileId=" << archiveFileId << " requester=" << diskInstanceName << ":" << user.name << ":" + << user.group; + if (activity) { + ue.getMessage() << " activity=" << activity.value(); + } + throw ue; + } + } + criteria.archiveFile = *archiveFile; + criteria.mountPolicy = mountPolicy; + } + return criteria; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsTapeFileCatalogue.hpp b/catalogue/rdbms/RdbmsTapeFileCatalogue.hpp new file mode 100644 index 0000000000..bfd8b6a6ca --- /dev/null +++ b/catalogue/rdbms/RdbmsTapeFileCatalogue.hpp @@ -0,0 +1,131 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/interfaces/TapeFileCatalogue.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct ArchiveFile; +struct DeleteArchiveRequest; +struct TapeFile; +} // namespace dataStructures +} // namespace common + +namespace log { +class TimingList; +} + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace utils { +class Timer; +} + +namespace catalogue { + +struct TapeItemWritten; +struct TapeFileWritten; +class RdbmsCatalogue; + +class RdbmsTapeFileCatalogue : public TapeFileCatalogue { +public: + ~RdbmsTapeFileCatalogue() override = default; + + void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) override; + + common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string &diskInstanceName, + const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity &user, + const std::optional<std::string> & activity, log::LogContext &lc, + const std::optional<std::string> &mountPolicyName = std::nullopt) override; + +protected: + RdbmsTapeFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue); + +protected: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + +protected: + void copyTapeFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, log::LogContext & lc) const; + + virtual void copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const = 0; + + /** + * Throws an exception if one of the fields of the specified event have not + * been set. + * + * @param callingFunc The name of the calling function. + * @param event The evnt to be checked. + */ + void checkTapeItemWrittenFieldsAreSet(const std::string &callingFunc, const TapeItemWritten &event) const; + + /** + * Throws an exception if one of the fields of the specified event have not + * been set. + * + * @param callingFunc The name of the calling function. + * @param event The evnt to be checked. + */ + void checkTapeFileWrittenFieldsAreSet(const std::string &callingFunc, const TapeFileWritten &event) const; + + friend class RdbmsFileRecycleLogCatalogue; + /** + * Inserts the specified tape file into the Tape table. + * + * @param conn The database connection. + * @param tapeFile The tape file. + * @param archiveFileId The identifier of the archive file of which the tape + * file is a copy. + */ + void insertTapeFile(rdbms::Conn &conn, const common::dataStructures::TapeFile &tapeFile, + const uint64_t archiveFileId); + + friend class OracleArchiveFileCatalogue; + friend class PostgresArchiveFileCatalogue; + friend class SqliteArchiveFileCatalogue; + /** + * Delete the TapeFiles associated to an ArchiveFile from the TAPE_FILE table + * @param conn the database connection + * @param file the file that contains the tape files to delete + */ + void deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::ArchiveFile &file) const; + + /** + * Delete the TapeFile from the TAPE_FILE table + * @param conn the database connection + * @param request the DeleteArchiveRequest that contains the archiveFileId to delete the corresponding tape files + */ + void deleteTapeFiles(rdbms::Conn & conn, const common::dataStructures::DeleteArchiveRequest & request) const; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/RdbmsTapePoolCatalogue.cpp b/catalogue/rdbms/RdbmsTapePoolCatalogue.cpp new file mode 100644 index 0000000000..58f181cb51 --- /dev/null +++ b/catalogue/rdbms/RdbmsTapePoolCatalogue.cpp @@ -0,0 +1,762 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <optional> +#include <string> + +#include "catalogue/interfaces/StorageClassCatalogue.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsTapePoolCatalogue.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/TapePoolSearchCriteria.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" +#include "common/log/Logger.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsTapePoolCatalogue::RdbmsTapePoolCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue) + : m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsTapePoolCatalogue::createTapePool(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot create tape pool because the tape pool name is an empty string"); + } + + if(vo.empty()) { + throw UserSpecifiedAnEmptyStringVo("Cannot create tape pool because the VO is an empty string"); + } + + if (comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create tape pool because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + auto conn = m_connPool->getConn(); + + if(RdbmsCatalogueUtils::tapePoolExists(conn, name)) { + throw exception::UserError(std::string("Cannot create tape pool ") + name + + " because a tape pool with the same name already exists"); + } + if(!RdbmsCatalogueUtils::virtualOrganizationExists(conn,vo)){ + throw exception::UserError(std::string("Cannot create tape pool ") + name + \ + " because vo : "+vo+" does not exist."); + } + 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," + "VIRTUAL_ORGANIZATION_ID," + "NB_PARTIAL_TAPES," + "IS_ENCRYPTED," + "SUPPLY," + + "USER_COMMENT," + + "CREATION_LOG_USER_NAME," + "CREATION_LOG_HOST_NAME," + "CREATION_LOG_TIME," + + "LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME)" + "SELECT " + ":TAPE_POOL_ID," + ":TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION_ID," + ":NB_PARTIAL_TAPES," + ":IS_ENCRYPTED," + ":SUPPLY," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME " + "FROM " + "VIRTUAL_ORGANIZATION " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VO"; + 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); + stmt.bindBool(":IS_ENCRYPTED", encryptionValue); + stmt.bindString(":SUPPLY", supply); + + stmt.bindString(":USER_COMMENT", comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::deleteTapePool(const std::string &name) { + try { + auto conn = m_connPool->getConn(); + + if(tapePoolUsedInAnArchiveRoute(conn, name)) { + UserSpecifiedTapePoolUsedInAnArchiveRoute ex; + ex.getMessage() << "Cannot delete tape-pool " << name << " because it is used in an archive route"; + throw ex; + } + + const uint64_t nbTapesInPool = getNbTapesInPool(conn, name); + + if(0 == nbTapesInPool) { + const char *const sql = "DELETE FROM TAPE_POOL WHERE TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete tape-pool ") + name + " because it does not exist"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } else { + throw UserSpecifiedAnEmptyTapePool(std::string("Cannot delete tape-pool ") + name + " because it is not empty"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<TapePool> RdbmsTapePoolCatalogue::getTapePools(const TapePoolSearchCriteria &searchCriteria) const { + try { + auto conn = m_connPool->getConn(); + return getTapePools(conn, searchCriteria); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<TapePool> RdbmsTapePoolCatalogue::getTapePools(rdbms::Conn &conn, + const TapePoolSearchCriteria &searchCriteria) const { + if (RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.name)) + throw exception::UserError("Pool name cannot be an empty string"); + if (RdbmsCatalogueUtils::isSetAndEmpty(searchCriteria.vo)) + throw exception::UserError("Virtual organisation cannot be an empty string"); + try { + + if (searchCriteria.name && !RdbmsCatalogueUtils::tapePoolExists(conn, searchCriteria.name.value())) { + UserSpecifiedANonExistentTapePool ex; + ex.getMessage() << "Cannot list tape pools because tape pool " + searchCriteria.name.value() + " does not exist"; + throw ex; + } + + if (searchCriteria.vo + && !RdbmsCatalogueUtils::virtualOrganizationExists(conn, searchCriteria.vo.value())) { + UserSpecifiedANonExistentVirtualOrganization ex; + ex.getMessage() << "Cannot list tape pools because virtual organization " + searchCriteria.vo.value() + " does not exist"; + throw ex; + } + + std::list<TapePool> pools; + std::string sql = + "SELECT " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES," + "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED," + "TAPE_POOL.SUPPLY AS SUPPLY," + + "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.DATA_IN_BYTES = 0 THEN 1 ELSE 0 END), 0) AS NB_EMPTY_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_DISABLED THEN 1 ELSE 0 END), 0) AS NB_DISABLED_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.IS_FULL <> '0' THEN 1 ELSE 0 END), 0) AS NB_FULL_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_ACTIVE AND TAPE.IS_FULL = '0' THEN 1 ELSE 0 END), 0) AS NB_WRITABLE_TAPES," + "COALESCE(SUM(MEDIA_TYPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES," + "COALESCE(SUM(TAPE.DATA_IN_BYTES), 0) AS DATA_IN_BYTES," + "COALESCE(SUM(TAPE.LAST_FSEQ), 0) AS NB_PHYSICAL_FILES," + + "TAPE_POOL.USER_COMMENT AS USER_COMMENT," + + "TAPE_POOL.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "TAPE_POOL.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "TAPE_POOL.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "TAPE_POOL.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "TAPE_POOL.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "TAPE_POOL.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE_POOL " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "LEFT OUTER JOIN TAPE ON " + "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID " + "LEFT OUTER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID"; + + if (searchCriteria.name || searchCriteria.vo || searchCriteria.encrypted) { + sql += " WHERE "; + } + bool addedAWhereConstraint = false; + if (searchCriteria.name) { + sql += "TAPE_POOL.TAPE_POOL_NAME = :NAME"; + addedAWhereConstraint = true; + } + + if (searchCriteria.vo) { + if (addedAWhereConstraint) sql += " AND "; + sql += "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME = :VO"; + addedAWhereConstraint = true; + } + + if (searchCriteria.encrypted) { + if (addedAWhereConstraint) sql += " AND "; + sql += "TAPE_POOL.IS_ENCRYPTED = :ENCRYPTED"; + } + + sql += + " GROUP BY " + "TAPE_POOL.TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME," + "TAPE_POOL.NB_PARTIAL_TAPES," + "TAPE_POOL.IS_ENCRYPTED," + "TAPE_POOL.SUPPLY," + "TAPE_POOL.USER_COMMENT," + "TAPE_POOL.CREATION_LOG_USER_NAME," + "TAPE_POOL.CREATION_LOG_HOST_NAME," + "TAPE_POOL.CREATION_LOG_TIME," + "TAPE_POOL.LAST_UPDATE_USER_NAME," + "TAPE_POOL.LAST_UPDATE_HOST_NAME," + "TAPE_POOL.LAST_UPDATE_TIME " + "ORDER BY " + "TAPE_POOL_NAME"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":STATE_DISABLED",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::DISABLED)); + stmt.bindString(":STATE_ACTIVE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); + + if (searchCriteria.name) { + stmt.bindString(":NAME", searchCriteria.name.value()); + } + + if (searchCriteria.vo) { + stmt.bindString(":VO", searchCriteria.vo.value()); + } + + if(searchCriteria.encrypted) { + stmt.bindBool(":ENCRYPTED", searchCriteria.encrypted.value()); + } + + auto rset = stmt.executeQuery(); + while (rset.next()) { + TapePool pool; + + pool.name = rset.columnString("TAPE_POOL_NAME"); + pool.vo.name = rset.columnString("VO"); + pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES"); + pool.encryption = rset.columnBool("IS_ENCRYPTED"); + pool.supply = rset.columnOptionalString("SUPPLY"); + pool.nbTapes = rset.columnUint64("NB_TAPES"); + pool.nbEmptyTapes = rset.columnUint64("NB_EMPTY_TAPES"); + pool.nbDisabledTapes = rset.columnUint64("NB_DISABLED_TAPES"); + pool.nbFullTapes = rset.columnUint64("NB_FULL_TAPES"); + pool.nbWritableTapes = rset.columnUint64("NB_WRITABLE_TAPES"); + pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + pool.dataBytes = rset.columnUint64("DATA_IN_BYTES"); + pool.nbPhysicalFiles = rset.columnUint64("NB_PHYSICAL_FILES"); + pool.comment = rset.columnString("USER_COMMENT"); + pool.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + pool.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + pool.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + pool.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + pool.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + pool.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + pools.push_back(pool); + } + + return pools; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<TapePool> RdbmsTapePoolCatalogue::getTapePool(const std::string &tapePoolName) const { + try { + const char *const sql = + "SELECT " + "TAPE_POOL.TAPE_POOL_NAME AS TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VO," + "TAPE_POOL.NB_PARTIAL_TAPES AS NB_PARTIAL_TAPES," + "TAPE_POOL.IS_ENCRYPTED AS IS_ENCRYPTED," + "TAPE_POOL.SUPPLY AS SUPPLY," + + "COALESCE(COUNT(TAPE.VID), 0) AS NB_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.DATA_IN_BYTES = 0 THEN 1 ELSE 0 END), 0) AS NB_EMPTY_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_DISABLED THEN 1 ELSE 0 END), 0) AS NB_DISABLED_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.IS_FULL <> '0' THEN 1 ELSE 0 END), 0) AS NB_FULL_TAPES," + "COALESCE(SUM(CASE WHEN TAPE.TAPE_STATE = :STATE_ACTIVE AND TAPE.IS_FULL = '0' THEN 1 ELSE 0 END), 0) AS NB_WRITABLE_TAPES," + "COALESCE(SUM(MEDIA_TYPE.CAPACITY_IN_BYTES), 0) AS CAPACITY_IN_BYTES," + "COALESCE(SUM(TAPE.DATA_IN_BYTES), 0) AS DATA_IN_BYTES," + "COALESCE(SUM(TAPE.LAST_FSEQ), 0) AS NB_PHYSICAL_FILES," + + "TAPE_POOL.USER_COMMENT AS USER_COMMENT," + + "TAPE_POOL.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "TAPE_POOL.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "TAPE_POOL.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "TAPE_POOL.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "TAPE_POOL.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "TAPE_POOL.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE_POOL " + "INNER JOIN VIRTUAL_ORGANIZATION ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "LEFT OUTER JOIN TAPE ON " + "TAPE_POOL.TAPE_POOL_ID = TAPE.TAPE_POOL_ID " + "LEFT OUTER JOIN MEDIA_TYPE ON " + "TAPE.MEDIA_TYPE_ID = MEDIA_TYPE.MEDIA_TYPE_ID " + "GROUP BY " + "TAPE_POOL.TAPE_POOL_NAME," + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME," + "TAPE_POOL.NB_PARTIAL_TAPES," + "TAPE_POOL.IS_ENCRYPTED," + "TAPE_POOL.SUPPLY," + "TAPE_POOL.USER_COMMENT," + "TAPE_POOL.CREATION_LOG_USER_NAME," + "TAPE_POOL.CREATION_LOG_HOST_NAME," + "TAPE_POOL.CREATION_LOG_TIME," + "TAPE_POOL.LAST_UPDATE_USER_NAME," + "TAPE_POOL.LAST_UPDATE_HOST_NAME," + "TAPE_POOL.LAST_UPDATE_TIME " + "HAVING " + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME " + "ORDER BY " + "TAPE_POOL_NAME"; + + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + stmt.bindString(":STATE_DISABLED",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::DISABLED)); + stmt.bindString(":STATE_ACTIVE",common::dataStructures::Tape::stateToString(common::dataStructures::Tape::ACTIVE)); + + auto rset = stmt.executeQuery(); + + if (!rset.next()) { + return std::nullopt; + } + + TapePool pool; + pool.name = rset.columnString("TAPE_POOL_NAME"); + pool.vo.name = rset.columnString("VO"); + pool.nbPartialTapes = rset.columnUint64("NB_PARTIAL_TAPES"); + pool.encryption = rset.columnBool("IS_ENCRYPTED"); + pool.supply = rset.columnOptionalString("SUPPLY"); + pool.nbTapes = rset.columnUint64("NB_TAPES"); + pool.nbEmptyTapes = rset.columnUint64("NB_EMPTY_TAPES"); + pool.nbDisabledTapes = rset.columnUint64("NB_DISABLED_TAPES"); + pool.nbFullTapes = rset.columnUint64("NB_FULL_TAPES"); + pool.nbWritableTapes = rset.columnUint64("NB_WRITABLE_TAPES"); + pool.capacityBytes = rset.columnUint64("CAPACITY_IN_BYTES"); + pool.dataBytes = rset.columnUint64("DATA_IN_BYTES"); + pool.nbPhysicalFiles = rset.columnUint64("NB_PHYSICAL_FILES"); + pool.comment = rset.columnString("USER_COMMENT"); + pool.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + pool.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + pool.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + pool.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + pool.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + pool.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + + return pool; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + if(vo.empty()) { + throw UserSpecifiedAnEmptyStringVo("Cannot modify tape pool because the new VO is an empty string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "VIRTUAL_ORGANIZATION_ID = (SELECT VIRTUAL_ORGANIZATION_ID FROM VIRTUAL_ORGANIZATION WHERE VIRTUAL_ORGANIZATION_NAME=:VO)," + "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 = :TAPE_POOL_NAME"; + auto conn = m_connPool->getConn(); + + if(!RdbmsCatalogueUtils::virtualOrganizationExists(conn,vo)){ + throw exception::UserError(std::string("Cannot modify tape pool ") + name +" because the vo " + vo + " does not exist"); + } + + auto stmt = conn.createStmt(sql); + stmt.bindString(":VO", vo); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + //The VO of this tapepool has changed, invalidate the tapepool-VO cache + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbPartialTapes) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "NB_PARTIAL_TAPES = :NB_PARTIAL_TAPES," + "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 = :TAPE_POOL_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":NB_PARTIAL_TAPES", nbPartialTapes); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + if(comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot modify tape pool because the new comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "USER_COMMENT = :USER_COMMENT," + "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 = :TAPE_POOL_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool encryptionValue) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "IS_ENCRYPTED = :IS_ENCRYPTED," + "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 = :TAPE_POOL_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindBool(":IS_ENCRYPTED", encryptionValue); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &supply) { + try { + if(name.empty()) { + throw UserSpecifiedAnEmptyStringTapePoolName("Cannot modify tape pool because the tape pool name is an empty" + " string"); + } + + std::optional<std::string> optionalSupply; + if(!supply.empty()) { + optionalSupply = supply; + } + + const time_t now = time(nullptr); + const char *const sql = + "UPDATE TAPE_POOL SET " + "SUPPLY = :SUPPLY," + "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 = :TAPE_POOL_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + stmt.bindString(":SUPPLY", optionalSupply); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":TAPE_POOL_NAME", name); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify tape pool ") + name + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsTapePoolCatalogue::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"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsTapePoolCatalogue::tapePoolUsedInAnArchiveRoute(rdbms::Conn &conn, const std::string &tapePoolName) const { + try { + const char *const sql = + "SELECT " + "TAPE_POOL_NAME AS TAPE_POOL_NAME " + "FROM " + "TAPE_POOL " + "INNER JOIN ARCHIVE_ROUTE ON " + "TAPE_POOL.TAPE_POOL_ID = ARCHIVE_ROUTE.TAPE_POOL_ID " + "WHERE " + "TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", tapePoolName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t RdbmsTapePoolCatalogue::getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const { + try { + const char *const sql = + "SELECT " + "COUNT(*) AS NB_TAPES " + "FROM " + "TAPE " + "INNER JOIN TAPE_POOL ON " + "TAPE.TAPE_POOL_ID = TAPE_POOL.TAPE_POOL_ID " + "WHERE " + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", name); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set of SELECT COUNT(*) is empty"); + } + return rset.columnUint64("NB_TAPES"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::optional<uint64_t> RdbmsTapePoolCatalogue::getTapePoolId(rdbms::Conn &conn, const std::string &name) const { + try { + const char *const sql = + "SELECT " + "TAPE_POOL_ID AS TAPE_POOL_ID " + "FROM " + "TAPE_POOL " + "WHERE " + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME", name); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + return std::nullopt; + } + return rset.columnUint64("TAPE_POOL_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsTapePoolCatalogue::tapePoolExists(const std::string &tapePoolName) const { + try { + auto conn = m_connPool->getConn(); + return RdbmsCatalogueUtils::tapePoolExists(conn, tapePoolName); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsTapePoolCatalogue.hpp b/catalogue/rdbms/RdbmsTapePoolCatalogue.hpp new file mode 100644 index 0000000000..c155f51016 --- /dev/null +++ b/catalogue/rdbms/RdbmsTapePoolCatalogue.hpp @@ -0,0 +1,122 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> + +#include "catalogue/interfaces/TapePoolCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsTapePoolCatalogue : public TapePoolCatalogue { +public: + ~RdbmsTapePoolCatalogue() override = default; + + void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) override; + + void deleteTapePool(const std::string &name) override; + + std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria) const override; + + std::optional<TapePool> getTapePool(const std::string &tapePoolName) const override; + + void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t nbPartialTapes) override; + + void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + 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; + + void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + bool tapePoolExists(const std::string &tapePoolName) const override; + +protected: + RdbmsTapePoolCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue); + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + /** + * 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) const = 0; + + std::list<TapePool> getTapePools(rdbms::Conn &conn, const TapePoolSearchCriteria &searchCriteria) const; + + /** + * Returns true if the specified tape pool is used in an archive route. + * + * @param conn The database connection. + * @param tapePoolName The name of the tape pool. + * @return True if the tape pool is used in an archive route. + */ + bool tapePoolUsedInAnArchiveRoute(rdbms::Conn &conn, const std::string &tapePoolName) const; + + /** + * Returns the number of tapes in the specified tape pool. + * + * If the tape pool does not exist then this method returns 0. + * + * @param conn The database connection. + * @param name The name of the tape pool. + * @return The number of tapes in the specified tape pool. + */ + uint64_t getNbTapesInPool(rdbms::Conn &conn, const std::string &name) const; + + friend class RdbmsTapeCatalogue; + std::optional<uint64_t> getTapePoolId(rdbms::Conn &conn, const std::string &name) const; +}; + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.cpp b/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.cpp new file mode 100644 index 0000000000..b9d5da8194 --- /dev/null +++ b/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.cpp @@ -0,0 +1,591 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +RdbmsVirtualOrganizationCatalogue::RdbmsVirtualOrganizationCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue): + m_log(log), m_connPool(connPool), m_rdbmsCatalogue(rdbmsCatalogue) {} + +void RdbmsVirtualOrganizationCatalogue::createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) { + try { + if (vo.name.empty()){ + throw UserSpecifiedAnEmptyStringVo("Cannot create virtual organization because the name is an empty string"); + } + if (vo.comment.empty()) { + throw UserSpecifiedAnEmptyStringComment("Cannot create virtual organization because the comment is an empty string"); + } + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(vo.comment, &m_log); + if (vo.diskInstanceName.empty()) { + throw UserSpecifiedAnEmptyStringDiskInstanceName("Cannot create virtual organization because the disk instance is an empty string"); + } + + auto conn = m_connPool->getConn(); + if (RdbmsCatalogueUtils::virtualOrganizationExists(conn, vo.name)) { + throw exception::UserError(std::string("Cannot create vo : ") + + vo.name + " because it already exists"); + } + const uint64_t virtualOrganizationId = getNextVirtualOrganizationId(conn); + const time_t now = time(nullptr); + const char *const sql = + "INSERT INTO VIRTUAL_ORGANIZATION(" + "VIRTUAL_ORGANIZATION_ID," + "VIRTUAL_ORGANIZATION_NAME," + + "READ_MAX_DRIVES," + "WRITE_MAX_DRIVES," + "MAX_FILE_SIZE," + + "DISK_INSTANCE_NAME," + + "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(" + ":VIRTUAL_ORGANIZATION_ID," + ":VIRTUAL_ORGANIZATION_NAME," + ":READ_MAX_DRIVES," + ":WRITE_MAX_DRIVES," + ":MAX_FILE_SIZE," + + ":DISK_INSTANCE_NAME," + + ":USER_COMMENT," + + ":CREATION_LOG_USER_NAME," + ":CREATION_LOG_HOST_NAME," + ":CREATION_LOG_TIME," + + ":LAST_UPDATE_USER_NAME," + ":LAST_UPDATE_HOST_NAME," + ":LAST_UPDATE_TIME)"; + auto stmt = conn.createStmt(sql); + + stmt.bindUint64(":VIRTUAL_ORGANIZATION_ID", virtualOrganizationId); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", vo.name); + + stmt.bindUint64(":READ_MAX_DRIVES",vo.readMaxDrives); + stmt.bindUint64(":WRITE_MAX_DRIVES",vo.writeMaxDrives); + stmt.bindUint64(":MAX_FILE_SIZE", vo.maxFileSize); + + stmt.bindString(":DISK_INSTANCE_NAME", vo.diskInstanceName); + + stmt.bindString(":USER_COMMENT", vo.comment); + + stmt.bindString(":CREATION_LOG_USER_NAME", admin.username); + stmt.bindString(":CREATION_LOG_HOST_NAME", admin.host); + stmt.bindUint64(":CREATION_LOG_TIME", now); + + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + + stmt.executeNonQuery(); + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::deleteVirtualOrganization(const std::string &voName) { + try { + auto conn = m_connPool->getConn(); + + if(virtualOrganizationIsUsedByStorageClasses(conn, voName)) { + throw UserSpecifiedStorageClassUsedByArchiveRoutes(std::string("The Virtual Organization ") + voName + + " is being used by one or more storage classes"); + } + + if(virtualOrganizationIsUsedByTapepools(conn, voName)) { + throw UserSpecifiedStorageClassUsedByArchiveFiles(std::string("The Virtual Organization ") + voName + + " is being used by one or more Tapepools"); + } + + const char *const sql = + "DELETE FROM " + "VIRTUAL_ORGANIZATION " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto stmt = conn.createStmt(sql); + + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + + stmt.executeNonQuery(); + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot delete Virtual Organization : ") + + voName + " because it does not exist"); + } + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<common::dataStructures::VirtualOrganization> RdbmsVirtualOrganizationCatalogue::getVirtualOrganizations() const { + try { + std::list<common::dataStructures::VirtualOrganization> virtualOrganizations; + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," + + "READ_MAX_DRIVES AS READ_MAX_DRIVES," + "WRITE_MAX_DRIVES AS WRITE_MAX_DRIVES," + "MAX_FILE_SIZE AS MAX_FILE_SIZE," + + "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," + + "DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + + "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 " + "FROM " + "VIRTUAL_ORGANIZATION " + "ORDER BY " + "VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while (rset.next()) { + common::dataStructures::VirtualOrganization virtualOrganization; + + virtualOrganization.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); + + virtualOrganization.readMaxDrives = rset.columnUint64("READ_MAX_DRIVES"); + virtualOrganization.writeMaxDrives = rset.columnUint64("WRITE_MAX_DRIVES"); + virtualOrganization.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); + virtualOrganization.comment = rset.columnString("USER_COMMENT"); + virtualOrganization.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + virtualOrganization.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + virtualOrganization.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + virtualOrganization.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + virtualOrganization.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + virtualOrganization.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + virtualOrganization.diskInstanceName = rset.columnString("DISK_INSTANCE_NAME"); + + virtualOrganizations.push_back(virtualOrganization); + } + + return virtualOrganizations; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::VirtualOrganization RdbmsVirtualOrganizationCatalogue::getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const { + try { + auto conn = m_connPool->getConn(); + return getVirtualOrganizationOfTapepool(conn,tapepoolName); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::VirtualOrganization RdbmsVirtualOrganizationCatalogue::getVirtualOrganizationOfTapepool( + rdbms::Conn & conn, const std::string & tapepoolName) const { + try { + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME," + + "VIRTUAL_ORGANIZATION.READ_MAX_DRIVES AS READ_MAX_DRIVES," + "VIRTUAL_ORGANIZATION.WRITE_MAX_DRIVES AS WRITE_MAX_DRIVES," + "VIRTUAL_ORGANIZATION.MAX_FILE_SIZE AS MAX_FILE_SIZE," + + "VIRTUAL_ORGANIZATION.USER_COMMENT AS USER_COMMENT," + + "VIRTUAL_ORGANIZATION.CREATION_LOG_USER_NAME AS CREATION_LOG_USER_NAME," + "VIRTUAL_ORGANIZATION.CREATION_LOG_HOST_NAME AS CREATION_LOG_HOST_NAME," + "VIRTUAL_ORGANIZATION.CREATION_LOG_TIME AS CREATION_LOG_TIME," + + "VIRTUAL_ORGANIZATION.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + + "VIRTUAL_ORGANIZATION.LAST_UPDATE_USER_NAME AS LAST_UPDATE_USER_NAME," + "VIRTUAL_ORGANIZATION.LAST_UPDATE_HOST_NAME AS LAST_UPDATE_HOST_NAME," + "VIRTUAL_ORGANIZATION.LAST_UPDATE_TIME AS LAST_UPDATE_TIME " + "FROM " + "TAPE_POOL " + "INNER JOIN " + "VIRTUAL_ORGANIZATION " + "ON " + "TAPE_POOL.VIRTUAL_ORGANIZATION_ID = VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "TAPE_POOL.TAPE_POOL_NAME = :TAPE_POOL_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":TAPE_POOL_NAME",tapepoolName); + auto rset = stmt.executeQuery(); + if(!rset.next()){ + throw exception::UserError(std::string("In RdbmsCatalogue::getVirtualOrganizationsOfTapepool() unable to find the Virtual Organization of the tapepool ") + tapepoolName + "."); + } + common::dataStructures::VirtualOrganization virtualOrganization; + + virtualOrganization.name = rset.columnString("VIRTUAL_ORGANIZATION_NAME"); + virtualOrganization.readMaxDrives = rset.columnUint64("READ_MAX_DRIVES"); + virtualOrganization.writeMaxDrives = rset.columnUint64("WRITE_MAX_DRIVES"); + virtualOrganization.maxFileSize = rset.columnUint64("MAX_FILE_SIZE"); + virtualOrganization.comment = rset.columnString("USER_COMMENT"); + virtualOrganization.creationLog.username = rset.columnString("CREATION_LOG_USER_NAME"); + virtualOrganization.creationLog.host = rset.columnString("CREATION_LOG_HOST_NAME"); + virtualOrganization.creationLog.time = rset.columnUint64("CREATION_LOG_TIME"); + virtualOrganization.lastModificationLog.username = rset.columnString("LAST_UPDATE_USER_NAME"); + virtualOrganization.lastModificationLog.host = rset.columnString("LAST_UPDATE_HOST_NAME"); + virtualOrganization.lastModificationLog.time = rset.columnUint64("LAST_UPDATE_TIME"); + virtualOrganization.diskInstanceName = rset.columnString("DISK_INSTANCE_NAME"); + return virtualOrganization; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +common::dataStructures::VirtualOrganization RdbmsVirtualOrganizationCatalogue::getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const { + try { + auto getNonCachedValue = [&] { + auto conn = m_connPool->getConn(); + return getVirtualOrganizationOfTapepool(conn,tapepoolName); + }; + return m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.getCachedValue(tapepoolName,getNonCachedValue).value; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "VIRTUAL_ORGANIZATION_NAME = :NEW_VIRTUAL_ORGANIZATION_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :CUR_VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + if(newVoName != currentVoName){ + if(RdbmsCatalogueUtils::virtualOrganizationExists(conn,newVoName)){ + throw exception::UserError(std::string("Cannot modify the virtual organization name ") + currentVoName +". The new name : " + newVoName+" already exists in the database."); + } + } + auto stmt = conn.createStmt(sql); + stmt.bindString(":NEW_VIRTUAL_ORGANIZATION_NAME", newVoName); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":CUR_VIRTUAL_ORGANIZATION_NAME", currentVoName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + currentVoName + + " because it does not exist"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationReadMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "READ_MAX_DRIVES = :READ_MAX_DRIVES," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":READ_MAX_DRIVES", readMaxDrives); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + + " because it does not exist"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationWriteMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "WRITE_MAX_DRIVES = :WRITE_MAX_DRIVES," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":WRITE_MAX_DRIVES", writeMaxDrives); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + + " because it does not exist"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationMaxFileSize( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "MAX_FILE_SIZE = :MAX_FILE_SIZE," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":MAX_FILE_SIZE", maxFileSize); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + + " because it does not exist"); + } + + m_rdbmsCatalogue->m_tapepoolVirtualOrganizationCache.invalidate(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) { + try { + RdbmsCatalogueUtils::checkCommentOrReasonMaxLength(comment, &m_log); + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "USER_COMMENT = :USER_COMMENT," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + stmt.bindString(":USER_COMMENT", comment); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void RdbmsVirtualOrganizationCatalogue::modifyVirtualOrganizationDiskInstanceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) { + try { + const time_t now = time(nullptr); + const char *const sql = + "UPDATE VIRTUAL_ORGANIZATION SET " + "DISK_INSTANCE_NAME = :DISK_INSTANCE_NAME," + "LAST_UPDATE_USER_NAME = :LAST_UPDATE_USER_NAME," + "LAST_UPDATE_HOST_NAME = :LAST_UPDATE_HOST_NAME," + "LAST_UPDATE_TIME = :LAST_UPDATE_TIME " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto conn = m_connPool->getConn(); + + auto stmt = conn.createStmt(sql); + stmt.bindString(":DISK_INSTANCE_NAME", diskInstance); + stmt.bindString(":LAST_UPDATE_USER_NAME", admin.username); + stmt.bindString(":LAST_UPDATE_HOST_NAME", admin.host); + stmt.bindUint64(":LAST_UPDATE_TIME", now); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + stmt.executeNonQuery(); + + if(0 == stmt.getNbAffectedRows()) { + throw exception::UserError(std::string("Cannot modify virtual organization : ") + voName + + " because it does not exist"); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsVirtualOrganizationCatalogue::virtualOrganizationIsUsedByStorageClasses(rdbms::Conn &conn, + const std::string &voName) const { + try { + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " + "FROM " + "VIRTUAL_ORGANIZATION " + "INNER JOIN " + "STORAGE_CLASS " + "ON " + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID = STORAGE_CLASS.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +bool RdbmsVirtualOrganizationCatalogue::virtualOrganizationIsUsedByTapepools(rdbms::Conn &conn, + const std::string &voName) const { + try { + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION_NAME AS VIRTUAL_ORGANIZATION_NAME " + "FROM " + "VIRTUAL_ORGANIZATION " + "INNER JOIN " + "TAPE_POOL " + "ON " + "VIRTUAL_ORGANIZATION.VIRTUAL_ORGANIZATION_ID = TAPE_POOL.VIRTUAL_ORGANIZATION_ID " + "WHERE " + "VIRTUAL_ORGANIZATION_NAME = :VIRTUAL_ORGANIZATION_NAME"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VIRTUAL_ORGANIZATION_NAME", voName); + auto rset = stmt.executeQuery(); + return rset.next(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp b/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..4682cc4e52 --- /dev/null +++ b/catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp @@ -0,0 +1,110 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/VirtualOrganizationCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { + +namespace rdbms { +class Conn; +class ConnPool; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class RdbmsVirtualOrganizationCatalogue : public VirtualOrganizationCatalogue { +public: + ~RdbmsVirtualOrganizationCatalogue() override = default; + + void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) override; + + void deleteVirtualOrganization(const std::string &voName) override; + std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const override; + + common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + void modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) override; + + void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t readMaxDrives) override; + + void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t writeMaxDrives) override; + + void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t maxFileSize) override; + + void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &comment) override; + + void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &diskInstance) override; + +protected: + RdbmsVirtualOrganizationCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + + /** + * Returns a unique virtual organization ID that can be used by a new Virtual Organization + * 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 virtual organization ID that can be used by a new Virtual Organization + * within the catalogue. + */ + virtual uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) = 0; + +private: + log::Logger &m_log; + std::shared_ptr<rdbms::ConnPool> m_connPool; + RdbmsCatalogue* m_rdbmsCatalogue; + + common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool(rdbms::Conn & conn, + const std::string & tapepoolName) const; + + bool virtualOrganizationIsUsedByStorageClasses(rdbms::Conn &conn, const std::string &voName) const; + + /** + * Returns true if the specified Virtual Organization is currently being used by one + * or more Tapepools + * + * @param conn The database connection. + * @param voName The name of the Virtual Organization. + */ + bool virtualOrganizationIsUsedByTapepools(rdbms::Conn &conn, const std::string &voName) const; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.cpp b/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.cpp new file mode 100644 index 0000000000..52cfbb3c20 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.cpp @@ -0,0 +1,344 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/wrapper/OcciColumn.hpp" +#include "rdbms/wrapper/OcciStmt.hpp" + +namespace cta { +namespace catalogue { + +OracleArchiveFileCatalogue::OracleArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue) + : RdbmsArchiveFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void OracleArchiveFileCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, + const uint64_t archiveFileId, log::LogContext &lc) { + try { + const char *selectSql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " + "FOR UPDATE"; + utils::Timer t; + + auto conn = m_connPool->getConn(); + rdbms::AutoRollback autoRollback(conn); + + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + + const auto getConnTime = t.secs(utils::Timer::resetCounter); + auto selectStmt = conn.createStmt(selectSql); + const auto createStmtTime = t.secs(); + selectStmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + t.reset(); + rdbms::Rset selectRset = selectStmt.executeQuery(); + const auto selectFromArchiveFileTime = t.secs(); + std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; + std::set<std::string> vidsToSetDirty; + while(selectRset.next()) { + if(nullptr == archiveFile.get()) { + archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); + + archiveFile->archiveFileID = selectRset.columnUint64("ARCHIVE_FILE_ID"); + archiveFile->diskInstance = selectRset.columnString("DISK_INSTANCE_NAME"); + archiveFile->diskFileId = selectRset.columnString("DISK_FILE_ID"); + archiveFile->diskFileInfo.owner_uid = selectRset.columnUint64("DISK_FILE_UID"); + archiveFile->diskFileInfo.gid = selectRset.columnUint64("DISK_FILE_GID"); + archiveFile->fileSize = selectRset.columnUint64("SIZE_IN_BYTES"); + archiveFile->checksumBlob.deserializeOrSetAdler32(selectRset.columnBlob("CHECKSUM_BLOB"), selectRset.columnUint64("CHECKSUM_ADLER32")); + archiveFile->storageClass = selectRset.columnString("STORAGE_CLASS_NAME"); + archiveFile->creationTime = selectRset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + archiveFile->reconciliationTime = selectRset.columnUint64("RECONCILIATION_TIME"); + } + + // If there is a tape file + if(!selectRset.columnIsNull("VID")) { + // Add the tape file to the archive file's in-memory structure + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = selectRset.columnString("VID"); + vidsToSetDirty.insert(tapeFile.vid); + tapeFile.fSeq = selectRset.columnUint64("FSEQ"); + tapeFile.blockId = selectRset.columnUint64("BLOCK_ID"); + tapeFile.fileSize = selectRset.columnUint64("LOGICAL_SIZE_IN_BYTES"); + tapeFile.copyNb = selectRset.columnUint8("COPY_NB"); + tapeFile.creationTime = selectRset.columnUint64("TAPE_FILE_CREATION_TIME"); + tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience + archiveFile->tapeFiles.push_back(tapeFile); + } + } + + if(nullptr == archiveFile.get()) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", archiveFileId); + lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); + return; + } + + if(diskInstanceName != archiveFile->diskInstance) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("requestDiskInstance", diskInstanceName) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("createStmtTime", createStmtTime) + .add("selectFromArchiveFileTime", selectFromArchiveFileTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << static_cast<int>(it->copyNb) + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " + "of the archived file"); + + exception::UserError ue; + ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " + "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << + archiveFile->diskInstance; + throw ue; + } + + t.reset(); + { + const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + + const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); + + //Set the tapes where the files have been deleted to dirty + for(auto &vidToSetDirty: vidsToSetDirty){ + RdbmsCatalogueUtils::setTapeDirty(conn,vidToSetDirty); + } + + const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); + + { + const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); + + conn.commit(); + const auto commitTime = t.secs(); + + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("createStmtTime", createStmtTime) + .add("selectFromArchiveFileTime", selectFromArchiveFileTime) + .add("deleteFromTapeFileTime", deleteFromTapeFileTime) + .add("setTapeDirtyTime",setTapeDirtyTime) + .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) + .add("commitTime", commitTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << it->copyNb + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::INFO, "Archive file deleted from CTA catalogue"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + std::ostringstream msg; + msg << __FUNCTION__ << ": diskInstanceName=" << diskInstanceName <<",archiveFileId=" << + archiveFileId << ": " << ex.getMessage().str(); + ex.getMessage().str(msg.str()); + throw; + } +} + +uint64_t OracleArchiveFileCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { + try { + const char *const sql = + "SELECT " + "ARCHIVE_FILE_ID_SEQ.NEXTVAL AS ARCHIVE_FILE_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("ARCHIVE_FILE_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void OracleArchiveFileCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc){ + try { + utils::Timer t; + log::TimingList tl; + //We currently do an INSERT INTO, update and two DELETE FROM + //in a single transaction + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + const auto fileRecycleLog = static_cast<RdbmsFileRecycleLogCatalogue*>(m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLog->copyArchiveFileToFileRecycleLog(conn,request); + tl.insertAndReset("insertToRecycleBinTime",t); + RdbmsCatalogueUtils::setTapeDirty(conn,request.archiveFileID); + tl.insertAndReset("setTapeDirtyTime",t); + const auto tapeFileCatalogue = static_cast<RdbmsTapeFileCatalogue*>(m_rdbmsCatalogue->TapeFile().get()); + tapeFileCatalogue->deleteTapeFiles(conn,request); + tl.insertAndReset("deleteTapeFilesTime",t); + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); + deleteArchiveFile(conn,request); + tl.insertAndReset("deleteArchiveFileTime",t); + log::ScopedParamContainer spc(lc); + spc.add("archiveFileId",request.archiveFileID); + spc.add("diskFileId",request.diskFileId); + spc.add("diskFilePath",request.diskFilePath); + spc.add("diskInstance",request.diskInstance); + tl.addToLog(spc); + lc.log(log::INFO,"In OracleCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// selectArchiveFileSizeAndChecksum +//------------------------------------------------------------------------------ +std::map<uint64_t, OracleArchiveFileCatalogue::FileSizeAndChecksum> + OracleArchiveFileCatalogue::selectArchiveFileSizesAndChecksums(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events) { + try { + std::vector<oracle::occi::Number> archiveFileIdList(events.size()); + for (const auto &event: events) { + archiveFileIdList.push_back(oracle::occi::Number(event.archiveFileId)); + } + + const char *const sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32 " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN TEMP_TAPE_FILE_INSERTION_BATCH ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + + std::map<uint64_t, FileSizeAndChecksum> fileSizesAndChecksums; + while (rset.next()) { + const uint64_t archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + + if (fileSizesAndChecksums.end() != fileSizesAndChecksums.find(archiveFileId)) { + exception::Exception ex; + ex.getMessage() << __FUNCTION__ << " failed: " + "Found duplicate archive file identifier in batch of files written to tape: archiveFileId=" << archiveFileId; + throw ex; + } + FileSizeAndChecksum fileSizeAndChecksum; + fileSizeAndChecksum.fileSize = rset.columnUint64("SIZE_IN_BYTES"); + fileSizeAndChecksum.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + fileSizesAndChecksums[archiveFileId] = fileSizeAndChecksum; + } + + return fileSizesAndChecksums; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp b/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..188246d7bf --- /dev/null +++ b/catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp @@ -0,0 +1,71 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "common/checksum/ChecksumBlob.hpp" + +namespace cta { + +namespace catalogue { + +class TapeFileWritten; +class RdbmsCatalogue; + +class OracleArchiveFileCatalogue : public RdbmsArchiveFileCatalogue { +public: + OracleArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleArchiveFileCatalogue() override = default; + + void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, + log::LogContext &lc) override; + +private: + uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; + + void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; + + /** + * The size and checksum of a file. + */ + struct FileSizeAndChecksum { + uint64_t fileSize; + checksum::ChecksumBlob checksumBlob; + }; + + friend class OracleTapeFileCatalogue; + /** + * Returns the sizes and checksums of the specified archive files. + * + * @param conn The database connection. + * @param events The tape file written events that identify the archive files. + * @return A map from the identifier of each archive file to its size and checksum. + */ + std::map<uint64_t, FileSizeAndChecksum> selectArchiveFileSizesAndChecksums(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events); +}; // class OracleArchiveFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleCatalogue.cpp b/catalogue/rdbms/oracle/OracleCatalogue.cpp new file mode 100644 index 0000000000..8e79aacb56 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleCatalogue.cpp @@ -0,0 +1,85 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleTapeCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp" +#include "rdbms/Login.hpp" + +namespace cta { +namespace catalogue { + +OracleCatalogue::OracleCatalogue( + log::Logger &log, + const std::string &username, + const std::string &password, + const std::string &database, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns): + RdbmsCatalogue( + log, + rdbms::Login(rdbms::Login::DBTYPE_ORACLE, username, password, database, "", 0), + nbConns, + nbArchiveFileListingConns) { + RdbmsCatalogue::m_fileRecycleLog = std::make_unique<OracleFileRecycleLogCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_storageClass = std::make_unique<OracleStorageClassCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_vo = std::make_unique<OracleVirtualOrganizationCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapePool = std::make_unique<OracleTapePoolCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_mediaType = std::make_unique<OracleMediaTypeCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_logicalLibrary = std::make_unique<OracleLogicalLibraryCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tape = std::make_unique<OracleTapeCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_archiveFile = std::make_unique<OracleArchiveFileCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapeFile = std::make_unique<OracleTapeFileCatalogue>(m_log, m_connPool, this); +} + +std::string OracleCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const { + const std::string tempTableName = "ORA$PTT_DISK_FXIDS"; + + try { + if(diskFileIds) { + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + std::string sql = "CREATE PRIVATE TEMPORARY TABLE " + tempTableName + + "(DISK_FILE_ID VARCHAR2(100))"; + conn.executeNonQuery(sql); + + sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; + auto stmt = conn.createStmt(sql); + for(auto &diskFileId : diskFileIds.value()) { + stmt.bindString(":DISK_FILE_ID", diskFileId); + stmt.executeNonQuery(); + } + } + + return tempTableName; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleCatalogue.hpp b/catalogue/rdbms/oracle/OracleCatalogue.hpp new file mode 100644 index 0000000000..17192f581f --- /dev/null +++ b/catalogue/rdbms/oracle/OracleCatalogue.hpp @@ -0,0 +1,73 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +/** + * An Oracle based implementation of the CTA catalogue. + */ +class OracleCatalogue: public RdbmsCatalogue { +public: + + /** + * Constructor. + * + * @param log Object representing the API to the CTA logging system. + * @param username The database username. + * @param password The database password. + * @param database The database name. + * @param nbConns The maximum number of concurrent connections to the + * underlying relational database for all operations accept listing archive + * files which can be relatively long operations. + * @param nbArchiveFileListingConns The maximum number of concurrent + * connections to the underlying relational database for the sole purpose of + * listing archive files. + */ + OracleCatalogue( + log::Logger &log, + const std::string &username, + const std::string &password, + const std::string &database, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns); + + /** + * Destructor. + */ + ~OracleCatalogue() override = default; + + /** + * Creates a temporary table from the list of disk file IDs provided in the search criteria. + * + * @param conn The database connection. + * @param diskFileIds List of disk file IDs (fxid). + * @return Name of the temporary table + */ + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const override; +}; // class OracleCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.cpp b/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.cpp new file mode 100644 index 0000000000..99b1af1ecb --- /dev/null +++ b/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.cpp @@ -0,0 +1,117 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +OracleFileRecycleLogCatalogue::OracleFileRecycleLogCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsFileRecycleLogCatalogue(log, connPool, rdbmsCatalogue) {} + +//------------------------------------------------------------------------------ +// restoreEntryInRecycleLog +//------------------------------------------------------------------------------ +void OracleFileRecycleLogCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, + FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) { + try { + utils::Timer timer; + log::TimingList timingList; + + if (!fileRecycleLogItor.hasMore()) { + throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); + } + auto fileRecycleLog = fileRecycleLogItor.next(); + if (fileRecycleLogItor.hasMore()) { + // stop restoring more than one file at once + throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); + } + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + + const auto archiveFileCatalogue = static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + if (auto archiveFilePtr = archiveFileCatalogue->getArchiveFileById(conn, fileRecycleLog.archiveFileId); + !archiveFilePtr) { + RdbmsFileRecycleLogCatalogue::restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); + } else { + if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { + // copy with same copy_nb exists, cannot restore + UserSpecifiedExistingDeletedFileCopy ex; + ex.getMessage() << "Cannot restore file copy with archiveFileId " + << std::to_string(fileRecycleLog.archiveFileId) + << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) + << " because a tapefile with same archiveFileId and copy_nb already exists"; + throw ex; + } + } + + RdbmsFileRecycleLogCatalogue::restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); + + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); + conn.commit(); + + log::ScopedParamContainer spc(lc); + timingList.insertAndReset("commitTime", timer); + timingList.addToLog(spc); + lc.log(log::INFO, "In OracleFileRecycleLogCatalogue::restoreEntryInRecycleLog: " + "all file copies successfully restored."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t OracleFileRecycleLogCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) const { + try { + const char *const sql = + "SELECT " + "FILE_RECYCLE_LOG_ID_SEQ.NEXTVAL AS FILE_RECYCLE_LOG_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("FILE_RECYCLE_LOG_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp b/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..51d6c4466b --- /dev/null +++ b/catalogue/rdbms/oracle/OracleFileRecycleLogCatalogue.hpp @@ -0,0 +1,61 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleFileRecycleLogCatalogue : public RdbmsFileRecycleLogCatalogue { +public: + OracleFileRecycleLogCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleFileRecycleLogCatalogue() override = default; + +private: + void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, + log::LogContext & lc) override; + + /** + * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry + * @param conn the database connection + * @param fileRecycleLog the fileRecycleLog we want to restore + * @param lc the log context + */ + void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, + log::LogContext & lc); + + uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) const override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.cpp b/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.cpp new file mode 100644 index 0000000000..af74b94a1c --- /dev/null +++ b/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.cpp @@ -0,0 +1,54 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleLogicalLibraryCatalogue::OracleLogicalLibraryCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsLogicalLibraryCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleLogicalLibraryCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) const { + try { + const char *const sql = + "SELECT " + "LOGICAL_LIBRARY_ID_SEQ.NEXTVAL AS LOGICAL_LIBRARY_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("LOGICAL_LIBRARY_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp b/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..9b9396e33c --- /dev/null +++ b/catalogue/rdbms/oracle/OracleLogicalLibraryCatalogue.hpp @@ -0,0 +1,40 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class RdbmsCatalogue; + +class OracleLogicalLibraryCatalogue : public RdbmsLogicalLibraryCatalogue { +public: + OracleLogicalLibraryCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleLogicalLibraryCatalogue() override = default; + +private: + uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) const override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.cpp b/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.cpp new file mode 100644 index 0000000000..1f62d03395 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.cpp @@ -0,0 +1,54 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleMediaTypeCatalogue::OracleMediaTypeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsMediaTypeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleMediaTypeCatalogue::getNextMediaTypeId(rdbms::Conn &conn) const { + try { + const char *const sql = + "SELECT " + "MEDIA_TYPE_ID_SEQ.NEXTVAL AS MEDIA_TYPE_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("MEDIA_TYPE_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp b/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp new file mode 100644 index 0000000000..3dbdf2f3c8 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleMediaTypeCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleMediaTypeCatalogue : public RdbmsMediaTypeCatalogue { +public: + OracleMediaTypeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleMediaTypeCatalogue() override = default; + +private: + uint64_t getNextMediaTypeId(rdbms::Conn &conn) const override; +}; // class PostgresMediaTypeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleStorageClassCatalogue.cpp b/catalogue/rdbms/oracle/OracleStorageClassCatalogue.cpp new file mode 100644 index 0000000000..f11220edde --- /dev/null +++ b/catalogue/rdbms/oracle/OracleStorageClassCatalogue.cpp @@ -0,0 +1,54 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleStorageClassCatalogue::OracleStorageClassCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsStorageClassCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleStorageClassCatalogue::getNextStorageClassId(rdbms::Conn &conn) { + try { + const char *const sql = + "SELECT " + "STORAGE_CLASS_ID_SEQ.NEXTVAL AS STORAGE_CLASS_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("STORAGE_CLASS_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp b/catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp new file mode 100644 index 0000000000..cbf05b895c --- /dev/null +++ b/catalogue/rdbms/oracle/OracleStorageClassCatalogue.hpp @@ -0,0 +1,42 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleStorageClassCatalogue : public RdbmsStorageClassCatalogue { +public: + OracleStorageClassCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleStorageClassCatalogue() override = default; + +private: + uint64_t getNextStorageClassId(rdbms::Conn &conn) override; +}; // class PostgresStorageClassCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleTapeCatalogue.cpp b/catalogue/rdbms/oracle/OracleTapeCatalogue.cpp new file mode 100644 index 0000000000..3750928aeb --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapeCatalogue.cpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/oracle/OracleTapeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleTapeCatalogue::OracleTapeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleTapeCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " + "FROM " + "TAPE " + "WHERE " + "VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if(rset.next()) { + return rset.columnUint64("LAST_FSEQ"); + } else { + throw exception::Exception(std::string("No such tape with vid=") + vid); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleTapeCatalogue.hpp b/catalogue/rdbms/oracle/OracleTapeCatalogue.hpp new file mode 100644 index 0000000000..fc0f460e54 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapeCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleTapeCatalogue : public RdbmsTapeCatalogue { +public: + OracleTapeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleTapeCatalogue() override = default; + +private: + uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const override; +}; // class OracleTapeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleTapeFileCatalogue.cpp b/catalogue/rdbms/oracle/OracleTapeFileCatalogue.cpp new file mode 100644 index 0000000000..6ca4f0cd79 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapeFileCatalogue.cpp @@ -0,0 +1,619 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <algorithm> +#include <string> + +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/rdbms/oracle/OracleArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeItemWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "common/checksum/ChecksumBlob.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/FileSizeMismatch.hpp" +#include "common/exception/LostDatabaseConnection.hpp" +#include "common/exception/TapeFseqMismatch.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/rdbms.hpp" +#include "rdbms/wrapper/OcciColumn.hpp" +#include "rdbms/wrapper/OcciStmt.hpp" + +namespace cta { +namespace catalogue { + +namespace { +/** + * Structure used to assemble a batch of rows to insert into the TAPE_FILE + * table. + */ +struct TapeFileBatch { + size_t nbRows; + rdbms::wrapper::OcciColumn vid; + rdbms::wrapper::OcciColumn fSeq; + rdbms::wrapper::OcciColumn blockId; + rdbms::wrapper::OcciColumn fileSize; + rdbms::wrapper::OcciColumn copyNb; + rdbms::wrapper::OcciColumn creationTime; + rdbms::wrapper::OcciColumn archiveFileId; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + TapeFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + vid("VID", nbRows), + fSeq("FSEQ", nbRows), + blockId("BLOCK_ID", nbRows), + fileSize("LOGICAL_SIZE_IN_BYTES", nbRows), + copyNb("COPY_NB", nbRows), + creationTime("CREATION_TIME", nbRows), + archiveFileId("ARCHIVE_FILE_ID", nbRows) { + } +}; // struct TapeFileBatch + +/** + * Structure used to assemble a batch of rows to insert into the ARCHIVE_FILE + * table. + */ +struct ArchiveFileBatch { + size_t nbRows; + rdbms::wrapper::OcciColumn archiveFileId; + rdbms::wrapper::OcciColumn diskInstance; + rdbms::wrapper::OcciColumn diskFileId; + rdbms::wrapper::OcciColumn diskFileUser; + rdbms::wrapper::OcciColumn diskFileGroup; + rdbms::wrapper::OcciColumn size; + rdbms::wrapper::OcciColumn checksumBlob; + rdbms::wrapper::OcciColumn checksumAdler32; + rdbms::wrapper::OcciColumn storageClassName; + rdbms::wrapper::OcciColumn creationTime; + rdbms::wrapper::OcciColumn reconciliationTime; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + ArchiveFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + archiveFileId("ARCHIVE_FILE_ID", nbRows), + diskInstance("DISK_INSTANCE_NAME", nbRows), + diskFileId("DISK_FILE_ID", nbRows), + diskFileUser("DISK_FILE_UID", nbRows), + diskFileGroup("DISK_FILE_GID", nbRows), + size("SIZE_IN_BYTES", nbRows), + checksumBlob("CHECKSUM_BLOB", nbRows), + checksumAdler32("CHECKSUM_ADLER32", nbRows), + storageClassName("STORAGE_CLASS_NAME", nbRows), + creationTime("CREATION_TIME", nbRows), + reconciliationTime("RECONCILIATION_TIME", nbRows) { + } +}; // struct ArchiveFileBatch + +/** + * Structure used to assemble a batch of rows to insert into the + * TAPE_FILE_BATCH temporary table. + */ +struct TempTapeFileBatch { + size_t nbRows; + rdbms::wrapper::OcciColumn archiveFileId; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + TempTapeFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + archiveFileId("ARCHIVE_FILE_ID", nbRows) { + } +}; // struct TempTapeFileBatch + +} // anonymous namespace + +OracleTapeFileCatalogue::OracleTapeFileCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue) + : RdbmsTapeFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void OracleTapeFileCatalogue::copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const { + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + const auto fileRecycleLogCatalogue = static_cast<RdbmsFileRecycleLogCatalogue*>( + RdbmsTapeFileCatalogue::m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLogCatalogue->copyTapeFilesToFileRecycleLog(conn, file, reason); + timingList->insertAndReset("insertToRecycleBinTime", *timer); + RdbmsCatalogueUtils::setTapeDirty(conn, file.archiveFileID); + timingList->insertAndReset("setTapeDirtyTime", *timer); + deleteTapeFiles(conn, file); + timingList->insertAndReset("deleteTapeFilesTime", *timer); + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); + conn.commit(); +} + +void OracleTapeFileCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { + try { + if (events.empty()) { + return; + } + + auto firstEventItor = events.begin(); + const auto &firstEvent = *(*firstEventItor); + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); + const time_t now = time(nullptr); + threading::MutexLocker locker(m_rdbmsCatalogue->m_mutex); + auto conn = m_connPool->getConn(); + rdbms::AutoRollback autoRollback(conn); + + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_OFF); + + const uint64_t lastFSeq = selectTapeForUpdateAndGetLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; + uint64_t totalLogicalBytesWritten = 0; + + uint32_t i = 0; + // We have a mix of files and items. Only files will be recorded, but items + // allow checking fSeq coherency. + // determine the number of files + size_t filesCount=std::count_if(events.cbegin(), events.cend(), + [](const TapeItemWrittenPointer &e) -> bool {return typeid(*e)==typeid(TapeFileWritten);}); + TapeFileBatch tapeFileBatch(filesCount); + + std::set<TapeFileWritten> fileEvents; + + for (const auto &eventP: events) { + // Check for all item types. + const auto &event = *eventP; + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); + + if (event.vid != firstEvent.vid) { + throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); + } + + if (expectedFSeq != event.fSeq) { + exception::TapeFseqMismatch ex; + ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << + event.fSeq; + throw ex; + } + expectedFSeq++; + + try { + // If this is a file (as opposed to a placeholder), do the full processing. + const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); + + checkTapeFileWrittenFieldsAreSet(__FUNCTION__, fileEvent); + + totalLogicalBytesWritten += fileEvent.size; + + // Store the length of each field and implicitly calculate the maximum field + // length of each column + tapeFileBatch.vid.setFieldLenToValueLen(i, fileEvent.vid); + tapeFileBatch.fSeq.setFieldLenToValueLen(i, fileEvent.fSeq); + tapeFileBatch.blockId.setFieldLenToValueLen(i, fileEvent.blockId); + tapeFileBatch.fileSize.setFieldLenToValueLen(i, fileEvent.size); + tapeFileBatch.copyNb.setFieldLenToValueLen(i, fileEvent.copyNb); + tapeFileBatch.creationTime.setFieldLenToValueLen(i, now); + tapeFileBatch.archiveFileId.setFieldLenToValueLen(i, fileEvent.archiveFileId); + + fileEvents.insert(fileEvent); + i++; + } catch (std::bad_cast&) {} + } + + // Store the value of each field + i = 0; + for (const auto &event: fileEvents) { + tapeFileBatch.vid.setFieldValue(i, event.vid); + tapeFileBatch.fSeq.setFieldValue(i, event.fSeq); + tapeFileBatch.blockId.setFieldValue(i, event.blockId); + tapeFileBatch.fileSize.setFieldValue(i, event.size); + tapeFileBatch.copyNb.setFieldValue(i, event.copyNb); + tapeFileBatch.creationTime.setFieldValue(i, now); + tapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); + i++; + } + + // Update the tape because all the necessary information is now available + auto lastEventItor = events.cend(); + lastEventItor--; + const TapeItemWritten &lastEvent = **lastEventItor; + RdbmsCatalogueUtils::updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, + lastEvent.tapeDrive); + + // If we had only placeholders and no file recorded, we are done (but we still commit the update of the tape's fSeq). + if (fileEvents.empty()) { + conn.commit(); + return; + } + + // Create the archive file entries, skipping those that already exist + idempotentBatchInsertArchiveFiles(conn, fileEvents); + + { + const char *const sql = + "INSERT INTO TEMP_TAPE_FILE_INSERTION_BATCH(" "\n" + "VID," "\n" + "FSEQ," "\n" + "BLOCK_ID," "\n" + "LOGICAL_SIZE_IN_BYTES," "\n" + "COPY_NB," "\n" + "CREATION_TIME," "\n" + "ARCHIVE_FILE_ID)" "\n" + "VALUES(" "\n" + ":VID," "\n" + ":FSEQ," "\n" + ":BLOCK_ID," "\n" + ":LOGICAL_SIZE_IN_BYTES," "\n" + ":COPY_NB," "\n" + ":CREATION_TIME," "\n" + ":ARCHIVE_FILE_ID)" "\n"; + auto stmt = conn.createStmt(sql); + rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt()); + occiStmt.setColumn(tapeFileBatch.vid); + occiStmt.setColumn(tapeFileBatch.fSeq); + occiStmt.setColumn(tapeFileBatch.blockId); + occiStmt.setColumn(tapeFileBatch.fileSize); + occiStmt.setColumn(tapeFileBatch.copyNb); + occiStmt.setColumn(tapeFileBatch.creationTime); + occiStmt.setColumn(tapeFileBatch.archiveFileId); + try { + occiStmt->executeArrayUpdate(tapeFileBatch.nbRows); + } catch(oracle::occi::SQLException &ex) { + std::ostringstream msg; + msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << + ex.what(); + + if(rdbms::wrapper::OcciStmt::connShouldBeClosed(ex)) { + // Close the statement first and then the connection + try { + occiStmt.close(); + } catch(...) { + } + + try { + conn.closeUnderlyingStmtsAndConn(); + } catch(...) { + } + throw exception::LostDatabaseConnection(msg.str()); + } + throw exception::Exception(msg.str()); + } catch(std::exception &se) { + std::ostringstream msg; + msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << + se.what(); + + throw exception::Exception(msg.str()); + } + } + + // Verify that the archive file entries in the catalogue database agree with + // the tape file written events + const auto archiveFileCatalogue = static_cast<OracleArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + const auto fileSizesAndChecksums = archiveFileCatalogue->selectArchiveFileSizesAndChecksums(conn, fileEvents); + for (const auto &event: fileEvents) { + const auto fileSizeAndChecksumItor = fileSizesAndChecksums.find(event.archiveFileId); + + std::ostringstream fileContext; + fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << + ", diskFileId=" << event.diskFileId; + + // This should never happen + if(fileSizesAndChecksums.end() == fileSizeAndChecksumItor) { + exception::Exception ex; + ex.getMessage() << __FUNCTION__ << ": Failed to find archive file entry in the catalogue: " << fileContext.str(); + throw ex; + } + + const auto &fileSizeAndChecksum = fileSizeAndChecksumItor->second; + + if(fileSizeAndChecksum.fileSize != event.size) { + catalogue::FileSizeMismatch ex; + ex.getMessage() << __FUNCTION__ << ": File size mismatch: expected=" << fileSizeAndChecksum.fileSize << + ", actual=" << event.size << ": " << fileContext.str(); + throw ex; + } + + fileSizeAndChecksum.checksumBlob.validate(event.checksumBlob); + } + + std::list<InsertFileRecycleLog> recycledFiles = insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn); + + { + const char *const sql = + "INSERT INTO TAPE_FILE (VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES, " + "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID) " + "SELECT VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES, " + "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID FROM TEMP_TAPE_FILE_INSERTION_BATCH"; + auto stmt = conn.createStmt(sql); + stmt.executeNonQuery(); + } + + for(auto & recycledFile: recycledFiles){ + const char *const sql = + "DELETE FROM " + "TAPE_FILE " + "WHERE " + "TAPE_FILE.VID = :VID AND TAPE_FILE.FSEQ = :FSEQ"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID",recycledFile.vid); + stmt.bindUint64(":FSEQ",recycledFile.fSeq); + stmt.executeNonQuery(); + } + + { + conn.setAutocommitMode(rdbms::AutocommitMode::AUTOCOMMIT_ON); + conn.commit(); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t OracleTapeFileCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, + const std::string &vid) { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " + "FROM " + "TAPE " + "WHERE " + "VID = :VID " + "FOR UPDATE"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if (!rset.next()) { + throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); + } + + return rset.columnUint64("LAST_FSEQ"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void OracleTapeFileCatalogue::idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events) { + try { + ArchiveFileBatch archiveFileBatch(events.size()); + const time_t now = time(nullptr); + std::vector<uint32_t> adler32(events.size()); + + // Store the length of each field and implicitly calculate the maximum field length of each column + uint32_t i = 0; + for (const auto &event: events) { + // Keep transition ADLER32 checksum column up-to-date with the ChecksumBlob + try { + std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(event.checksumBlob.at(checksum::ADLER32)); + adler32[i] = strtoul(adler32hex.c_str(), 0, 16); + } catch(exception::ChecksumTypeMismatch &ex) { + // No ADLER32 checksum exists in the checksumBlob + adler32[i] = 0; + } + + archiveFileBatch.archiveFileId.setFieldLenToValueLen(i, event.archiveFileId); + archiveFileBatch.diskInstance.setFieldLenToValueLen(i, event.diskInstance); + archiveFileBatch.diskFileId.setFieldLenToValueLen(i, event.diskFileId); + archiveFileBatch.diskFileUser.setFieldLenToValueLen(i, event.diskFileOwnerUid); + archiveFileBatch.diskFileGroup.setFieldLenToValueLen(i, event.diskFileGid); + archiveFileBatch.size.setFieldLenToValueLen(i, event.size); + archiveFileBatch.checksumBlob.setFieldLen(i, 2 + event.checksumBlob.length()); + archiveFileBatch.checksumAdler32.setFieldLenToValueLen(i, adler32[i]); + archiveFileBatch.storageClassName.setFieldLenToValueLen(i, event.storageClassName); + archiveFileBatch.creationTime.setFieldLenToValueLen(i, now); + archiveFileBatch.reconciliationTime.setFieldLenToValueLen(i, now); + i++; + } + + // Store the value of each field + i = 0; + for (const auto &event: events) { + archiveFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); + archiveFileBatch.diskInstance.setFieldValue(i, event.diskInstance); + archiveFileBatch.diskFileId.setFieldValue(i, event.diskFileId); + archiveFileBatch.diskFileUser.setFieldValue(i, event.diskFileOwnerUid); + archiveFileBatch.diskFileGroup.setFieldValue(i, event.diskFileGid); + archiveFileBatch.size.setFieldValue(i, event.size); + archiveFileBatch.checksumBlob.setFieldValueToRaw(i, event.checksumBlob.serialize()); + archiveFileBatch.checksumAdler32.setFieldValue(i, adler32[i]); + archiveFileBatch.storageClassName.setFieldValue(i, event.storageClassName); + archiveFileBatch.creationTime.setFieldValue(i, now); + archiveFileBatch.reconciliationTime.setFieldValue(i, now); + i++; + } + + const char *const sql = + "INSERT INTO ARCHIVE_FILE(" + "ARCHIVE_FILE_ID," + "DISK_INSTANCE_NAME," + "DISK_FILE_ID," + "DISK_FILE_UID," + "DISK_FILE_GID," + "SIZE_IN_BYTES," + "CHECKSUM_BLOB," + "CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + "CREATION_TIME," + "RECONCILIATION_TIME)" + "SELECT " + ":ARCHIVE_FILE_ID," + ":DISK_INSTANCE_NAME," + ":DISK_FILE_ID," + ":DISK_FILE_UID," + ":DISK_FILE_GID," + ":SIZE_IN_BYTES," + ":CHECKSUM_BLOB," + ":CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + ":CREATION_TIME," + ":RECONCILIATION_TIME " + "FROM " + "STORAGE_CLASS " + "WHERE " + "STORAGE_CLASS_NAME = :STORAGE_CLASS_NAME"; + auto stmt = conn.createStmt(sql); + rdbms::wrapper::OcciStmt &occiStmt = dynamic_cast<rdbms::wrapper::OcciStmt &>(stmt.getStmt()); + occiStmt->setBatchErrorMode(true); + + occiStmt.setColumn(archiveFileBatch.archiveFileId); + occiStmt.setColumn(archiveFileBatch.diskInstance); + occiStmt.setColumn(archiveFileBatch.diskFileId); + occiStmt.setColumn(archiveFileBatch.diskFileUser); + occiStmt.setColumn(archiveFileBatch.diskFileGroup); + occiStmt.setColumn(archiveFileBatch.size); + occiStmt.setColumn(archiveFileBatch.checksumBlob, oracle::occi::OCCI_SQLT_VBI); + occiStmt.setColumn(archiveFileBatch.checksumAdler32); + occiStmt.setColumn(archiveFileBatch.storageClassName); + occiStmt.setColumn(archiveFileBatch.creationTime); + occiStmt.setColumn(archiveFileBatch.reconciliationTime); + + try { + occiStmt->executeArrayUpdate(archiveFileBatch.nbRows); + } catch(oracle::occi::BatchSQLException &be) { + const unsigned int nbFailedRows = be.getFailedRowCount(); + exception::Exception ex; + ex.getMessage() << "Caught a BatchSQLException" << nbFailedRows; + bool foundErrorOtherThanUniqueConstraint = false; + for (unsigned int row = 0; row < nbFailedRows; row++ ) { + oracle::occi::SQLException err = be.getException(row); + const unsigned int rowIndex = be.getRowNum(row); + const int errorCode = err.getErrorCode(); + + // If the error is anything other than a unique constraint error + if(1 != errorCode) { + foundErrorOtherThanUniqueConstraint = true; + ex.getMessage() << ": Row " << rowIndex << " generated ORA error " << errorCode; + } + } + if (foundErrorOtherThanUniqueConstraint) { + throw ex; + } + } catch(oracle::occi::SQLException &ex) { + std::ostringstream msg; + msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << + ex.what(); + + if(rdbms::wrapper::OcciStmt::connShouldBeClosed(ex)) { + // Close the statement first and then the connection + try { + occiStmt.close(); + } catch(...) { + } + + try { + conn.closeUnderlyingStmtsAndConn(); + } catch(...) { + } + throw exception::LostDatabaseConnection(msg.str()); + } + throw exception::Exception(msg.str()); + } catch(std::exception &se) { + std::ostringstream msg; + msg << std::string(__FUNCTION__) << " failed for SQL statement " << rdbms::getSqlForException(sql) << ": " << + se.what(); + + throw exception::Exception(msg.str()); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + + +std::list<cta::catalogue::InsertFileRecycleLog> OracleTapeFileCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog( + rdbms::Conn& conn) { + std::list<cta::catalogue::InsertFileRecycleLog> fileRecycleLogsToInsert; + try { + //Get the TAPE_FILE entry to put on the file recycle log + { + const char *const sql = + "SELECT " + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," + "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " + "FROM " + "TAPE_FILE " + "JOIN " + "TEMP_TAPE_FILE_INSERTION_BATCH " + "ON " + "TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID AND TEMP_TAPE_FILE_INSERTION_BATCH.COPY_NB = TAPE_FILE.COPY_NB " + "WHERE " + "TAPE_FILE.VID != TEMP_TAPE_FILE_INSERTION_BATCH.VID OR TAPE_FILE.FSEQ != TEMP_TAPE_FILE_INSERTION_BATCH.FSEQ"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while(rset.next()){ + cta::catalogue::InsertFileRecycleLog fileRecycleLog; + fileRecycleLog.vid = rset.columnString("VID"); + fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); + fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); + fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); + fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); + fileRecycleLog.recycleLogTime = time(nullptr); + fileRecycleLogsToInsert.push_back(fileRecycleLog); + } + } + { + for(auto & fileRecycleLog: fileRecycleLogsToInsert){ + const auto fileRecycleLogCatalogue + = static_cast<RdbmsFileRecycleLogCatalogue*>(m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLogCatalogue->insertFileInFileRecycleLog(conn, fileRecycleLog); + } + } + return fileRecycleLogsToInsert; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp b/catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp new file mode 100644 index 0000000000..e60ec5d889 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapeFileCatalogue.hpp @@ -0,0 +1,88 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "common/checksum/ChecksumBlob.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class InsertFileRecycleLog; +class RdbmsCatalogue; + +class OracleTapeFileCatalogue : public RdbmsTapeFileCatalogue { +public: + OracleTapeFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + ~OracleTapeFileCatalogue() override = default; + + void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) override; + +private: + void copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const override; + + uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid); + + /** + * Batch inserts rows into the ARCHIVE_FILE table that correspond to the + * specified TapeFileWritten events. + * + * This method has idempotent behaviour in the case where an ARCHIVE_FILE + * already exists. Such a situation will occur when a file has more than one + * copy on tape. The first tape copy will cause two successful inserts, one + * into the ARCHIVE_FILE table and one into the TAPE_FILE table. The second + * tape copy will try to do the same, but the insert into the ARCHIVE_FILE + * table will fail or simply bounce as the row will already exists. The + * insert into the TABLE_FILE table will succeed because the two TAPE_FILE + * rows will be unique. + * + * @param conn The database connection. + * @param events The tape file written events. + */ + void idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const std::set<TapeFileWritten> &events); + + /** + * In the case we insert a TAPE_FILE that already has a copy on the catalogue (same copyNb), + * this TAPE_FILE will go to the FILE_RECYCLE_LOG table. + * + * This case happens always during the repacking of a tape: the new TAPE_FILE created + * will replace the old one, the old one will then be moved to the FILE_RECYCLE_LOG table + * + * @param conn The database connection. + * @returns the list of inserted fileRecycleLog + */ + std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn & conn); + +}; // class OracleTapeFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleTapePoolCatalogue.cpp b/catalogue/rdbms/oracle/OracleTapePoolCatalogue.cpp new file mode 100644 index 0000000000..4dde1f6b93 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapePoolCatalogue.cpp @@ -0,0 +1,55 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleTapePoolCatalogue::OracleTapePoolCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapePoolCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleTapePoolCatalogue::getNextTapePoolId(rdbms::Conn &conn) const { + try { + const char *const sql = + "SELECT " + "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; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp b/catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp new file mode 100644 index 0000000000..857291cd8d --- /dev/null +++ b/catalogue/rdbms/oracle/OracleTapePoolCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapePoolCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleTapePoolCatalogue : public RdbmsTapePoolCatalogue { +public: + OracleTapePoolCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleTapePoolCatalogue() override = default; + +private: + uint64_t getNextTapePoolId(rdbms::Conn &conn) const override; +}; // class PostgresMediaTypeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.cpp b/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.cpp new file mode 100644 index 0000000000..3c1ca532b4 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.cpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +OracleVirtualOrganizationCatalogue::OracleVirtualOrganizationCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsVirtualOrganizationCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t OracleVirtualOrganizationCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { + try { + const char *const sql = + "SELECT " + "VIRTUAL_ORGANIZATION_ID_SEQ.NEXTVAL AS VIRTUAL_ORGANIZATION_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("VIRTUAL_ORGANIZATION_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp b/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..c8e46e9b12 --- /dev/null +++ b/catalogue/rdbms/oracle/OracleVirtualOrganizationCatalogue.hpp @@ -0,0 +1,39 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class OracleVirtualOrganizationCatalogue : public RdbmsVirtualOrganizationCatalogue { +public: + OracleVirtualOrganizationCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~OracleVirtualOrganizationCatalogue() override = default; + +private: + uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; +}; // class OracleFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.cpp b/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.cpp new file mode 100644 index 0000000000..9e00c39e50 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.cpp @@ -0,0 +1,338 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresArchiveFileCatalogue::PostgresArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue) + : RdbmsArchiveFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void PostgresArchiveFileCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, + const uint64_t archiveFileId, log::LogContext &lc) { + try { + const char *selectSql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.DISK_INSTANCE_NAME AS DISK_INSTANCE_NAME," + "ARCHIVE_FILE.DISK_FILE_ID AS DISK_FILE_ID," + "ARCHIVE_FILE.DISK_FILE_UID AS DISK_FILE_UID," + "ARCHIVE_FILE.DISK_FILE_GID AS DISK_FILE_GID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32," + "STORAGE_CLASS.STORAGE_CLASS_NAME AS STORAGE_CLASS_NAME," + "ARCHIVE_FILE.CREATION_TIME AS ARCHIVE_FILE_CREATION_TIME," + "ARCHIVE_FILE.RECONCILIATION_TIME AS RECONCILIATION_TIME," + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.LOGICAL_SIZE_IN_BYTES AS LOGICAL_SIZE_IN_BYTES," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN STORAGE_CLASS ON " + "ARCHIVE_FILE.STORAGE_CLASS_ID = STORAGE_CLASS.STORAGE_CLASS_ID " + "INNER JOIN TAPE_FILE ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID " + "WHERE " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID " + "FOR UPDATE OF ARCHIVE_FILE"; + utils::Timer t; + auto conn = m_connPool->getConn(); + rdbms::AutoRollback autoRollback(conn); + conn.executeNonQuery("BEGIN"); + + const auto getConnTime = t.secs(utils::Timer::resetCounter); + auto selectStmt = conn.createStmt(selectSql); + const auto createStmtTime = t.secs(); + selectStmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + t.reset(); + rdbms::Rset selectRset = selectStmt.executeQuery(); + const auto selectFromArchiveFileTime = t.secs(); + std::unique_ptr<common::dataStructures::ArchiveFile> archiveFile; + std::set<std::string> vidsToSetDirty; + while(selectRset.next()) { + if(nullptr == archiveFile.get()) { + archiveFile = std::make_unique<common::dataStructures::ArchiveFile>(); + + archiveFile->archiveFileID = selectRset.columnUint64("ARCHIVE_FILE_ID"); + archiveFile->diskInstance = selectRset.columnString("DISK_INSTANCE_NAME"); + archiveFile->diskFileId = selectRset.columnString("DISK_FILE_ID"); + archiveFile->diskFileInfo.owner_uid = selectRset.columnUint64("DISK_FILE_UID"); + archiveFile->diskFileInfo.gid = selectRset.columnUint64("DISK_FILE_GID"); + archiveFile->fileSize = selectRset.columnUint64("SIZE_IN_BYTES"); + archiveFile->checksumBlob.deserializeOrSetAdler32(selectRset.columnBlob("CHECKSUM_BLOB"), selectRset.columnUint64("CHECKSUM_ADLER32")); + archiveFile->storageClass = selectRset.columnString("STORAGE_CLASS_NAME"); + archiveFile->creationTime = selectRset.columnUint64("ARCHIVE_FILE_CREATION_TIME"); + archiveFile->reconciliationTime = selectRset.columnUint64("RECONCILIATION_TIME"); + } + + // If there is a tape file + if(!selectRset.columnIsNull("VID")) { + // Add the tape file to the archive file's in-memory structure + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = selectRset.columnString("VID"); + vidsToSetDirty.insert(tapeFile.vid); + tapeFile.fSeq = selectRset.columnUint64("FSEQ"); + tapeFile.blockId = selectRset.columnUint64("BLOCK_ID"); + tapeFile.fileSize = selectRset.columnUint64("LOGICAL_SIZE_IN_BYTES"); + tapeFile.copyNb = selectRset.columnUint64("COPY_NB"); + tapeFile.creationTime = selectRset.columnUint64("TAPE_FILE_CREATION_TIME"); + tapeFile.checksumBlob = archiveFile->checksumBlob; // Duplicated for convenience + + archiveFile->tapeFiles.push_back(tapeFile); + } + } + + if(nullptr == archiveFile.get()) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", archiveFileId); + lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); + return; + } + + if(diskInstanceName != archiveFile->diskInstance) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("requestDiskInstance", diskInstanceName) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("createStmtTime", createStmtTime) + .add("selectFromArchiveFileTime", selectFromArchiveFileTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << it->copyNb + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << it->copyNb; + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " + "of the archived file"); + + exception::UserError ue; + ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " + "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << + archiveFile->diskInstance; + throw ue; + } + + t.reset(); + { + const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + + const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); + + for(auto &vidToSetDirty: vidsToSetDirty){ + //We deleted the TAPE_FILE so the tapes containing them should be set as dirty + RdbmsCatalogueUtils::setTapeDirty(conn,vidToSetDirty); + } + + const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); + + { + const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); + + conn.commit(); + autoRollback.cancel(); + const auto commitTime = t.secs(); + + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("createStmtTime", createStmtTime) + .add("selectFromArchiveFileTime", selectFromArchiveFileTime) + .add("deleteFromTapeFileTime", deleteFromTapeFileTime) + .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) + .add("setTapeDirtyTime",setTapeDirtyTime) + .add("commitTime", commitTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << it->copyNb + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::INFO, "Archive file deleted from CTA catalogue"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t PostgresArchiveFileCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { + try { + const char *const sql = + "select NEXTVAL('ARCHIVE_FILE_ID_SEQ') AS ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("ARCHIVE_FILE_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void PostgresArchiveFileCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) { + try { + utils::Timer t; + log::TimingList tl; + //We currently do an INSERT INTO and a DELETE FROM + //in a single transaction + conn.executeNonQuery("BEGIN"); + const auto fileRecycleLog = static_cast<RdbmsFileRecycleLogCatalogue*>(m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLog->copyArchiveFileToFileRecycleLog(conn,request); + tl.insertAndReset("insertToRecycleBinTime",t); + RdbmsCatalogueUtils::setTapeDirty(conn,request.archiveFileID); + tl.insertAndReset("setTapeDirtyTime",t); + const auto tapeFileCatalogue = static_cast<RdbmsTapeFileCatalogue*>(m_rdbmsCatalogue->TapeFile().get()); + tapeFileCatalogue->deleteTapeFiles(conn,request); + tl.insertAndReset("deleteTapeFilesTime",t); + deleteArchiveFile(conn,request); + tl.insertAndReset("deleteArchiveFileTime",t); + conn.commit(); + tl.insertAndReset("commitTime",t); + log::ScopedParamContainer spc(lc); + spc.add("archiveFileId",request.archiveFileID); + spc.add("diskFileId",request.diskFileId); + spc.add("diskFilePath",request.diskFilePath); + spc.add("diskInstance",request.diskInstance); + tl.addToLog(spc); + lc.log(log::INFO,"In PostgresCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// selectArchiveFileSizeAndChecksum +//------------------------------------------------------------------------------ +std::map<uint64_t, PostgresArchiveFileCatalogue::FileSizeAndChecksum> + PostgresArchiveFileCatalogue::selectArchiveFileSizesAndChecksums( + rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const { + try { + std::vector<uint64_t> archiveFileIdList(events.size()); + for (const auto &event: events) { + archiveFileIdList.push_back(event.archiveFileId); + } + + const char *const sql = + "SELECT " + "ARCHIVE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID," + "ARCHIVE_FILE.SIZE_IN_BYTES AS SIZE_IN_BYTES," + "ARCHIVE_FILE.CHECKSUM_BLOB AS CHECKSUM_BLOB," + "ARCHIVE_FILE.CHECKSUM_ADLER32 AS CHECKSUM_ADLER32 " + "FROM " + "ARCHIVE_FILE " + "INNER JOIN TEMP_TAPE_FILE_BATCH ON " + "ARCHIVE_FILE.ARCHIVE_FILE_ID = TEMP_TAPE_FILE_BATCH.ARCHIVE_FILE_ID"; + auto stmt = conn.createStmt(sql); + + auto rset = stmt.executeQuery(); + + std::map<uint64_t, FileSizeAndChecksum> fileSizesAndChecksums; + while (rset.next()) { + const uint64_t archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + + if (fileSizesAndChecksums.end() != fileSizesAndChecksums.find(archiveFileId)) { + exception::Exception ex; + ex.getMessage() << __FUNCTION__ << " failed: " + "Found duplicate archive file identifier in batch of files written to tape: archiveFileId=" << archiveFileId; + throw ex; + } + + FileSizeAndChecksum fileSizeAndChecksum; + fileSizeAndChecksum.fileSize = rset.columnUint64("SIZE_IN_BYTES"); + fileSizeAndChecksum.checksumBlob.deserializeOrSetAdler32(rset.columnBlob("CHECKSUM_BLOB"), rset.columnUint64("CHECKSUM_ADLER32")); + fileSizesAndChecksums[archiveFileId] = fileSizeAndChecksum; + } + + return fileSizesAndChecksums; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp b/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..97f40414dc --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp @@ -0,0 +1,72 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "common/checksum/ChecksumBlob.hpp" + +namespace cta { + +namespace catalogue { + +class TapeFileWritten; +class RdbmsCatalogue; + +class PostgresArchiveFileCatalogue : public RdbmsArchiveFileCatalogue { +public: + PostgresArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresArchiveFileCatalogue() override = default; + + void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, + log::LogContext &lc) override; + +private: + uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; + + void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; + + /** + * The size and checksum of a file. + */ + struct FileSizeAndChecksum { + uint64_t fileSize; + checksum::ChecksumBlob checksumBlob; + }; + + friend class PostgresTapeFileCatalogue; + + /** + * Returns the sizes and checksums of the specified archive files. + * + * @param conn The database connection. + * @param events The tape file written events that identify the archive files. + * @return A map from the identifier of each archive file to its size and checksum. + */ + std::map<uint64_t, FileSizeAndChecksum> selectArchiveFileSizesAndChecksums(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events) const; +}; // class PostgresArchiveFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresCatalogue.cpp b/catalogue/rdbms/postgres/PostgresCatalogue.cpp new file mode 100644 index 0000000000..ab3d09952c --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresCatalogue.cpp @@ -0,0 +1,91 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "rdbms/Login.hpp" + +namespace cta { +namespace catalogue { + +PostgresCatalogue::PostgresCatalogue( + log::Logger &log, + const rdbms::Login &login, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns) + : RdbmsCatalogue( + log, + rdbms::Login(rdbms::Login::DBTYPE_POSTGRESQL, + login.username, login.password, login.database, + login.hostname, login.port), + nbConns, + nbArchiveFileListingConns) { + RdbmsCatalogue::m_vo = std::make_unique<PostgresVirtualOrganizationCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_mediaType = std::make_unique<PostgresMediaTypeCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_storageClass = std::make_unique<PostgresStorageClassCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapePool = std::make_unique<PostgresTapePoolCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapeFile = std::make_unique<PostgresTapeFileCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_fileRecycleLog = std::make_unique<PostgresFileRecycleLogCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_logicalLibrary = std::make_unique<PostgresLogicalLibraryCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_archiveFile = std::make_unique<PostgresArchiveFileCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tape = std::make_unique<PostgresTapeCatalogue>(m_log, m_connPool, this); +} + +std::string PostgresCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const { + const std::string tempTableName = "TEMP_DISK_FXIDS"; + + if(diskFileIds) { + try { + std::string sql = "CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID VARCHAR(100))"; + try { + conn.executeNonQuery(sql); + } catch(exception::Exception &ex) { + // Postgres does not drop temporary tables until the end of the session; trying to create another + // temporary table in the same unit test will fail. If this happens, truncate the table and carry on. + sql = "TRUNCATE TABLE " + tempTableName; + conn.executeNonQuery(sql); + } + + sql = "INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"; + auto stmt = conn.createStmt(sql); + for(auto &diskFileId : diskFileIds.value()) { + stmt.bindString(":DISK_FILE_ID", diskFileId); + stmt.executeNonQuery(); + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } + } + return tempTableName; +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresCatalogue.hpp b/catalogue/rdbms/postgres/PostgresCatalogue.hpp new file mode 100644 index 0000000000..f5afb9e043 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresCatalogue.hpp @@ -0,0 +1,69 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +/** + * An Postgres based implementation of the CTA catalogue. + */ +class PostgresCatalogue: public RdbmsCatalogue { +public: + + /** + * Constructor. + * + * @param log Object representing the API to the CTA logging system. + * @param username The database username. + * @param password The database password. + * @param database The database name. + * @param nbConns The maximum number of concurrent connections to the + * underlying relational database for all operations accept listing archive + * files which can be relatively long operations. + * @param nbArchiveFileListingConns The maximum number of concurrent + * connections to the underlying relational database for the sole purpose of + * listing archive files. + */ + PostgresCatalogue( + log::Logger &log, + const rdbms::Login &login, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns); + + /** + * Destructor. + */ + ~PostgresCatalogue() override = default; + + /** + * Creates a temporary table from the list of disk file IDs provided in the search criteria. + * + * @param conn The database connection. + * @param diskFileIds List of disk file IDs (fxid). + * @return Name of the temporary table + */ + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const override; +}; // class PostgresCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.cpp b/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.cpp new file mode 100644 index 0000000000..f0688bf7f4 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.cpp @@ -0,0 +1,110 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +PostgresFileRecycleLogCatalogue::PostgresFileRecycleLogCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsFileRecycleLogCatalogue(log, connPool, rdbmsCatalogue) {} + + +void PostgresFileRecycleLogCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, + FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) { + try { + utils::Timer timer; + log::TimingList timingList; + + if (!fileRecycleLogItor.hasMore()) { + throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); + } + auto fileRecycleLog = fileRecycleLogItor.next(); + if (fileRecycleLogItor.hasMore()) { + // stop restoring more than one file at once + throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); + } + + // We currently do all file copies restoring in a single transaction + conn.executeNonQuery("BEGIN"); + const auto archiveFileCatalogue = static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + if (auto archiveFilePtr = archiveFileCatalogue->getArchiveFileById(conn, fileRecycleLog.archiveFileId); + !archiveFilePtr) { + RdbmsFileRecycleLogCatalogue::restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); + } else { + if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { + // copy with same copy_nb exists, cannot restore + UserSpecifiedExistingDeletedFileCopy ex; + ex.getMessage() << "Cannot restore file copy with archiveFileId " + << std::to_string(fileRecycleLog.archiveFileId) + << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) + << " because a tapefile with same archiveFileId and copy_nb already exists"; + throw ex; + } + } + + RdbmsFileRecycleLogCatalogue::restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); + conn.commit(); + + log::ScopedParamContainer spc(lc); + timingList.insertAndReset("commitTime", timer); + timingList.addToLog(spc); + lc.log(log::INFO, "In PostgresFileRecycleLogCatalogue::restoreEntryInRecycleLog: " + "all file copies successfully restored."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t PostgresFileRecycleLogCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) const { + try { + const char *const sql = + "select NEXTVAL('FILE_RECYCLE_LOG_ID_SEQ') AS FILE_RECYCLE_LOG_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("FILE_RECYCLE_LOG_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp b/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..3383c4214a --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresFileRecycleLogCatalogue.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresFileRecycleLogCatalogue : public RdbmsFileRecycleLogCatalogue { +public: + PostgresFileRecycleLogCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresFileRecycleLogCatalogue() override = default; + +private: + + void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, + log::LogContext & lc) override; + + /** + * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry + * @param conn the database connection + * @param fileRecycleLog the fileRecycleLog we want to restore + * @param lc the log context + */ + void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, + log::LogContext & lc); + + uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) const override; +}; // class PostgresFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.cpp b/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.cpp new file mode 100644 index 0000000000..aae87be493 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.cpp @@ -0,0 +1,50 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresLogicalLibraryCatalogue::PostgresLogicalLibraryCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsLogicalLibraryCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresLogicalLibraryCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) const { + try { + const char *const sql = + "select NEXTVAL('LOGICAL_LIBRARY_ID_SEQ') AS LOGICAL_LIBRARY_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("LOGICAL_LIBRARY_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp b/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..80c7d76b8b --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresLogicalLibraryCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresLogicalLibraryCatalogue : public RdbmsLogicalLibraryCatalogue { +public: + PostgresLogicalLibraryCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresLogicalLibraryCatalogue() override = default; + +private: + uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) const override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.cpp b/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.cpp new file mode 100644 index 0000000000..d44d38f74e --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.cpp @@ -0,0 +1,49 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresMediaTypeCatalogue::PostgresMediaTypeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsMediaTypeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresMediaTypeCatalogue::getNextMediaTypeId(rdbms::Conn &conn) const { + try { + const char *const sql = "select NEXTVAL('MEDIA_TYPE_ID_SEQ') AS MEDIA_TYPE_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("MEDIA_TYPE_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp b/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp new file mode 100644 index 0000000000..90187242a3 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresMediaTypeCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresMediaTypeCatalogue : public RdbmsMediaTypeCatalogue { +public: + PostgresMediaTypeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresMediaTypeCatalogue() override = default; + +private: + uint64_t getNextMediaTypeId(rdbms::Conn &conn) const override; +}; // class PostgresMediaTypeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.cpp b/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.cpp new file mode 100644 index 0000000000..eaa1ec954c --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.cpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresStorageClassCatalogue::PostgresStorageClassCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsStorageClassCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresStorageClassCatalogue::getNextStorageClassId(rdbms::Conn &conn) { + try { + const char *const sql = + "select NEXTVAL('STORAGE_CLASS_ID_SEQ') AS STORAGE_CLASS_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("STORAGE_CLASS_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp b/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp new file mode 100644 index 0000000000..4c42d2af1d --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresStorageClassCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresStorageClassCatalogue : public RdbmsStorageClassCatalogue { +public: + PostgresStorageClassCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresStorageClassCatalogue() override = default; + +private: + uint64_t getNextStorageClassId(rdbms::Conn &conn) override; +}; // class PostgresStorageClassCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresTapeCatalogue.cpp b/catalogue/rdbms/postgres/PostgresTapeCatalogue.cpp new file mode 100644 index 0000000000..2d2d28f2a0 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapeCatalogue.cpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresTapeCatalogue::PostgresTapeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresTapeCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " + "FROM " + "TAPE " + "WHERE " + "VID = :VID"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if(rset.next()) { + return rset.columnUint64("LAST_FSEQ"); + } else { + throw exception::Exception(std::string("No such tape with vid=") + vid); + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp b/catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp new file mode 100644 index 0000000000..882d727337 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapeCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresTapeCatalogue : public RdbmsTapeCatalogue { +public: + PostgresTapeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresTapeCatalogue() override = default; + +private: + uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const override; +}; // class PostgresTapeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.cpp b/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.cpp new file mode 100644 index 0000000000..b98c44d352 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.cpp @@ -0,0 +1,589 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <algorithm> +#include <string> + +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/rdbms/postgres/PostgresArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/TapeItemWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/FileSizeMismatch.hpp" +#include "common/exception/TapeFseqMismatch.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/wrapper/PostgresColumn.hpp" +#include "rdbms/wrapper/PostgresStmt.hpp" + +namespace cta { +namespace catalogue { + +namespace { +/** + * Structure used to assemble a batch of rows to insert into the TAPE_FILE + * table. + */ +struct TapeFileBatch { + size_t nbRows; + rdbms::wrapper::PostgresColumn vid; + rdbms::wrapper::PostgresColumn fSeq; + rdbms::wrapper::PostgresColumn blockId; + rdbms::wrapper::PostgresColumn fileSize; + rdbms::wrapper::PostgresColumn copyNb; + rdbms::wrapper::PostgresColumn creationTime; + rdbms::wrapper::PostgresColumn archiveFileId; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + TapeFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + vid("VID", nbRows), + fSeq("FSEQ", nbRows), + blockId("BLOCK_ID", nbRows), + fileSize("LOGICAL_SIZE_IN_BYTES", nbRows), + copyNb("COPY_NB", nbRows), + creationTime("CREATION_TIME", nbRows), + archiveFileId("ARCHIVE_FILE_ID", nbRows) { + } +}; // struct TapeFileBatch + +/** + * Structure used to assemble a batch of rows to insert into the TEMP_ARCHIVE_FILE_BATCH + * table. + */ +struct ArchiveFileBatch { + size_t nbRows; + rdbms::wrapper::PostgresColumn archiveFileId; + rdbms::wrapper::PostgresColumn diskInstance; + rdbms::wrapper::PostgresColumn diskFileId; + rdbms::wrapper::PostgresColumn diskFileUser; + rdbms::wrapper::PostgresColumn diskFileGroup; + rdbms::wrapper::PostgresColumn size; + rdbms::wrapper::PostgresColumn checksumBlob; + rdbms::wrapper::PostgresColumn checksumAdler32; + rdbms::wrapper::PostgresColumn storageClassName; + rdbms::wrapper::PostgresColumn creationTime; + rdbms::wrapper::PostgresColumn reconciliationTime; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + ArchiveFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + archiveFileId("ARCHIVE_FILE_ID", nbRows), + diskInstance("DISK_INSTANCE_NAME", nbRows), + diskFileId("DISK_FILE_ID", nbRows), + diskFileUser("DISK_FILE_UID", nbRows), + diskFileGroup("DISK_FILE_GID", nbRows), + size("SIZE_IN_BYTES", nbRows), + checksumBlob("CHECKSUM_BLOB", nbRows), + checksumAdler32("CHECKSUM_ADLER32", nbRows), + storageClassName("STORAGE_CLASS_NAME", nbRows), + creationTime("CREATION_TIME", nbRows), + reconciliationTime("RECONCILIATION_TIME", nbRows) { + } +}; // struct ArchiveFileBatch + +/** + * Structure used to assemble a batch of rows to insert into the + * TAPE_FILE_BATCH temporary table. + */ +struct TempTapeFileBatch { + size_t nbRows; + rdbms::wrapper::PostgresColumn archiveFileId; + + /** + * Constructor. + * + * @param nbRowsValue The Number of rows to be inserted. + */ + TempTapeFileBatch(const size_t nbRowsValue): + nbRows(nbRowsValue), + archiveFileId("ARCHIVE_FILE_ID", nbRows) { + } +}; // struct TempTapeFileBatch + +} // anonymous namespace + +PostgresTapeFileCatalogue::PostgresTapeFileCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue) + : RdbmsTapeFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void PostgresTapeFileCatalogue::copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const { + conn.executeNonQuery("BEGIN"); + const auto fileRecycleLogCatalogue = static_cast<RdbmsFileRecycleLogCatalogue*>( + RdbmsTapeFileCatalogue::m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLogCatalogue->copyTapeFilesToFileRecycleLog(conn, file, reason); + timingList->insertAndReset("insertToRecycleBinTime", *timer); + RdbmsCatalogueUtils::setTapeDirty(conn, file.archiveFileID); + timingList->insertAndReset("setTapeDirtyTime", *timer); + deleteTapeFiles(conn, file); + timingList->insertAndReset("deleteTapeFilesTime", *timer); + conn.commit(); +} + +void PostgresTapeFileCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { + try { + if (events.empty()) { + return; + } + + auto firstEventItor = events.begin(); + const auto &firstEvent = **firstEventItor; + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); + const time_t now = time(nullptr); + auto conn = m_connPool->getConn(); + rdbms::AutoRollback autoRollback(conn); + + // Start DB transaction and create temporary tables TEMP_ARCHIVE_FILE_BATCH and TEMP_TAPE_FILE_BATCH. + // These two tables will exist only for the duration of the transaction. + // Set deferrable for second (disk instance, disk file id) constraint of the ARCHIVE_FILE table + // to avoid violation in the case of concurrent inserts of a previously not existing archive file. + beginCreateTemporarySetDeferred(conn); + + 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 + // allow checking fSeq coherency. + // determine the number of files + size_t filesCount=std::count_if(events.cbegin(), events.cend(), + [](const TapeItemWrittenPointer &e) -> bool {return typeid(*e)==typeid(TapeFileWritten);}); + TapeFileBatch tapeFileBatch(filesCount); + + std::set<TapeFileWritten> fileEvents; + + for (const auto &eventP: events) { + // Check for all item types. + const auto &event = *eventP; + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); + + if (event.vid != firstEvent.vid) { + throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); + } + + if (expectedFSeq != event.fSeq) { + exception::TapeFseqMismatch ex; + ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << + event.fSeq; + throw ex; + } + expectedFSeq++; + + try { + // If this is a file (as opposed to a placeholder), do the full processing. + const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); + + checkTapeFileWrittenFieldsAreSet(__FUNCTION__, fileEvent); + + totalLogicalBytesWritten += fileEvent.size; + + fileEvents.insert(fileEvent); + } catch (std::bad_cast&) {} + } + + // Update the tape because all the necessary information is now available + auto lastEventItor = events.cend(); + lastEventItor--; + const TapeItemWritten &lastEvent = **lastEventItor; + RdbmsCatalogueUtils::updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, + lastEvent.tapeDrive); + + // If we had only placeholders and no file recorded, we are done (but we still commit the update of the tape's fSeq). + if (fileEvents.empty()) { + conn.commit(); + return; + } + + // Create the archive file entries, skipping those that already exist + // However we don't currently lock existing rows, so this transaction may + // still fail later, in the face of certain concurrent modifications such + // as the deletion of one of the existing archive files for which we are + // inserting another tape file. + idempotentBatchInsertArchiveFiles(conn, fileEvents); + + insertTapeFileBatchIntoTempTable(conn, fileEvents); + + // Verify that the archive file entries in the catalogue database agree with + // the tape file written events + const auto archiveFileCatalogue = static_cast<PostgresArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + const auto fileSizesAndChecksums = archiveFileCatalogue->selectArchiveFileSizesAndChecksums(conn, fileEvents); + for (const auto &event: fileEvents) { + const auto fileSizeAndChecksumItor = fileSizesAndChecksums.find(event.archiveFileId); + + std::ostringstream fileContext; + fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << + ", diskFileId=" << event.diskFileId; + + // This should never happen + if(fileSizesAndChecksums.end() == fileSizeAndChecksumItor) { + exception::Exception ex; + ex.getMessage() << __FUNCTION__ << ": Failed to find archive file entry in the catalogue: " << fileContext.str(); + throw ex; + } + + const auto &fileSizeAndChecksum = fileSizeAndChecksumItor->second; + + if(fileSizeAndChecksum.fileSize != event.size) { + catalogue::FileSizeMismatch ex; + ex.getMessage() << __FUNCTION__ << ": File size mismatch: expected=" << fileSizeAndChecksum.fileSize << + ", actual=" << event.size << ": " << fileContext.str(); + throw ex; + } + + fileSizeAndChecksum.checksumBlob.validate(event.checksumBlob); + } + + // Store the value of each field + uint32_t i = 0; + for (const auto &event: fileEvents) { + tapeFileBatch.vid.setFieldValue(i, event.vid); + tapeFileBatch.fSeq.setFieldValue(i, event.fSeq); + tapeFileBatch.blockId.setFieldValue(i, event.blockId); + tapeFileBatch.fileSize.setFieldValue(i, event.size); + tapeFileBatch.copyNb.setFieldValue(i, event.copyNb); + tapeFileBatch.creationTime.setFieldValue(i, now); + tapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); + i++; + } + + const char *const sql = + "CREATE TEMPORARY TABLE TEMP_TAPE_FILE_INSERTION_BATCH (" "\n" + "LIKE TAPE_FILE) " "\n" + "ON COMMIT DROP;" "\n" + "COPY TEMP_TAPE_FILE_INSERTION_BATCH(" "\n" + "VID," "\n" + "FSEQ," "\n" + "BLOCK_ID," "\n" + "LOGICAL_SIZE_IN_BYTES," "\n" + "COPY_NB," "\n" + "CREATION_TIME," "\n" + "ARCHIVE_FILE_ID) " "\n" + "FROM STDIN; --" "\n" + "-- :VID," "\n" + "-- :FSEQ," "\n" + "-- :BLOCK_ID," "\n" + "-- :LOGICAL_SIZE_IN_BYTES," "\n" + "-- :COPY_NB," "\n" + "-- :CREATION_TIME," "\n" + "-- :ARCHIVE_FILE_ID;" "\n"; + + auto stmt = conn.createStmt(sql); + rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); + postgresStmt.setColumn(tapeFileBatch.vid); + postgresStmt.setColumn(tapeFileBatch.fSeq); + postgresStmt.setColumn(tapeFileBatch.blockId); + postgresStmt.setColumn(tapeFileBatch.fileSize); + postgresStmt.setColumn(tapeFileBatch.copyNb); + postgresStmt.setColumn(tapeFileBatch.creationTime); + postgresStmt.setColumn(tapeFileBatch.archiveFileId); + + postgresStmt.executeCopyInsert(tapeFileBatch.nbRows); + + auto recycledFiles = insertOldCopiesOfFilesIfAnyOnFileRecycleLog(conn); + + { + //Insert the tapefiles from the TEMP_TAPE_FILE_INSERTION_BATCH + const char * const insertTapeFileSql = + "INSERT INTO TAPE_FILE (VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES, " + "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID) " + "SELECT VID, FSEQ, BLOCK_ID, LOGICAL_SIZE_IN_BYTES, " + "COPY_NB, CREATION_TIME, ARCHIVE_FILE_ID FROM TEMP_TAPE_FILE_INSERTION_BATCH;"; + conn.executeNonQuery(insertTapeFileSql); + } + + for(auto & recycledFile: recycledFiles){ + const char * const deleteTapeFileSql = + "DELETE FROM TAPE_FILE WHERE TAPE_FILE.VID = :VID AND TAPE_FILE.FSEQ = :FSEQ"; + auto deleteTapeFileStmt = conn.createStmt(deleteTapeFileSql); + deleteTapeFileStmt.bindString(":VID",recycledFile.vid); + deleteTapeFileStmt.bindUint64(":FSEQ",recycledFile.fSeq); + deleteTapeFileStmt.executeNonQuery(); + } + + autoRollback.cancel(); + conn.commit(); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +std::list<cta::catalogue::InsertFileRecycleLog> PostgresTapeFileCatalogue::insertOldCopiesOfFilesIfAnyOnFileRecycleLog( + rdbms::Conn& conn){ + std::list<cta::catalogue::InsertFileRecycleLog> fileRecycleLogsToInsert; + try { + //Get the TAPE_FILE entry to put on the file recycle log + { + const char *const sql = + "SELECT " + "TAPE_FILE.VID AS VID," + "TAPE_FILE.FSEQ AS FSEQ," + "TAPE_FILE.BLOCK_ID AS BLOCK_ID," + "TAPE_FILE.COPY_NB AS COPY_NB," + "TAPE_FILE.CREATION_TIME AS TAPE_FILE_CREATION_TIME," + "TAPE_FILE.ARCHIVE_FILE_ID AS ARCHIVE_FILE_ID " + "FROM " + "TAPE_FILE " + "JOIN " + "TEMP_TAPE_FILE_INSERTION_BATCH " + "ON " + "TEMP_TAPE_FILE_INSERTION_BATCH.ARCHIVE_FILE_ID = TAPE_FILE.ARCHIVE_FILE_ID AND TEMP_TAPE_FILE_INSERTION_BATCH.COPY_NB = TAPE_FILE.COPY_NB " + "WHERE " + "TAPE_FILE.VID != TEMP_TAPE_FILE_INSERTION_BATCH.VID OR TAPE_FILE.FSEQ != TEMP_TAPE_FILE_INSERTION_BATCH.FSEQ"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + while(rset.next()){ + cta::catalogue::InsertFileRecycleLog fileRecycleLog; + fileRecycleLog.vid = rset.columnString("VID"); + fileRecycleLog.fSeq = rset.columnUint64("FSEQ"); + fileRecycleLog.blockId = rset.columnUint64("BLOCK_ID"); + fileRecycleLog.copyNb = rset.columnUint8("COPY_NB"); + fileRecycleLog.tapeFileCreationTime = rset.columnUint64("TAPE_FILE_CREATION_TIME"); + fileRecycleLog.archiveFileId = rset.columnUint64("ARCHIVE_FILE_ID"); + fileRecycleLog.reasonLog = InsertFileRecycleLog::getRepackReasonLog(); + fileRecycleLog.recycleLogTime = time(nullptr); + fileRecycleLogsToInsert.push_back(fileRecycleLog); + } + } + { + for(auto & fileRecycleLog: fileRecycleLogsToInsert){ + const auto fileRecycleLogCatalogue + = static_cast<RdbmsFileRecycleLogCatalogue*>(m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLogCatalogue->insertFileInFileRecycleLog(conn,fileRecycleLog); + } + return fileRecycleLogsToInsert; + } + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t PostgresTapeFileCatalogue::selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " + "FROM " + "TAPE " + "WHERE " + "VID = :VID " + "FOR UPDATE"; + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if (!rset.next()) { + throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); + } + + return rset.columnUint64("LAST_FSEQ"); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void PostgresTapeFileCatalogue::beginCreateTemporarySetDeferred(rdbms::Conn &conn) const { + conn.executeNonQuery("BEGIN"); + conn.executeNonQuery("CREATE TEMPORARY TABLE TEMP_ARCHIVE_FILE_BATCH (LIKE ARCHIVE_FILE) ON COMMIT DROP"); + conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ADD COLUMN STORAGE_CLASS_NAME VARCHAR(100)"); + conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ALTER COLUMN STORAGE_CLASS_ID DROP NOT NULL"); + conn.executeNonQuery("ALTER TABLE TEMP_ARCHIVE_FILE_BATCH ALTER COLUMN IS_DELETED DROP NOT NULL"); + conn.executeNonQuery("CREATE INDEX TEMP_A_F_B_ARCHIVE_FILE_ID_I ON TEMP_ARCHIVE_FILE_BATCH(ARCHIVE_FILE_ID)"); + conn.executeNonQuery("CREATE INDEX TEMP_A_F_B_DIN_SCN_I ON TEMP_ARCHIVE_FILE_BATCH(DISK_INSTANCE_NAME, STORAGE_CLASS_NAME)"); + conn.executeNonQuery("CREATE TEMPORARY TABLE TEMP_TAPE_FILE_BATCH(ARCHIVE_FILE_ID NUMERIC(20,0)) ON COMMIT DROP"); + conn.executeNonQuery("CREATE INDEX TEMP_T_F_B_ARCHIVE_FILE_ID_I ON TEMP_TAPE_FILE_BATCH(ARCHIVE_FILE_ID)"); + conn.executeNonQuery("SET CONSTRAINTS ARCHIVE_FILE_DIN_DFI_UN DEFERRED"); +} + +void PostgresTapeFileCatalogue::idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events) const { + try { + ArchiveFileBatch archiveFileBatch(events.size()); + const time_t now = time(nullptr); + + // Store the value of each field + uint32_t i = 0; + for (const auto &event: events) { + archiveFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); + archiveFileBatch.diskInstance.setFieldValue(i, event.diskInstance); + archiveFileBatch.diskFileId.setFieldValue(i, event.diskFileId); + archiveFileBatch.diskFileUser.setFieldValue(i, event.diskFileOwnerUid); + archiveFileBatch.diskFileGroup.setFieldValue(i, event.diskFileGid); + archiveFileBatch.size.setFieldValue(i, event.size); + archiveFileBatch.checksumBlob.setFieldByteA(conn, i, event.checksumBlob.serialize()); + // Keep transition ADLER32 checksum up-to-date if it exists + std::string adler32str; + try { + std::string adler32hex = checksum::ChecksumBlob::ByteArrayToHex(event.checksumBlob.at(checksum::ADLER32)); + uint32_t adler32 = strtoul(adler32hex.c_str(), 0, 16); + adler32str = std::to_string(adler32); + } catch(exception::ChecksumTypeMismatch &ex) { + adler32str = "0"; + } + archiveFileBatch.checksumAdler32.setFieldValue(i, adler32str); + archiveFileBatch.storageClassName.setFieldValue(i, event.storageClassName); + archiveFileBatch.creationTime.setFieldValue(i, now); + archiveFileBatch.reconciliationTime.setFieldValue(i, now); + i++; + } + + const char *const sql = + "COPY TEMP_ARCHIVE_FILE_BATCH(" + "ARCHIVE_FILE_ID," + "DISK_INSTANCE_NAME," + "DISK_FILE_ID," + "DISK_FILE_UID," + "DISK_FILE_GID," + "SIZE_IN_BYTES," + "CHECKSUM_BLOB," + "CHECKSUM_ADLER32," + "STORAGE_CLASS_NAME," + "CREATION_TIME," + "RECONCILIATION_TIME) " + "FROM STDIN --" + ":ARCHIVE_FILE_ID," + ":DISK_INSTANCE_NAME," + ":DISK_FILE_ID," + ":DISK_FILE_UID," + ":DISK_FILE_GID," + ":SIZE_IN_BYTES," + ":CHECKSUM_BLOB," + ":CHECKSUM_ADLER32," + ":STORAGE_CLASS_NAME," + ":CREATION_TIME," + ":RECONCILIATION_TIME"; + + auto stmt = conn.createStmt(sql); + rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); + + postgresStmt.setColumn(archiveFileBatch.archiveFileId); + postgresStmt.setColumn(archiveFileBatch.diskInstance); + postgresStmt.setColumn(archiveFileBatch.diskFileId); + postgresStmt.setColumn(archiveFileBatch.diskFileUser); + postgresStmt.setColumn(archiveFileBatch.diskFileGroup); + postgresStmt.setColumn(archiveFileBatch.size); + postgresStmt.setColumn(archiveFileBatch.checksumBlob); + postgresStmt.setColumn(archiveFileBatch.checksumAdler32); + postgresStmt.setColumn(archiveFileBatch.storageClassName); + postgresStmt.setColumn(archiveFileBatch.creationTime); + postgresStmt.setColumn(archiveFileBatch.reconciliationTime); + + postgresStmt.executeCopyInsert(archiveFileBatch.nbRows); + + const char *const sql_insert = + "INSERT INTO ARCHIVE_FILE(" + "ARCHIVE_FILE_ID," + "DISK_INSTANCE_NAME," + "DISK_FILE_ID," + "DISK_FILE_UID," + "DISK_FILE_GID," + "SIZE_IN_BYTES," + "CHECKSUM_BLOB," + "CHECKSUM_ADLER32," + "STORAGE_CLASS_ID," + "CREATION_TIME," + "RECONCILIATION_TIME) " + "SELECT " + "A.ARCHIVE_FILE_ID," + "A.DISK_INSTANCE_NAME," + "A.DISK_FILE_ID," + "A.DISK_FILE_UID," + "A.DISK_FILE_GID," + "A.SIZE_IN_BYTES," + "A.CHECKSUM_BLOB," + "A.CHECKSUM_ADLER32," + "S.STORAGE_CLASS_ID," + "A.CREATION_TIME," + "A.RECONCILIATION_TIME " + "FROM TEMP_ARCHIVE_FILE_BATCH AS A, STORAGE_CLASS AS S " + "WHERE A.STORAGE_CLASS_NAME = S.STORAGE_CLASS_NAME " + "ORDER BY A.ARCHIVE_FILE_ID " + "ON CONFLICT (ARCHIVE_FILE_ID) DO NOTHING"; + + // Concerns for bulk insertion in archive_file: deadlock with concurrent + // inserts of previously not-existing entry for the same archive file, + // hence insert with ORDER BY to define an update order. + + auto stmt_insert = conn.createStmt(sql_insert); + stmt_insert.executeNonQuery(); + + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void PostgresTapeFileCatalogue::insertTapeFileBatchIntoTempTable(rdbms::Conn &conn, + const std::set<TapeFileWritten> &events) const { + try { + TempTapeFileBatch tempTapeFileBatch(events.size()); + + // Store the value of each field + uint32_t i = 0; + for (const auto &event: events) { + tempTapeFileBatch.archiveFileId.setFieldValue(i, event.archiveFileId); + i++; + } + + const char *const sql = + "COPY TEMP_TAPE_FILE_BATCH(" + "ARCHIVE_FILE_ID) " + "FROM STDIN --" + ":ARCHIVE_FILE_ID"; + + auto stmt = conn.createStmt(sql); + rdbms::wrapper::PostgresStmt &postgresStmt = dynamic_cast<rdbms::wrapper::PostgresStmt &>(stmt.getStmt()); + + postgresStmt.setColumn(tempTapeFileBatch.archiveFileId); + postgresStmt.executeCopyInsert(tempTapeFileBatch.nbRows); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp b/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp new file mode 100644 index 0000000000..87186a5160 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapeFileCatalogue.hpp @@ -0,0 +1,101 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresTapeFileCatalogue : public RdbmsTapeFileCatalogue { +public: + PostgresTapeFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + ~PostgresTapeFileCatalogue() override = default; + + void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) override; + +private: + void copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const override; + + std::list<cta::catalogue::InsertFileRecycleLog> insertOldCopiesOfFilesIfAnyOnFileRecycleLog(rdbms::Conn& conn); + + /** + * 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. + */ + uint64_t selectTapeForUpdateAndGetLastFSeq(rdbms::Conn &conn, const std::string &vid) const; + + /** + * Start a database transaction and then create the temporary + * tables TEMP_ARCHIVE_FILE_BATCH and TEMP_TAPE_FILE_BATCH. + * Sets deferred mode for one of the db constraints to avoid + * violations during concurrent bulk insert. + * + * @parm conn The database connection. + */ + void beginCreateTemporarySetDeferred(rdbms::Conn &conn) const; + + /** + * Batch inserts rows into the ARCHIVE_FILE table that correspond to the + * specified TapeFileWritten events. + * + * This method has idempotent behaviour in the case where an ARCHIVE_FILE + * already exists. Such a situation will occur when a file has more than one + * copy on tape. The first tape copy will cause two successful inserts, one + * into the ARCHIVE_FILE table and one into the TAPE_FILE table. The second + * tape copy will try to do the same, but the insert into the ARCHIVE_FILE + * table will fail or simply bounce as the row will already exists. The + * insert into the TABLE_FILE table will succeed because the two TAPE_FILE + * rows will be unique. + * + * @param conn The database connection. + * @param events The tape file written events. + */ + void idempotentBatchInsertArchiveFiles(rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const; + + /** + * Batch inserts rows into the TAPE_FILE_BATCH temporary table that correspond + * to the specified TapeFileWritten events. + * + * @param conn The database connection. + * @param events The tape file written events. + */ + void insertTapeFileBatchIntoTempTable(rdbms::Conn &conn, const std::set<TapeFileWritten> &events) const; +}; // class PostgresTapeFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.cpp b/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.cpp new file mode 100644 index 0000000000..f09debac82 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.cpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresTapePoolCatalogue::PostgresTapePoolCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapePoolCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresTapePoolCatalogue::getNextTapePoolId(rdbms::Conn &conn) const { + 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; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp b/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp new file mode 100644 index 0000000000..c3334cea7c --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresTapePoolCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapePoolCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresTapePoolCatalogue : public RdbmsTapePoolCatalogue { +public: + PostgresTapePoolCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresTapePoolCatalogue() override = default; + +private: + uint64_t getNextTapePoolId(rdbms::Conn &conn) const override; +}; // class PostgresTapePoolCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.cpp b/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.cpp new file mode 100644 index 0000000000..65bcd29822 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.cpp @@ -0,0 +1,50 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +PostgresVirtualOrganizationCatalogue::PostgresVirtualOrganizationCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsVirtualOrganizationCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t PostgresVirtualOrganizationCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { + try { + const char *const sql = + "select NEXTVAL('VIRTUAL_ORGANIZATION_ID_SEQ') AS VIRTUAL_ORGANIZATION_ID"; + auto stmt = conn.createStmt(sql); + auto rset = stmt.executeQuery(); + if(!rset.next()) { + throw exception::Exception("Result set is unexpectedly empty"); + } + return rset.columnUint64("VIRTUAL_ORGANIZATION_ID"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp b/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..c8e68cf121 --- /dev/null +++ b/catalogue/rdbms/postgres/PostgresVirtualOrganizationCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class PostgresVirtualOrganizationCatalogue : public RdbmsVirtualOrganizationCatalogue { +public: + PostgresVirtualOrganizationCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~PostgresVirtualOrganizationCatalogue() override = default; + +protected: + uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; +}; // class PostgresVirtualOrganizationCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.cpp new file mode 100644 index 0000000000..f2748ed0cf --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.cpp @@ -0,0 +1,240 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/AutoRollback.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteArchiveFileCatalogue::SqliteArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue) + : RdbmsArchiveFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void SqliteArchiveFileCatalogue::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, + const uint64_t archiveFileId, + log::LogContext &lc) { + try { + utils::Timer t; + auto conn = m_connPool->getConn(); + const auto getConnTime = t.secs(); + rdbms::AutoRollback autoRollback(conn); + t.reset(); + const auto archiveFile = getArchiveFileById(conn, archiveFileId); + const auto getArchiveFileTime = t.secs(); + + if(nullptr == archiveFile.get()) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", archiveFileId); + lc.log(log::WARNING, "Ignoring request to delete archive file because it does not exist in the catalogue"); + return; + } + + if(diskInstanceName != archiveFile->diskInstance) { + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("requestDiskInstance", diskInstanceName) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("getArchiveFileTime", getArchiveFileTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << it->copyNb + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << it->copyNb; //this shouldn't be here: repeated field + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::WARNING, "Failed to delete archive file because the disk instance of the request does not match that " + "of the archived file"); + + exception::UserError ue; + ue.getMessage() << "Failed to delete archive file with ID " << archiveFileId << " because the disk instance of " + "the request does not match that of the archived file: archiveFileId=" << archiveFileId << " requestDiskInstance=" << diskInstanceName << " archiveFileDiskInstance=" << + archiveFile->diskInstance; + throw ue; + } + + t.reset(); + { + const char *const sql = "BEGIN DEFERRED;"; + auto stmt = conn.createStmt(sql); + stmt.executeNonQuery(); + } + { + const char *const sql = "DELETE FROM TAPE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + + const auto deleteFromTapeFileTime = t.secs(utils::Timer::resetCounter); + + std::set<std::string> vidsToSetDirty; + //We will insert the vids to set dirty in a set so that + //we limit the calls to setTapeDirty to the number of tapes that contained the deleted tape files + for(auto &tapeFile: archiveFile->tapeFiles){ + vidsToSetDirty.insert(tapeFile.vid); + } + + for(auto &vidToSetDirty: vidsToSetDirty){ + RdbmsCatalogueUtils::setTapeDirty(conn,vidToSetDirty); + } + + const auto setTapeDirtyTime = t.secs(utils::Timer::resetCounter); + + { + const char *const sql = "DELETE FROM ARCHIVE_FILE WHERE ARCHIVE_FILE_ID = :ARCHIVE_FILE_ID;"; + auto stmt = conn.createStmt(sql); + stmt.bindUint64(":ARCHIVE_FILE_ID", archiveFileId); + stmt.executeNonQuery(); + } + const auto deleteFromArchiveFileTime = t.secs(utils::Timer::resetCounter); + + conn.commit(); + const auto commitTime = t.secs(); + + log::ScopedParamContainer spc(lc); + spc.add("fileId", std::to_string(archiveFile->archiveFileID)) + .add("diskInstance", archiveFile->diskInstance) + .add("diskFileId", archiveFile->diskFileId) + .add("diskFileInfo.owner_uid", archiveFile->diskFileInfo.owner_uid) + .add("diskFileInfo.gid", archiveFile->diskFileInfo.gid) + .add("fileSize", std::to_string(archiveFile->fileSize)) + .add("creationTime", std::to_string(archiveFile->creationTime)) + .add("reconciliationTime", std::to_string(archiveFile->reconciliationTime)) + .add("storageClass", archiveFile->storageClass) + .add("getConnTime", getConnTime) + .add("getArchiveFileTime", getArchiveFileTime) + .add("deleteFromTapeFileTime", deleteFromTapeFileTime) + .add("deleteFromArchiveFileTime", deleteFromArchiveFileTime) + .add("setTapeDirtyTime",setTapeDirtyTime) + .add("commitTime", commitTime); + archiveFile->checksumBlob.addFirstChecksumToLog(spc); + for(auto it=archiveFile->tapeFiles.begin(); it!=archiveFile->tapeFiles.end(); it++) { + std::stringstream tapeCopyLogStream; + tapeCopyLogStream << "copy number: " << it->copyNb + << " vid: " << it->vid + << " fSeq: " << it->fSeq + << " blockId: " << it->blockId + << " creationTime: " << it->creationTime + << " fileSize: " << it->fileSize + << " checksumBlob: " << it->checksumBlob //this shouldn't be here: repeated field + << " copyNb: " << static_cast<int>(it->copyNb); //this shouldn't be here: repeated field + spc.add("TAPE FILE", tapeCopyLogStream.str()); + } + lc.log(log::INFO, "Archive file deleted from CTA catalogue"); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t SqliteArchiveFileCatalogue::getNextArchiveFileId(rdbms::Conn &conn) { + try { + conn.executeNonQuery("INSERT INTO ARCHIVE_FILE_ID VALUES(NULL)"); + uint64_t archiveFileId = 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 + "\'"); + } + archiveFileId = 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 ARCHIVE_FILE_ID"); + + return archiveFileId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +//------------------------------------------------------------------------------ +// copyArchiveFileToRecycleBinAndDelete +//------------------------------------------------------------------------------ +void SqliteArchiveFileCatalogue::copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) { + try { + utils::Timer t; + log::TimingList tl; + //We currently do an INSERT INTO and a DELETE FROM + //in a single transaction + conn.executeNonQuery("BEGIN TRANSACTION"); + const auto fileRecycleLog = static_cast<RdbmsFileRecycleLogCatalogue*>(m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLog->copyArchiveFileToFileRecycleLog(conn,request); + tl.insertAndReset("insertToRecycleBinTime",t); + RdbmsCatalogueUtils::setTapeDirty(conn,request.archiveFileID); + tl.insertAndReset("setTapeDirtyTime",t); + const auto tapeFileCatalogue = static_cast<RdbmsTapeFileCatalogue*>(m_rdbmsCatalogue->TapeFile().get()); + tapeFileCatalogue->deleteTapeFiles(conn,request); + tl.insertAndReset("deleteTapeFilesTime",t); + deleteArchiveFile(conn,request); + tl.insertAndReset("deleteArchiveFileTime",t); + conn.commit(); + tl.insertAndReset("commitTime",t); + log::ScopedParamContainer spc(lc); + spc.add("archiveFileId",request.archiveFileID); + spc.add("diskFileId",request.diskFileId); + spc.add("diskFilePath",request.diskFilePath); + spc.add("diskInstance",request.diskInstance); + tl.addToLog(spc); + lc.log(log::INFO,"In SqliteCatalogue::copyArchiveFileToRecycleBinAndDelete: ArchiveFile moved to the recycle-bin."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp new file mode 100644 index 0000000000..392afa0eff --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp @@ -0,0 +1,47 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteArchiveFileCatalogue : public RdbmsArchiveFileCatalogue { +public: + SqliteArchiveFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteArchiveFileCatalogue() override = default; + + void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, + log::LogContext &lc) override; + +private: + uint64_t getNextArchiveFileId(rdbms::Conn &conn) override; + + void copyArchiveFileToFileRecyleLogAndDelete(rdbms::Conn & conn, + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) override; +}; // class SqliteArchiveFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteCatalogue.cpp new file mode 100644 index 0000000000..677737d058 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteCatalogue.cpp @@ -0,0 +1,86 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/Login.hpp" + +namespace cta { +namespace catalogue { + +//------------------------------------------------------------------------------ +// constructor +//------------------------------------------------------------------------------ +SqliteCatalogue::SqliteCatalogue( + log::Logger &log, + const std::string &filename, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns): + RdbmsCatalogue( + log, + rdbms::Login(rdbms::Login::DBTYPE_SQLITE, "", "", filename, "", 0), + nbConns, + nbArchiveFileListingConns) { + RdbmsCatalogue::m_fileRecycleLog = std::make_unique<SqliteFileRecycleLogCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_storageClass = std::make_unique<SqliteStorageClassCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapePool = std::make_unique<SqliteTapePoolCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_vo = std::make_unique<SqliteVirtualOrganizationCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_mediaType = std::make_unique<SqliteMediaTypeCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_logicalLibrary = std::make_unique<SqliteLogicalLibraryCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tape = std::make_unique<SqliteTapeCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_archiveFile = std::make_unique<SqliteArchiveFileCatalogue>(m_log, m_connPool, this); + RdbmsCatalogue::m_tapeFile = std::make_unique<SqliteTapeFileCatalogue>(m_log, m_connPool, this); +} + +//------------------------------------------------------------------------------ +// createAndPopulateTempTableFxid +//------------------------------------------------------------------------------ +std::string SqliteCatalogue::createAndPopulateTempTableFxid(rdbms::Conn &conn, const std::optional<std::vector<std::string>> &diskFileIds) const { + try { + const std::string tempTableName = "TEMP.DISK_FXIDS"; + + // Drop any prexisting temporary table and create a new one + conn.executeNonQuery("DROP TABLE IF EXISTS " + tempTableName); + conn.executeNonQuery("CREATE TEMPORARY TABLE " + tempTableName + "(DISK_FILE_ID TEXT)"); + + if(diskFileIds) { + auto stmt = conn.createStmt("INSERT INTO " + tempTableName + " VALUES(:DISK_FILE_ID)"); + for(auto &diskFileId : diskFileIds.value()) { + stmt.bindString(":DISK_FILE_ID", diskFileId); + stmt.executeNonQuery(); + } + } + + return tempTableName; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteCatalogue.hpp new file mode 100644 index 0000000000..86e1574c11 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteCatalogue.hpp @@ -0,0 +1,68 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/rdbms/RdbmsCatalogue.hpp" + +namespace cta { +namespace catalogue { + +/** + * An SQLite implementation of the CTA catalogue. + */ +class SqliteCatalogue: public RdbmsCatalogue { +public: + + /** + * Constructor. + * + * @param log Object representing the API to the CTA logging system. + * @param filename The filename to be passed to the sqlite3_open() function. + * @param nbConns The maximum number of concurrent connections to the + * underlying relational database for all operations accept listing archive + * files which can be relatively long operations. + * @param nbArchiveFileListingConns The maximum number of concurrent + * connections to the underlying relational database for the sole purpose of + * listing archive files. + */ + SqliteCatalogue( + log::Logger &log, + const std::string &filename, + const uint64_t nbConns, + const uint64_t nbArchiveFileListingConns); + +public: + /** + * Destructor. + */ + ~SqliteCatalogue() override = default; + +protected: + /** + * Creates a temporary table from the list of disk file IDs provided in the search criteria. + * + * @param conn The database connection. + * @param diskFileIds List of disk file IDs (fxid). + * @return Name of the temporary table + */ + std::string createAndPopulateTempTableFxid(rdbms::Conn &conn, + const std::optional<std::vector<std::string>> &diskFileIds) const override; +}; // class SqliteCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.cpp new file mode 100644 index 0000000000..bbe1db3199 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.cpp @@ -0,0 +1,118 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/Conn.hpp" + +namespace cta { +namespace catalogue { + +SqliteFileRecycleLogCatalogue::SqliteFileRecycleLogCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue) + : RdbmsFileRecycleLogCatalogue(log, connPool, rdbmsCatalogue) {} + +void SqliteFileRecycleLogCatalogue::restoreEntryInRecycleLog(rdbms::Conn & conn, + FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, log::LogContext & lc) { + try { + utils::Timer timer; + log::TimingList timingList; + + if (!fileRecycleLogItor.hasMore()) { + throw cta::exception::UserError("No file in the recycle bin matches the parameters passed"); + } + auto fileRecycleLog = fileRecycleLogItor.next(); + if (fileRecycleLogItor.hasMore()) { + // stop restoring more than one file at once + throw cta::exception::UserError("More than one recycle bin file matches the parameters passed"); + } + + // We currently do all file copies restoring in a single transaction + conn.executeNonQuery("BEGIN TRANSACTION"); + const auto archiveFileCatalogue = static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + if (auto archiveFilePtr = archiveFileCatalogue->getArchiveFileById(conn, fileRecycleLog.archiveFileId); + !archiveFilePtr) { + RdbmsFileRecycleLogCatalogue::restoreArchiveFileInRecycleLog(conn, fileRecycleLog, newFid, lc); + } else { + if (archiveFilePtr->tapeFiles.find(fileRecycleLog.copyNb) != archiveFilePtr->tapeFiles.end()) { + // copy with same copy_nb exists, cannot restore + UserSpecifiedExistingDeletedFileCopy ex; + ex.getMessage() << "Cannot restore file copy with archiveFileId " + << std::to_string(fileRecycleLog.archiveFileId) + << " and copy_nb " << std::to_string(fileRecycleLog.copyNb) + << " because a tapefile with same archiveFileId and copy_nb already exists"; + throw ex; + } + } + + RdbmsFileRecycleLogCatalogue::restoreFileCopyInRecycleLog(conn, fileRecycleLog, lc); + conn.commit(); + + log::ScopedParamContainer spc(lc); + timingList.insertAndReset("commitTime", timer); + timingList.addToLog(spc); + lc.log(log::INFO, "In PostgresFileRecycleLogCatalogue::restoreEntryInRecycleLog: " + "all file copies successfully restored."); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +uint64_t SqliteFileRecycleLogCatalogue::getNextFileRecyleLogId(rdbms::Conn &conn) const { + try { + conn.executeNonQuery("INSERT INTO FILE_RECYCLE_LOG_ID VALUES(NULL)"); + uint64_t fileRecycleLogId = 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 + "\'"); + } + fileRecycleLogId = 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 FILE_RECYCLE_LOG_ID"); + + return fileRecycleLogId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp new file mode 100644 index 0000000000..772bf7f26e --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteFileRecycleLogCatalogue.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteFileRecycleLogCatalogue : public RdbmsFileRecycleLogCatalogue { +public: + SqliteFileRecycleLogCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + ~SqliteFileRecycleLogCatalogue() override = default; + +private: + + void restoreEntryInRecycleLog(rdbms::Conn & conn, FileRecycleLogItor &fileRecycleLogItor, const std::string &newFid, + log::LogContext & lc) override; + + /** + * Copy the fileRecycleLog to the TAPE_FILE table and deletes the corresponding FILE_RECYCLE_LOG table entry + * @param conn the database connection + * @param fileRecycleLog the fileRecycleLog we want to restore + * @param lc the log context + */ + void restoreFileCopyInRecycleLog(rdbms::Conn & conn, const common::dataStructures::FileRecycleLog &fileRecycleLog, + log::LogContext & lc); + + uint64_t getNextFileRecyleLogId(rdbms::Conn & conn) const override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.cpp new file mode 100644 index 0000000000..79fa62caf4 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.cpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteLogicalLibraryCatalogue::SqliteLogicalLibraryCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsLogicalLibraryCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteLogicalLibraryCatalogue::getNextLogicalLibraryId(rdbms::Conn &conn) const { + try { + conn.executeNonQuery("INSERT INTO LOGICAL_LIBRARY_ID VALUES(NULL)"); + uint64_t logicalLibraryId = 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 + "\'"); + } + logicalLibraryId = 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 LOGICAL_LIBRARY_ID"); + + return logicalLibraryId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp new file mode 100644 index 0000000000..e495fb5bd3 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteLogicalLibraryCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsLogicalLibraryCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteLogicalLibraryCatalogue : public RdbmsLogicalLibraryCatalogue { +public: + SqliteLogicalLibraryCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteLogicalLibraryCatalogue() override = default; + +private: + uint64_t getNextLogicalLibraryId(rdbms::Conn &conn) const override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.cpp new file mode 100644 index 0000000000..92979ce509 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.cpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteMediaTypeCatalogue::SqliteMediaTypeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsMediaTypeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteMediaTypeCatalogue::getNextMediaTypeId(rdbms::Conn &conn) const { + try { + conn.executeNonQuery("INSERT INTO MEDIA_TYPE_ID VALUES(NULL)"); + uint64_t id = 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 + "\'"); + } + id = 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 MEDIA_TYPE_ID"); + + return id; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp new file mode 100644 index 0000000000..360409d25a --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteMediaTypeCatalogue.hpp @@ -0,0 +1,39 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include "catalogue/rdbms/RdbmsMediaTypeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteMediaTypeCatalogue : public RdbmsMediaTypeCatalogue { +public: + SqliteMediaTypeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteMediaTypeCatalogue() override = default; + +private: + uint64_t getNextMediaTypeId(rdbms::Conn &conn) const override; +}; // class SqliteMediaTypeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.cpp new file mode 100644 index 0000000000..b9f68cd5e4 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.cpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteStorageClassCatalogue::SqliteStorageClassCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsStorageClassCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteStorageClassCatalogue::getNextStorageClassId(rdbms::Conn &conn) { + try { + conn.executeNonQuery("INSERT INTO STORAGE_CLASS_ID VALUES(NULL)"); + uint64_t storageClassId = 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 + "\'"); + } + storageClassId = 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 STORAGE_CLASS_ID"); + + return storageClassId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp new file mode 100644 index 0000000000..d653c24c0d --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteStorageClassCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsStorageClassCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteStorageClassCatalogue : public RdbmsStorageClassCatalogue { +public: + SqliteStorageClassCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteStorageClassCatalogue() override = default; + +private: + uint64_t getNextStorageClassId(rdbms::Conn &conn) override; +}; // class SqliteStorageClassCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteTapeCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteTapeCatalogue.cpp new file mode 100644 index 0000000000..86c5d9668c --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapeCatalogue.cpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteTapeCatalogue::SqliteTapeCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapeCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteTapeCatalogue::getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const { + try { + const char *const sql = + "SELECT " + "LAST_FSEQ AS LAST_FSEQ " + "FROM " + "TAPE " + "WHERE " + "VID = :VID;"; + + auto stmt = conn.createStmt(sql); + stmt.bindString(":VID", vid); + auto rset = stmt.executeQuery(); + if (!rset.next()) { + throw exception::Exception(std::string("The tape with VID " + vid + " does not exist")); + } + + return rset.columnUint64("LAST_FSEQ"); + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp new file mode 100644 index 0000000000..e426f9b70a --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp @@ -0,0 +1,42 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteTapeCatalogue : public RdbmsTapeCatalogue { +public: + SqliteTapeCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteTapeCatalogue() override = default; + +private: + friend class SqliteTapeFileCatalogue; + uint64_t getTapeLastFSeq(rdbms::Conn &conn, const std::string &vid) const override; +}; // class SqliteTapeCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.cpp new file mode 100644 index 0000000000..5f93b418eb --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.cpp @@ -0,0 +1,202 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <string> + +#include "catalogue/ArchiveFileRow.hpp" +#include "catalogue/ArchiveFileRowWithoutTimestamps.hpp" +#include "catalogue/rdbms/RdbmsArchiveFileCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/rdbms/RdbmsFileRecycleLogCatalogue.hpp" +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteTapeCatalogue.hpp" +#include "catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeItemWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/FileSizeMismatch.hpp" +#include "common/exception/TapeFseqMismatch.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/TimingList.hpp" +#include "common/Timer.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" +#include "rdbms/PrimaryKeyError.hpp" + +namespace cta { +namespace catalogue { + +SqliteTapeFileCatalogue::SqliteTapeFileCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue *rdbmsCatalogue) + : RdbmsTapeFileCatalogue(log, connPool, rdbmsCatalogue) {} + +void SqliteTapeFileCatalogue::copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const { + conn.executeNonQuery("BEGIN TRANSACTION"); + const auto fileRecycleLogCatalogue = static_cast<RdbmsFileRecycleLogCatalogue*>( + RdbmsTapeFileCatalogue::m_rdbmsCatalogue->FileRecycleLog().get()); + fileRecycleLogCatalogue->copyTapeFilesToFileRecycleLog(conn, file, reason); + timingList->insertAndReset("insertToRecycleBinTime", *timer); + RdbmsCatalogueUtils::setTapeDirty(conn, file.archiveFileID); + timingList->insertAndReset("setTapeDirtyTime", *timer); + deleteTapeFiles(conn, file); + timingList->insertAndReset("deleteTapeFilesTime", *timer); + conn.commit(); +} + +void SqliteTapeFileCatalogue::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &events) { + try { + if(events.empty()) { + return; + } + + auto firstEventItor = events.cbegin(); + const auto &firstEvent = **firstEventItor;; + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, firstEvent); + + // The SQLite implementation of this method relies on the fact that a tape + // cannot be physically mounted in two or more drives at the same time + // + // Given the above assumption regarding the laws of physics, a simple lock + // on the mutex of the SqliteCatalogue object is enough to emulate an + // Oracle SELECT FOR UPDATE + threading::MutexLocker locker(m_rdbmsCatalogue->m_mutex); + auto conn = m_connPool->getConn(); + + const uint64_t lastFSeq + = static_cast<SqliteTapeCatalogue*>(m_rdbmsCatalogue->Tape().get())->getTapeLastFSeq(conn, firstEvent.vid); + uint64_t expectedFSeq = lastFSeq + 1; + uint64_t totalLogicalBytesWritten = 0; + uint64_t filesCount = 0; + + for(const auto &eventP: events) { + const auto & event = *eventP; + checkTapeItemWrittenFieldsAreSet(__FUNCTION__, event); + + if(event.vid != firstEvent.vid) { + throw exception::Exception(std::string("VID mismatch: expected=") + firstEvent.vid + " actual=" + event.vid); + } + + if(expectedFSeq != event.fSeq) { + exception::TapeFseqMismatch ex; + ex.getMessage() << "FSeq mismatch for tape " << firstEvent.vid << ": expected=" << expectedFSeq << " actual=" << + firstEvent.fSeq; + throw ex; + } + expectedFSeq++; + + + try { + // If this is a file (as opposed to a placeholder), do the full processing. + const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(event); + totalLogicalBytesWritten += fileEvent.size; + filesCount++; + } catch (std::bad_cast&) {} + } + + auto lastEventItor = events.cend(); + lastEventItor--; + const TapeItemWritten &lastEvent = **lastEventItor; + RdbmsCatalogueUtils::updateTape(conn, lastEvent.vid, lastEvent.fSeq, totalLogicalBytesWritten, filesCount, + lastEvent.tapeDrive); + + for(const auto &event : events) { + try { + // If this is a file (as opposed to a placeholder), do the full processing. + const auto &fileEvent=dynamic_cast<const TapeFileWritten &>(*event); + fileWrittenToTape(conn, fileEvent); + } catch (std::bad_cast&) {} + } + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +void SqliteTapeFileCatalogue::fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event) { + try { + checkTapeFileWrittenFieldsAreSet(__FUNCTION__, event); + + // Try to insert a row into the ARCHIVE_FILE table - it is normal this will + // fail if another tape copy has already been written to tape + try { + ArchiveFileRowWithoutTimestamps row; + row.archiveFileId = event.archiveFileId; + row.diskFileId = event.diskFileId; + row.diskInstance = event.diskInstance; + row.size = event.size; + row.checksumBlob = event.checksumBlob; + row.storageClassName = event.storageClassName; + row.diskFileOwnerUid = event.diskFileOwnerUid; + row.diskFileGid = event.diskFileGid; + static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get())->insertArchiveFile(conn, row); + } catch(rdbms::PrimaryKeyError &) { + // Ignore this error + } catch(...) { + throw; + } + + const time_t now = time(nullptr); + const auto archiveFileCatalogue = static_cast<RdbmsArchiveFileCatalogue*>(m_rdbmsCatalogue->ArchiveFile().get()); + const auto archiveFileRow = archiveFileCatalogue->getArchiveFileRowById(conn, event.archiveFileId); + + if(nullptr == archiveFileRow) { + // This should never happen + exception::Exception ex; + ex.getMessage() << "Failed to find archive file row: archiveFileId=" << event.archiveFileId; + throw ex; + } + + std::ostringstream fileContext; + fileContext << "archiveFileId=" << event.archiveFileId << ", diskInstanceName=" << event.diskInstance << + ", diskFileId=" << event.diskFileId; + + if(archiveFileRow->size != event.size) { + catalogue::FileSizeMismatch ex; + ex.getMessage() << "File size mismatch: expected=" << archiveFileRow->size << ", actual=" << event.size << ": " + << fileContext.str(); + throw ex; + } + + archiveFileRow->checksumBlob.validate(event.checksumBlob); + + // Insert the tape file + common::dataStructures::TapeFile tapeFile; + tapeFile.vid = event.vid; + tapeFile.fSeq = event.fSeq; + tapeFile.blockId = event.blockId; + tapeFile.fileSize = event.size; + tapeFile.copyNb = event.copyNb; + tapeFile.creationTime = now; + insertTapeFile(conn, tapeFile, event.archiveFileId); + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp new file mode 100644 index 0000000000..2ae92a01dd --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapeFileCatalogue.hpp @@ -0,0 +1,55 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapeFileCatalogue.hpp" + +namespace cta { + +namespace utils { +class Timer; +} + +namespace log { +class TimingList; +} + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteTapeFileCatalogue : public RdbmsTapeFileCatalogue { +public: + SqliteTapeFileCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue *rdbmsCatalogue); + ~SqliteTapeFileCatalogue() override = default; + + void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) override; + +private: + void copyTapeFileToFileRecyleLogAndDeleteTransaction(rdbms::Conn & conn, + const cta::common::dataStructures::ArchiveFile &file, const std::string &reason, utils::Timer *timer, + log::TimingList *timingList, log::LogContext & lc) const override; + + void fileWrittenToTape(rdbms::Conn &conn, const TapeFileWritten &event); +}; // class SqliteTapeFileCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.cpp new file mode 100644 index 0000000000..a4b27104ff --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.cpp @@ -0,0 +1,60 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteTapePoolCatalogue::SqliteTapePoolCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsTapePoolCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteTapePoolCatalogue::getNextTapePoolId(rdbms::Conn &conn) const { + 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; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp new file mode 100644 index 0000000000..5536d31527 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteTapePoolCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsTapePoolCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteTapePoolCatalogue : public RdbmsTapePoolCatalogue { +public: + SqliteTapePoolCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteTapePoolCatalogue() override = default; + +private: + uint64_t getNextTapePoolId(rdbms::Conn &conn) const override; +}; // class SqliteTapePoolCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.cpp b/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.cpp new file mode 100644 index 0000000000..7d7b7b1a84 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.cpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "rdbms/Conn.hpp" +#include "rdbms/ConnPool.hpp" + +namespace cta { +namespace catalogue { + +SqliteVirtualOrganizationCatalogue::SqliteVirtualOrganizationCatalogue(log::Logger &log, + std::shared_ptr<rdbms::ConnPool> connPool, RdbmsCatalogue* rdbmsCatalogue) + : RdbmsVirtualOrganizationCatalogue(log, connPool, rdbmsCatalogue) {} + +uint64_t SqliteVirtualOrganizationCatalogue::getNextVirtualOrganizationId(rdbms::Conn &conn) { + try { + conn.executeNonQuery("INSERT INTO VIRTUAL_ORGANIZATION_ID VALUES(NULL)"); + uint64_t virtualOrganizationId = 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 + "\'"); + } + virtualOrganizationId = 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 VIRTUAL_ORGANIZATION_ID"); + + return virtualOrganizationId; + } catch(exception::UserError &) { + throw; + } catch(exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + ": " + ex.getMessage().str()); + throw; + } +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp b/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp new file mode 100644 index 0000000000..d5d21cf3a6 --- /dev/null +++ b/catalogue/rdbms/sqlite/SqliteVirtualOrganizationCatalogue.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <string> + +#include "catalogue/rdbms/RdbmsVirtualOrganizationCatalogue.hpp" + +namespace cta { + +namespace catalogue { + +class RdbmsCatalogue; + +class SqliteVirtualOrganizationCatalogue : public RdbmsVirtualOrganizationCatalogue { +public: + SqliteVirtualOrganizationCatalogue(log::Logger &log, std::shared_ptr<rdbms::ConnPool> connPool, + RdbmsCatalogue* rdbmsCatalogue); + ~SqliteVirtualOrganizationCatalogue() override = default; + +private: + uint64_t getNextVirtualOrganizationId(rdbms::Conn &conn) override; +}; // class SqliteFileRecycleLogCatalogue + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..bb9ce62f4f --- /dev/null +++ b/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.cpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/AdminUser.hpp" + +namespace cta { +namespace catalogue { + +AdminUserCatalogueRetryWrapper::AdminUserCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void AdminUserCatalogueRetryWrapper::createAdminUser(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->AdminUser()->createAdminUser(admin, username, comment);}, + m_maxTriesToConnect); +} + +void AdminUserCatalogueRetryWrapper::deleteAdminUser(const std::string &username) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->AdminUser()->deleteAdminUser(username);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::AdminUser> AdminUserCatalogueRetryWrapper::getAdminUsers() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->AdminUser()->getAdminUsers();}, m_maxTriesToConnect); +} + +void AdminUserCatalogueRetryWrapper::modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->AdminUser()->modifyAdminUserComment(admin, username, + comment);}, + m_maxTriesToConnect); +} + +bool AdminUserCatalogueRetryWrapper::isAdmin(const common::dataStructures::SecurityIdentity &identity) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->AdminUser()->isAdmin(identity);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..796dd818de --- /dev/null +++ b/catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp @@ -0,0 +1,59 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/AdminUserCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class AdminUserCatalogueRetryWrapper : public AdminUserCatalogue { +public: + AdminUserCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~AdminUserCatalogueRetryWrapper() override = default; + + void createAdminUser(const common::dataStructures::SecurityIdentity &admin, const std::string &username, + const std::string &comment) override; + + void deleteAdminUser(const std::string &username) override; + + std::list<common::dataStructures::AdminUser> getAdminUsers() const override; + + void modifyAdminUserComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &username, const std::string &comment) override; + + bool isAdmin(const common::dataStructures::SecurityIdentity &identity) const override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..9f8c7c3cd3 --- /dev/null +++ b/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.cpp @@ -0,0 +1,127 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" + +namespace cta { +namespace catalogue { + +ArchiveFileCatalogueRetryWrapper::ArchiveFileCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +uint64_t ArchiveFileCatalogueRetryWrapper::checkAndGetNextArchiveFileId(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, storageClassName, user); + }, m_maxTriesToConnect); +} + +common::dataStructures::ArchiveFileQueueCriteria ArchiveFileCatalogueRetryWrapper::getArchiveFileQueueCriteria( + const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getArchiveFileQueueCriteria(diskInstanceName, storageClassName, user); + }, m_maxTriesToConnect); +} + +ArchiveFileItor ArchiveFileCatalogueRetryWrapper::getArchiveFilesItor( + const TapeFileSearchCriteria &searchCriteria) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + }, m_maxTriesToConnect); +} + +common::dataStructures::ArchiveFile ArchiveFileCatalogueRetryWrapper::getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getArchiveFileForDeletion(searchCriteria); + }, m_maxTriesToConnect); +} + +std::list<common::dataStructures::ArchiveFile> ArchiveFileCatalogueRetryWrapper::getFilesForRepack( + const std::string &vid, const uint64_t startFSeq, const uint64_t maxNbFiles) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFSeq, maxNbFiles); + }, m_maxTriesToConnect); +} + +ArchiveFileItor ArchiveFileCatalogueRetryWrapper::getArchiveFilesForRepackItor(const std::string &vid, + const uint64_t startFSeq) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getArchiveFilesForRepackItor(vid, startFSeq); + }, m_maxTriesToConnect); +} + +common::dataStructures::ArchiveFileSummary ArchiveFileCatalogueRetryWrapper::getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + }, m_maxTriesToConnect); +} + +common::dataStructures::ArchiveFile ArchiveFileCatalogueRetryWrapper::getArchiveFileById(const uint64_t id) const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->getArchiveFileById(id); + }, m_maxTriesToConnect); +} + +void ArchiveFileCatalogueRetryWrapper::modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string& newStorageClassName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveFile()->modifyArchiveFileStorageClassId( + archiveFileId, newStorageClassName);}, m_maxTriesToConnect); +} + +void ArchiveFileCatalogueRetryWrapper::modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, + const std::string& fxId, const std::string &diskInstance) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveFile()->modifyArchiveFileFxIdAndDiskInstance( + archiveId, fxId, diskInstance);}, m_maxTriesToConnect); +} + +void ArchiveFileCatalogueRetryWrapper::DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, + const uint64_t archiveFileId, log::LogContext &lc) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(diskInstanceName, archiveFileId, lc); + }, m_maxTriesToConnect); +} + +void ArchiveFileCatalogueRetryWrapper::updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->updateDiskFileId(archiveFileId, diskInstance, diskFileId); + }, m_maxTriesToConnect); +} + +void ArchiveFileCatalogueRetryWrapper::moveArchiveFileToRecycleLog( + const common::dataStructures::DeleteArchiveRequest &request, log::LogContext & lc) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(request, lc); + }, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..ac830e5d6c --- /dev/null +++ b/catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp @@ -0,0 +1,84 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/ArchiveFileCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class ArchiveFileCatalogueRetryWrapper : public ArchiveFileCatalogue { +public: + ArchiveFileCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~ArchiveFileCatalogueRetryWrapper() override = default; + + uint64_t checkAndGetNextArchiveFileId(const std::string &diskInstanceName, const std::string &storageClassName, + const common::dataStructures::RequesterIdentity &user) override; + + common::dataStructures::ArchiveFileQueueCriteria getArchiveFileQueueCriteria(const std::string &diskInstanceName, + const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user) override; + + ArchiveFileItor getArchiveFilesItor( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileForDeletion( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, + const uint64_t maxNbFiles) const override; + + ArchiveFileItor getArchiveFilesForRepackItor(const std::string &vid, const uint64_t startFSeq) const override; + + common::dataStructures::ArchiveFileSummary getTapeFileSummary( + const TapeFileSearchCriteria &searchCriteria = TapeFileSearchCriteria()) const override; + + common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override; + + void modifyArchiveFileStorageClassId(const uint64_t archiveFileId, + const std::string& newStorageClassName) const override; + + void modifyArchiveFileFxIdAndDiskInstance(const uint64_t archiveId, const std::string& fxId, + const std::string &diskInstance) const override; + + void moveArchiveFileToRecycleLog(const common::dataStructures::DeleteArchiveRequest &request, + log::LogContext & lc) override; + + void updateDiskFileId(uint64_t archiveFileId, const std::string &diskInstance, + const std::string &diskFileId) override; + + void DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(const std::string &diskInstanceName, const uint64_t archiveFileId, + log::LogContext &lc) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..6c21cffef6 --- /dev/null +++ b/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.cpp @@ -0,0 +1,70 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" + +namespace cta { +namespace catalogue { + +ArchiveRouteCatalogueRetryWrapper::ArchiveRouteCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void ArchiveRouteCatalogueRetryWrapper::createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName, + const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->createArchiveRoute(admin, + storageClassName, copyNb, tapePoolName, comment);}, m_maxTriesToConnect); +} + +void ArchiveRouteCatalogueRetryWrapper::deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->deleteArchiveRoute(storageClassName, + copyNb);}, m_maxTriesToConnect); +} + +std::list<common::dataStructures::ArchiveRoute> ArchiveRouteCatalogueRetryWrapper::getArchiveRoutes() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->getArchiveRoutes();}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::ArchiveRoute> ArchiveRouteCatalogueRetryWrapper::getArchiveRoutes( + const std::string &storageClassName, const std::string &tapePoolName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->getArchiveRoutes(storageClassName, + tapePoolName);}, m_maxTriesToConnect); +} + +void ArchiveRouteCatalogueRetryWrapper::modifyArchiveRouteTapePoolName( + const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, const uint32_t copyNb, + const std::string &tapePoolName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->modifyArchiveRouteTapePoolName(admin, + storageClassName, copyNb, tapePoolName);}, m_maxTriesToConnect); +} + +void ArchiveRouteCatalogueRetryWrapper::modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->ArchiveRoute()->modifyArchiveRouteComment(admin, + storageClassName, copyNb, comment);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..70ce4a8ca4 --- /dev/null +++ b/catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp @@ -0,0 +1,63 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/ArchiveRouteCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class ArchiveRouteCatalogueRetryWrapper : public ArchiveRouteCatalogue { +public: + ArchiveRouteCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~ArchiveRouteCatalogueRetryWrapper() override = default; + + void createArchiveRoute(const common::dataStructures::SecurityIdentity &admin, const std::string &storageClassName, + const uint32_t copyNb, const std::string &tapePoolName, const std::string &comment) override; + + void deleteArchiveRoute(const std::string &storageClassName, const uint32_t copyNb) override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes() const override; + + std::list<common::dataStructures::ArchiveRoute> getArchiveRoutes(const std::string &storageClassName, + const std::string &tapePoolName) const override; + + void modifyArchiveRouteTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &tapePoolName) override; + + void modifyArchiveRouteComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &storageClassName, const uint32_t copyNb, const std::string &comment) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/CatalogueRetryWrapper.cpp b/catalogue/retrywrappers/CatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..e7f9a7473e --- /dev/null +++ b/catalogue/retrywrappers/CatalogueRetryWrapper.cpp @@ -0,0 +1,163 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/retrywrappers/AdminUserCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/ArchiveFileCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/ArchiveRouteCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/CatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp" + +namespace cta { + +namespace catalogue { + +CatalogueRetryWrapper::CatalogueRetryWrapper(log::Logger &log, std::unique_ptr<Catalogue> catalogue, + const uint32_t maxTriesToConnect): + m_log(log), + m_catalogue(std::move(catalogue)), + m_maxTriesToConnect(maxTriesToConnect), + m_schema(std::make_unique<SchemaCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_adminUser(std::make_unique<AdminUserCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_diskSystem(std::make_unique<DiskSystemCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_diskInstance(std::make_unique<DiskInstanceCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_diskInstanceSpace(std::make_unique<DiskInstanceSpaceCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_vo(std::make_unique<VirtualOrganizationCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_archiveRoute(std::make_unique<ArchiveRouteCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_mediaType(std::make_unique<MediaTypeCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_storageClass(std::make_unique<StorageClassCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_tapePool(std::make_unique<TapePoolCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_tape(std::make_unique<TapeCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_mountPolicy(std::make_unique<MountPolicyCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_requesterActivityMountRule(std::make_unique<RequesterActivityMountRuleCatalogueRetryWrapper>(m_catalogue, m_log, + m_maxTriesToConnect)), + m_requesterMountRule(std::make_unique<RequesterMountRuleCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_requesterGroupMountRule(std::make_unique<RequesterGroupMountRuleCatalogueRetryWrapper>(m_catalogue, m_log, + m_maxTriesToConnect)), + m_logicalLibrary(std::make_unique<LogicalLibraryCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_tapeFile(std::make_unique<TapeFileCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_fileRecycleLog(std::make_unique<FileRecycleLogCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_driveConfig(std::make_unique<DriveConfigCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_driveState(std::make_unique<DriveStateCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)), + m_archiveFile(std::make_unique<ArchiveFileCatalogueRetryWrapper>(m_catalogue, m_log, m_maxTriesToConnect)) { +} + +const std::unique_ptr<SchemaCatalogue>& CatalogueRetryWrapper::Schema() { + return m_schema; +} + +const std::unique_ptr<AdminUserCatalogue>& CatalogueRetryWrapper::AdminUser() { + return m_adminUser; +} + +const std::unique_ptr<DiskSystemCatalogue>& CatalogueRetryWrapper::DiskSystem() { + return m_diskSystem; +} + +const std::unique_ptr<DiskInstanceCatalogue>& CatalogueRetryWrapper::DiskInstance() { + return m_diskInstance; +} + +const std::unique_ptr<DiskInstanceSpaceCatalogue>& CatalogueRetryWrapper::DiskInstanceSpace() { + return m_diskInstanceSpace; +} + +const std::unique_ptr<VirtualOrganizationCatalogue>& CatalogueRetryWrapper::VO() { + return m_vo; +} + +const std::unique_ptr<ArchiveRouteCatalogue>& CatalogueRetryWrapper::ArchiveRoute() { + return m_archiveRoute; +} + +const std::unique_ptr<MediaTypeCatalogue>& CatalogueRetryWrapper::MediaType() { + return m_mediaType; +} + +const std::unique_ptr<StorageClassCatalogue>& CatalogueRetryWrapper::StorageClass() { + return m_storageClass; +} + +const std::unique_ptr<TapePoolCatalogue>& CatalogueRetryWrapper::TapePool() { + return m_tapePool; +} + +const std::unique_ptr<TapeCatalogue>& CatalogueRetryWrapper::Tape() { + return m_tape; +} + +const std::unique_ptr<MountPolicyCatalogue>& CatalogueRetryWrapper::MountPolicy() { + return m_mountPolicy; +} + +const std::unique_ptr<RequesterActivityMountRuleCatalogue>& CatalogueRetryWrapper::RequesterActivityMountRule() { + return m_requesterActivityMountRule; +} + +const std::unique_ptr<RequesterMountRuleCatalogue>& CatalogueRetryWrapper::RequesterMountRule() { + return m_requesterMountRule; +} + +const std::unique_ptr<RequesterGroupMountRuleCatalogue>& CatalogueRetryWrapper::RequesterGroupMountRule() { + return m_requesterGroupMountRule; +} + +const std::unique_ptr<LogicalLibraryCatalogue>& CatalogueRetryWrapper::LogicalLibrary() { + return m_logicalLibrary; +} + +const std::unique_ptr<TapeFileCatalogue>& CatalogueRetryWrapper::TapeFile() { + return m_tapeFile; +} + +const std::unique_ptr<FileRecycleLogCatalogue>& CatalogueRetryWrapper::FileRecycleLog() { + return m_fileRecycleLog; +} + +const std::unique_ptr<DriveConfigCatalogue>& CatalogueRetryWrapper::DriveConfig() { + return m_driveConfig; +} + +const std::unique_ptr<ArchiveFileCatalogue>& CatalogueRetryWrapper::ArchiveFile() { + return m_archiveFile; +} + +const std::unique_ptr<DriveStateCatalogue>& CatalogueRetryWrapper::DriveState() { + return m_driveState; +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/CatalogueRetryWrapper.hpp b/catalogue/retrywrappers/CatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..29b6973171 --- /dev/null +++ b/catalogue/retrywrappers/CatalogueRetryWrapper.hpp @@ -0,0 +1,116 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { + +namespace catalogue { + +/** + * Wrapper around a CTA catalogue object that retries a method if a + * LostConnectionException is thrown. + */ +class CatalogueRetryWrapper: public Catalogue { +public: + /** + * Constructor. + * + * @param log Object representing the API to the CTA logging system. + * @param catalogue The catalogue to be wrapped. + * @param maxTriesToConnect The maximum number of times a single method should + * try to connect to the database in the event of LostDatabaseConnection + * exceptions being thrown. + */ + CatalogueRetryWrapper(log::Logger &log, std::unique_ptr<Catalogue> catalogue, const uint32_t maxTriesToConnect = 3); + + CatalogueRetryWrapper(CatalogueRetryWrapper &) = delete; + + ~CatalogueRetryWrapper() override = default; + + CatalogueRetryWrapper &operator=(const CatalogueRetryWrapper &) = delete; + + const std::unique_ptr<SchemaCatalogue>& Schema() override; + const std::unique_ptr<AdminUserCatalogue>& AdminUser() override; + const std::unique_ptr<DiskSystemCatalogue>& DiskSystem() override; + const std::unique_ptr<DiskInstanceCatalogue>& DiskInstance() override; + const std::unique_ptr<DiskInstanceSpaceCatalogue>& DiskInstanceSpace() override; + const std::unique_ptr<VirtualOrganizationCatalogue>& VO() override; + const std::unique_ptr<ArchiveRouteCatalogue>& ArchiveRoute() override; + const std::unique_ptr<MediaTypeCatalogue>& MediaType() override; + const std::unique_ptr<StorageClassCatalogue>& StorageClass() override; + const std::unique_ptr<TapePoolCatalogue>& TapePool() override; + const std::unique_ptr<TapeCatalogue>& Tape() override; + const std::unique_ptr<MountPolicyCatalogue>& MountPolicy() override; + const std::unique_ptr<RequesterActivityMountRuleCatalogue>& RequesterActivityMountRule() override; + const std::unique_ptr<RequesterMountRuleCatalogue>& RequesterMountRule() override; + const std::unique_ptr<RequesterGroupMountRuleCatalogue>& RequesterGroupMountRule() override; + const std::unique_ptr<LogicalLibraryCatalogue>& LogicalLibrary() override; + const std::unique_ptr<DriveConfigCatalogue>& DriveConfig() override; + const std::unique_ptr<DriveStateCatalogue>& DriveState() override; + const std::unique_ptr<TapeFileCatalogue>& TapeFile() override; + const std::unique_ptr<FileRecycleLogCatalogue>& FileRecycleLog() override; + const std::unique_ptr<ArchiveFileCatalogue>& ArchiveFile() override; + +protected: + /** + * Object representing the API to the CTA logging system. + */ + log::Logger &m_log; + + /** + * The wrapped catalogue. + */ + std::unique_ptr<Catalogue> m_catalogue; + + /** + * The maximum number of times a single method should try to connect to the + * database in the event of LostDatabaseConnection exceptions being thrown. + */ + uint32_t m_maxTriesToConnect; + +private: + std::unique_ptr<SchemaCatalogue> m_schema; + std::unique_ptr<AdminUserCatalogue> m_adminUser; + std::unique_ptr<DiskSystemCatalogue> m_diskSystem; + std::unique_ptr<DiskInstanceCatalogue> m_diskInstance; + std::unique_ptr<DiskInstanceSpaceCatalogue> m_diskInstanceSpace; + std::unique_ptr<VirtualOrganizationCatalogue> m_vo; + std::unique_ptr<ArchiveRouteCatalogue> m_archiveRoute; + std::unique_ptr<MediaTypeCatalogue> m_mediaType; + std::unique_ptr<StorageClassCatalogue> m_storageClass; + std::unique_ptr<TapePoolCatalogue> m_tapePool; + std::unique_ptr<TapeCatalogue> m_tape; + std::unique_ptr<MountPolicyCatalogue> m_mountPolicy; + std::unique_ptr<RequesterActivityMountRuleCatalogue> m_requesterActivityMountRule; + std::unique_ptr<RequesterMountRuleCatalogue> m_requesterMountRule; + std::unique_ptr<RequesterGroupMountRuleCatalogue> m_requesterGroupMountRule; + std::unique_ptr<LogicalLibraryCatalogue> m_logicalLibrary; + std::unique_ptr<TapeFileCatalogue> m_tapeFile; + std::unique_ptr<FileRecycleLogCatalogue> m_fileRecycleLog; + std::unique_ptr<DriveConfigCatalogue> m_driveConfig; + std::unique_ptr<DriveStateCatalogue> m_driveState; + std::unique_ptr<ArchiveFileCatalogue> m_archiveFile; +}; // class CatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..6c68450833 --- /dev/null +++ b/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.cpp @@ -0,0 +1,61 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +DiskInstanceCatalogueRetryWrapper::DiskInstanceCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void DiskInstanceCatalogueRetryWrapper::createDiskInstance(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->DiskInstance()->createDiskInstance(admin, name, comment); + }, m_maxTriesToConnect); +} + +void DiskInstanceCatalogueRetryWrapper::deleteDiskInstance(const std::string &name) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->DiskInstance()->deleteDiskInstance(name); + }, m_maxTriesToConnect); +} + +void DiskInstanceCatalogueRetryWrapper::modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->DiskInstance()->modifyDiskInstanceComment(admin, name, comment); + }, m_maxTriesToConnect); +} + +std::list<common::dataStructures::DiskInstance> DiskInstanceCatalogueRetryWrapper::getAllDiskInstances() const { + return retryOnLostConnection(m_log, [&]{ + return m_catalogue->DiskInstance()->getAllDiskInstances(); + }, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..fdb254267b --- /dev/null +++ b/catalogue/retrywrappers/DiskInstanceCatalogueRetryWrapper.hpp @@ -0,0 +1,57 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/DiskInstanceCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class DiskInstanceCatalogueRetryWrapper : public DiskInstanceCatalogue { +public: + DiskInstanceCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~DiskInstanceCatalogueRetryWrapper() override = default; + + void createDiskInstance(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + void deleteDiskInstance(const std::string &name) override; + + void modifyDiskInstanceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + std::list<common::dataStructures::DiskInstance> getAllDiskInstances() const override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class DiskInstanceCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..b1d9cfe58b --- /dev/null +++ b/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.cpp @@ -0,0 +1,88 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/DiskInstanceSpace.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +DiskInstanceSpaceCatalogueRetryWrapper::DiskInstanceSpaceCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void DiskInstanceSpaceCatalogueRetryWrapper::deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->deleteDiskInstanceSpace(name, + diskInstance);}, + m_maxTriesToConnect); +} + +void DiskInstanceSpaceCatalogueRetryWrapper::createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstance, + const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, + const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(admin, name, + diskInstance, freeSpaceQueryURL, refreshInterval, comment);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::DiskInstanceSpace> DiskInstanceSpaceCatalogueRetryWrapper::getAllDiskInstanceSpaces() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces();}, + m_maxTriesToConnect); +} + +void DiskInstanceSpaceCatalogueRetryWrapper::modifyDiskInstanceSpaceComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceComment(admin, name, + diskInstance, comment);}, + m_maxTriesToConnect); +} + +void DiskInstanceSpaceCatalogueRetryWrapper::modifyDiskInstanceSpaceRefreshInterval( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const uint64_t refreshInterval) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceRefreshInterval(admin, name, + diskInstance, refreshInterval);}, + m_maxTriesToConnect); +} + +void DiskInstanceSpaceCatalogueRetryWrapper::modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceFreeSpace(name, + diskInstance, freeSpace);}, + m_maxTriesToConnect); +} + +void DiskInstanceSpaceCatalogueRetryWrapper::modifyDiskInstanceSpaceQueryURL( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstance, + const std::string &freeSpaceQueryURL) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceQueryURL(admin, name, + diskInstance, freeSpaceQueryURL);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..859c82eae3 --- /dev/null +++ b/catalogue/retrywrappers/DiskInstanceSpaceCatalogueRetryWrapper.hpp @@ -0,0 +1,70 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/DiskInstanceSpaceCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class DiskInstanceSpaceCatalogueRetryWrapper : public DiskInstanceSpaceCatalogue { +public: + DiskInstanceSpaceCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~DiskInstanceSpaceCatalogueRetryWrapper() override = default; + + void deleteDiskInstanceSpace(const std::string &name, const std::string &diskInstance) override; + + void createDiskInstanceSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, + const std::string &diskInstance, + const std::string &freeSpaceQueryURL, + const uint64_t refreshInterval, + const std::string &comment) override; + + std::list<common::dataStructures::DiskInstanceSpace> getAllDiskInstanceSpaces() const override; + + void modifyDiskInstanceSpaceComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &comment) override; + + void modifyDiskInstanceSpaceRefreshInterval(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const uint64_t refreshInterval) override; + + void modifyDiskInstanceSpaceFreeSpace(const std::string &name, + const std::string &diskInstance, const uint64_t freeSpace) override; + + void modifyDiskInstanceSpaceQueryURL(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstance, const std::string &freeSpaceQueryURL) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class DiskInstancSpaceCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..bca23dbf3f --- /dev/null +++ b/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.cpp @@ -0,0 +1,93 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/log/Logger.hpp" +#include "disk/DiskSystem.hpp" + +namespace cta { +namespace catalogue { + +DiskSystemCatalogueRetryWrapper::DiskSystemCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void DiskSystemCatalogueRetryWrapper::createDiskSystem(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, + const std::string &fileRegexp, const uint64_t targetedFreeSpace, const time_t sleepTime,const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->createDiskSystem(admin, name, + diskInstanceName, diskInstanceSpaceName, fileRegexp, targetedFreeSpace, sleepTime, comment);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::deleteDiskSystem(const std::string &name) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->deleteDiskSystem(name);}, + m_maxTriesToConnect); +} + +disk::DiskSystemList DiskSystemCatalogueRetryWrapper::getAllDiskSystems() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->getAllDiskSystems();}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemFileRegexp(admin, name, + fileRegexp);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemTargetedFreeSpace( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t targetedFreeSpace) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemTargetedFreeSpace(admin, + name, targetedFreeSpace);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemComment(admin, name, + comment);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemSleepTime(admin, name, + sleepTime);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemDiskInstanceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &diskInstanceName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemDiskInstanceName(admin, + name, diskInstanceName);}, m_maxTriesToConnect); +} + +void DiskSystemCatalogueRetryWrapper::modifyDiskSystemDiskInstanceSpaceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceSpaceName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->modifyDiskSystemDiskInstanceSpaceName(admin, + name, diskInstanceSpaceName);}, m_maxTriesToConnect); +} + +bool DiskSystemCatalogueRetryWrapper::diskSystemExists(const std::string &name) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DiskSystem()->diskSystemExists(name);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..3dbe05074b --- /dev/null +++ b/catalogue/retrywrappers/DiskSystemCatalogueRetryWrapper.hpp @@ -0,0 +1,75 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/DiskSystemCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class DiskSystemCatalogueRetryWrapper : public DiskSystemCatalogue { +public: + DiskSystemCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~DiskSystemCatalogueRetryWrapper() override = default; + + void createDiskSystem(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &diskInstanceName, const std::string &diskInstanceSpaceName, const std::string &fileRegexp, + const uint64_t targetedFreeSpace, const time_t sleepTime, const std::string &comment) override; + + void deleteDiskSystem(const std::string &name) override; + + disk::DiskSystemList getAllDiskSystems() const override; + + void modifyDiskSystemFileRegexp(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &fileRegexp) override; + + void modifyDiskSystemTargetedFreeSpace(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t targetedFreeSpace) override; + + void modifyDiskSystemComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyDiskSystemSleepTime(const common::dataStructures::SecurityIdentity& admin, + const std::string& name, const uint64_t sleepTime) override; + + void modifyDiskSystemDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceName) override; + + void modifyDiskSystemDiskInstanceSpaceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &diskInstanceSpaceName) override; + + bool diskSystemExists(const std::string &name) const override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class DiskSystemCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..3676d29a87 --- /dev/null +++ b/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.cpp @@ -0,0 +1,71 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +DriveConfigCatalogueRetryWrapper::DriveConfigCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void DriveConfigCatalogueRetryWrapper::createTapeDriveConfig(const std::string &driveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->createTapeDriveConfig(driveName, category, + keyName, value, source);}, + m_maxTriesToConnect); +} + +std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> DriveConfigCatalogueRetryWrapper::getTapeDriveConfigs() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->getTapeDriveConfigs();}, + m_maxTriesToConnect); +} + +std::list<std::pair<std::string, std::string>> DriveConfigCatalogueRetryWrapper::getTapeDriveConfigNamesAndKeys() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->getTapeDriveConfigNamesAndKeys();}, + m_maxTriesToConnect); +} + +void DriveConfigCatalogueRetryWrapper::modifyTapeDriveConfig(const std::string &driveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->modifyTapeDriveConfig(driveName, category, + keyName, value, source);}, + m_maxTriesToConnect); +} + +std::optional<std::tuple<std::string, std::string, std::string>> DriveConfigCatalogueRetryWrapper::getTapeDriveConfig( + const std::string &tapeDriveName, + const std::string &keyName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, keyName);}, + m_maxTriesToConnect); +} + +void DriveConfigCatalogueRetryWrapper::deleteTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, + keyName);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..185fdc1007 --- /dev/null +++ b/catalogue/retrywrappers/DriveConfigCatalogueRetryWrapper.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveConfigCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +class DriveConfigCatalogueRetryWrapper: public DriveConfigCatalogue { +public: + DriveConfigCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + + ~DriveConfigCatalogueRetryWrapper() override = default; + + void createTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::list<DriveConfig> getTapeDriveConfigs() const override; + + std::list<std::pair<std::string, std::string>> getTapeDriveConfigNamesAndKeys() const override; + + void modifyTapeDriveConfig(const std::string &tapeDriveName, const std::string &category, + const std::string &keyName, const std::string &value, const std::string &source) override; + + std::optional<std::tuple<std::string, std::string, std::string>> getTapeDriveConfig(const std::string &tapeDriveName, + const std::string &keyName) const override; + + void deleteTapeDriveConfig(const std::string &tapeDriveName, const std::string &keyName) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..127fa03b01 --- /dev/null +++ b/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.cpp @@ -0,0 +1,104 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +DriveStateCatalogueRetryWrapper::DriveStateCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void DriveStateCatalogueRetryWrapper::createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->createTapeDrive(tapeDrive);}, + m_maxTriesToConnect); +} + +std::list<std::string> DriveStateCatalogueRetryWrapper::getTapeDriveNames() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->getTapeDriveNames();}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::TapeDrive> DriveStateCatalogueRetryWrapper::getTapeDrives() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->getTapeDrives();}, m_maxTriesToConnect); +} + +std::optional<common::dataStructures::TapeDrive> DriveStateCatalogueRetryWrapper::getTapeDrive( + const std::string &tapeDriveName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->getTapeDrive(tapeDriveName);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->setDesiredTapeDriveState(tapeDriveName, + desiredState);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->setDesiredTapeDriveStateComment( + tapeDriveName, comment);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->updateTapeDriveStatistics(tapeDriveName, + host, logicalLibrary, statistics);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->updateTapeDriveStatus(tapeDrive);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::deleteTapeDrive(const std::string &tapeDriveName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->deleteTapeDrive(tapeDriveName);}, + m_maxTriesToConnect); +} + +std::map<std::string, uint64_t> DriveStateCatalogueRetryWrapper::getDiskSpaceReservations() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->getDiskSpaceReservations();}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->reserveDiskSpace(driveName, mountId, + diskSpaceReservation, lc);}, + m_maxTriesToConnect); +} + +void DriveStateCatalogueRetryWrapper::releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->DriveState()->releaseDiskSpace(driveName, mountId, + diskSpaceReservation, lc);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..5276de0084 --- /dev/null +++ b/catalogue/retrywrappers/DriveStateCatalogueRetryWrapper.hpp @@ -0,0 +1,78 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> +#include <memory> +#include <optional> +#include <string> +#include <tuple> +#include <utility> + +#include "catalogue/interfaces/DriveStateCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +class DriveStateCatalogueRetryWrapper: public DriveStateCatalogue { +public: + DriveStateCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + + ~DriveStateCatalogueRetryWrapper() override = default; + + void createTapeDrive(const common::dataStructures::TapeDrive &tapeDrive) override; + + std::list<std::string> getTapeDriveNames() const override; + + std::list<common::dataStructures::TapeDrive> getTapeDrives() const override; + + std::optional<common::dataStructures::TapeDrive> getTapeDrive(const std::string &tapeDriveName) const override; + + void setDesiredTapeDriveState(const std::string& tapeDriveName, + const common::dataStructures::DesiredDriveState &desiredState) override; + + void setDesiredTapeDriveStateComment(const std::string& tapeDriveName, + const std::string &comment) override; + + void updateTapeDriveStatistics(const std::string& tapeDriveName, + const std::string& host, const std::string& logicalLibrary, + const common::dataStructures::TapeDriveStatistics& statistics) override; + + void updateTapeDriveStatus(const common::dataStructures::TapeDrive &tapeDrive) override; + + void deleteTapeDrive(const std::string &tapeDriveName) override; + + std::map<std::string, uint64_t> getDiskSpaceReservations() const override; + + void reserveDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + + void releaseDiskSpace(const std::string& driveName, const uint64_t mountId, + const DiskSpaceReservationRequest& diskSpaceReservation, log::LogContext & lc) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..cf296cb4fd --- /dev/null +++ b/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.cpp @@ -0,0 +1,54 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/log/LogContext.hpp" + +namespace cta { +namespace catalogue { + +FileRecycleLogCatalogueRetryWrapper::FileRecycleLogCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect): + m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +FileRecycleLogItor FileRecycleLogCatalogueRetryWrapper::getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->FileRecycleLog()->getFileRecycleLogItor(searchCriteria);}, + m_maxTriesToConnect); +} + +void FileRecycleLogCatalogueRetryWrapper::restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, + newFid);}, + m_maxTriesToConnect); +} + +void FileRecycleLogCatalogueRetryWrapper::deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->FileRecycleLog()->deleteFilesFromRecycleLog(vid, lc);}, + m_maxTriesToConnect); +} + + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..f6d21f7fe0 --- /dev/null +++ b/catalogue/retrywrappers/FileRecycleLogCatalogueRetryWrapper.hpp @@ -0,0 +1,58 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <string> + +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/RecyleTapeFileSearchCriteria.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class FileRecycleLogCatalogueRetryWrapper: public FileRecycleLogCatalogue { +public: + FileRecycleLogCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + + ~FileRecycleLogCatalogueRetryWrapper() override = default; + + FileRecycleLogItor getFileRecycleLogItor( + const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const override; + + void restoreFileInRecycleLog(const RecycleTapeFileSearchCriteria & searchCriteria, + const std::string &newFid) override; + + void deleteFilesFromRecycleLog(const std::string& vid, log::LogContext& lc) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..6ea7b4833d --- /dev/null +++ b/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.cpp @@ -0,0 +1,75 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/LogicalLibrary.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" + +namespace cta { +namespace catalogue { + +LogicalLibraryCatalogueRetryWrapper::LogicalLibraryCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void LogicalLibraryCatalogueRetryWrapper::createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool isDisabled, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->createLogicalLibrary(admin, name, + isDisabled, comment);}, m_maxTriesToConnect); +} + +void LogicalLibraryCatalogueRetryWrapper::deleteLogicalLibrary(const std::string &name) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->deleteLogicalLibrary(name);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::LogicalLibrary> LogicalLibraryCatalogueRetryWrapper::getLogicalLibraries() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->getLogicalLibraries();}, + m_maxTriesToConnect); +} + +void LogicalLibraryCatalogueRetryWrapper::modifyLogicalLibraryName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, const std::string &newName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->modifyLogicalLibraryName(admin, + currentName, newName);}, m_maxTriesToConnect); +} + +void LogicalLibraryCatalogueRetryWrapper::modifyLogicalLibraryComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->modifyLogicalLibraryComment(admin, + name, comment);}, m_maxTriesToConnect); +} + +void LogicalLibraryCatalogueRetryWrapper::modifyLogicalLibraryDisabledReason( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const std::string &disabledReason) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->modifyLogicalLibraryDisabledReason( + admin, name, disabledReason);}, m_maxTriesToConnect); +} + +void LogicalLibraryCatalogueRetryWrapper::setLogicalLibraryDisabled( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const bool disabledValue) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->LogicalLibrary()->setLogicalLibraryDisabled(admin, + name, disabledValue);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..0f5f210a04 --- /dev/null +++ b/catalogue/retrywrappers/LogicalLibraryCatalogueRetryWrapper.hpp @@ -0,0 +1,75 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/interfaces/LogicalLibraryCatalogue.hpp" + +namespace cta { + +namespace common { +namespace dataStructures { +struct LogicalLibrary; +struct SecurityIdentity; +} +} + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class LogicalLibraryCatalogueRetryWrapper: public LogicalLibraryCatalogue { +public: + LogicalLibraryCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~LogicalLibraryCatalogueRetryWrapper() override = default; + + void createLogicalLibrary(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool isDisabled, const std::string &comment) override; + + void deleteLogicalLibrary(const std::string &name) override; + + std::list<common::dataStructures::LogicalLibrary> getLogicalLibraries() const override; + + void modifyLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; + + void modifyLogicalLibraryComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyLogicalLibraryDisabledReason(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &disabledReason) override; + + void setLogicalLibraryDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const bool disabledValue) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class LogicalLibraryCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..e579454f09 --- /dev/null +++ b/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.cpp @@ -0,0 +1,111 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +MediaTypeCatalogueRetryWrapper::MediaTypeCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void MediaTypeCatalogueRetryWrapper::createMediaType(const common::dataStructures::SecurityIdentity &admin, + const MediaType &mediaType) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->createMediaType(admin, mediaType);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::deleteMediaType(const std::string &name) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->deleteMediaType(name);}, + m_maxTriesToConnect); +} + +std::list<MediaTypeWithLogs> MediaTypeCatalogueRetryWrapper::getMediaTypes() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->getMediaTypes();}, + m_maxTriesToConnect); +} + +MediaType MediaTypeCatalogueRetryWrapper::getMediaTypeByVid(const std::string & vid) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->getMediaTypeByVid(vid);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeName(admin, currentName, newName);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &cartridge) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeCartridge(admin, name, cartridge);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeCapacityInBytes( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t capacityInBytes) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeCapacityInBytes(admin, name, capacityInBytes);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypePrimaryDensityCode( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t primaryDensityCode) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypePrimaryDensityCode(admin, name, primaryDensityCode);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeSecondaryDensityCode( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint8_t secondaryDensityCode) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeSecondaryDensityCode(admin, name, secondaryDensityCode);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint32_t> &nbWraps) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeNbWraps(admin, name, nbWraps);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &minLPos) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeMinLPos(admin, name, minLPos);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::optional<std::uint64_t> &maxLPos) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeMaxLPos(admin, name, maxLPos);}, + m_maxTriesToConnect); +} + +void MediaTypeCatalogueRetryWrapper::modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MediaType()->modifyMediaTypeComment(admin, name, comment);}, + m_maxTriesToConnect); +} +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..55899c00ff --- /dev/null +++ b/catalogue/retrywrappers/MediaTypeCatalogueRetryWrapper.hpp @@ -0,0 +1,82 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/MediaTypeCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class MediaTypeCatalogueRetryWrapper : public MediaTypeCatalogue { +public: + MediaTypeCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~MediaTypeCatalogueRetryWrapper() override = default; + + void createMediaType(const common::dataStructures::SecurityIdentity &admin, const MediaType &mediaType) override; + + void deleteMediaType(const std::string &name) override; + + std::list<MediaTypeWithLogs> getMediaTypes() const override; + + MediaType getMediaTypeByVid(const std::string & vid) const override; + + void modifyMediaTypeName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + void modifyMediaTypeCartridge(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &cartridge) override; + + void modifyMediaTypeCapacityInBytes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t capacityInBytes) override; + + void modifyMediaTypePrimaryDensityCode(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint8_t primaryDensityCode) override; + + void modifyMediaTypeSecondaryDensityCode(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint8_t secondaryDensityCode) override; + + void modifyMediaTypeNbWraps(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint32_t> &nbWraps) override; + + void modifyMediaTypeMinLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &minLPos) override; + + void modifyMediaTypeMaxLPos(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::optional<std::uint64_t> &maxLPos) override; + + void modifyMediaTypeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class MediaTypeCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..dd912b2c8a --- /dev/null +++ b/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.cpp @@ -0,0 +1,96 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" + +namespace cta { +namespace catalogue { + +MountPolicyCatalogueRetryWrapper::MountPolicyCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void MountPolicyCatalogueRetryWrapper::createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->createMountPolicy(admin, mountPolicy);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::MountPolicy> MountPolicyCatalogueRetryWrapper::getMountPolicies() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->getMountPolicies();}, + m_maxTriesToConnect); +} + +std::optional<common::dataStructures::MountPolicy> MountPolicyCatalogueRetryWrapper::getMountPolicy( + const std::string &mountPolicyName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->getMountPolicy(mountPolicyName);}, + m_maxTriesToConnect); +} + + +std::list<common::dataStructures::MountPolicy> MountPolicyCatalogueRetryWrapper::getCachedMountPolicies() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->getCachedMountPolicies();}, + m_maxTriesToConnect); +} + +void MountPolicyCatalogueRetryWrapper::deleteMountPolicy(const std::string &name) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->deleteMountPolicy(name);}, + m_maxTriesToConnect); +} + +void MountPolicyCatalogueRetryWrapper::modifyMountPolicyArchivePriority( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t archivePriority) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->modifyMountPolicyArchivePriority(admin, + name, archivePriority);}, m_maxTriesToConnect); +} + +void MountPolicyCatalogueRetryWrapper::modifyMountPolicyArchiveMinRequestAge( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t minArchiveRequestAge) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->modifyMountPolicyArchiveMinRequestAge( + admin, name, minArchiveRequestAge);}, m_maxTriesToConnect); +} + +void MountPolicyCatalogueRetryWrapper::modifyMountPolicyRetrievePriority( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t retrievePriority) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->modifyMountPolicyRetrievePriority(admin, + name, retrievePriority);}, m_maxTriesToConnect); +} +void MountPolicyCatalogueRetryWrapper::modifyMountPolicyRetrieveMinRequestAge( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t minRetrieveRequestAge) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->modifyMountPolicyRetrieveMinRequestAge( + admin, name, minRetrieveRequestAge);}, m_maxTriesToConnect); +} + +void MountPolicyCatalogueRetryWrapper::modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->MountPolicy()->modifyMountPolicyComment(admin, name, + comment);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..7ea8e6f36c --- /dev/null +++ b/catalogue/retrywrappers/MountPolicyCatalogueRetryWrapper.hpp @@ -0,0 +1,74 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/MountPolicyCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class MountPolicyCatalogueRetryWrapper : public MountPolicyCatalogue { +public: + MountPolicyCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~MountPolicyCatalogueRetryWrapper() override = default; + + void createMountPolicy(const common::dataStructures::SecurityIdentity &admin, + const CreateMountPolicyAttributes & mountPolicy) override; + + std::list<common::dataStructures::MountPolicy> getMountPolicies() const override; + + std::optional<common::dataStructures::MountPolicy> getMountPolicy( + const std::string &mountPolicyName) const override; + + std::list<common::dataStructures::MountPolicy> getCachedMountPolicies() const override; + + void deleteMountPolicy(const std::string &name) override; + + void modifyMountPolicyArchivePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t archivePriority) override; + + void modifyMountPolicyArchiveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minArchiveRequestAge) override; + + void modifyMountPolicyRetrievePriority(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t retrievePriority) override; + + void modifyMountPolicyRetrieveMinRequestAge(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t minRetrieveRequestAge) override; + + void modifyMountPolicyComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..2b7c14df40 --- /dev/null +++ b/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.cpp @@ -0,0 +1,79 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" + +namespace cta { +namespace catalogue { + +RequesterActivityMountRuleCatalogueRetryWrapper::RequesterActivityMountRuleCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void RequesterActivityMountRuleCatalogueRetryWrapper::modifyRequesterActivityMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &mountPolicy) { + return retryOnLostConnection(m_log, [&](){ + m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRulePolicy(admin, instanceName, requesterName, + activityRegex, mountPolicy); + }, m_maxTriesToConnect); +} + +void RequesterActivityMountRuleCatalogueRetryWrapper::modifyRequesterActivityMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &activityRegex, const std::string &comment) { + return retryOnLostConnection(m_log, [&](){ + m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRuleComment(admin, instanceName, requesterName, + activityRegex, comment); + }, m_maxTriesToConnect); +} + +void RequesterActivityMountRuleCatalogueRetryWrapper::createRequesterActivityMountRule( + const common::dataStructures::SecurityIdentity &admin, const std::string &mountPolicyName, + const std::string &diskInstance, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) { + return retryOnLostConnection(m_log, [&](){ + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(admin, mountPolicyName, diskInstance, + requesterName, activityRegex, comment); + }, m_maxTriesToConnect); +} + +std::list<common::dataStructures::RequesterActivityMountRule> + RequesterActivityMountRuleCatalogueRetryWrapper::getRequesterActivityMountRules() const { + return retryOnLostConnection(m_log, [&](){ + return m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + }, m_maxTriesToConnect); +} + +void RequesterActivityMountRuleCatalogueRetryWrapper::deleteRequesterActivityMountRule( + const std::string &diskInstanceName, const std::string &requesterName, const std::string &activityRegex) { + return retryOnLostConnection(m_log, [&](){ + m_catalogue->RequesterActivityMountRule()->deleteRequesterActivityMountRule(diskInstanceName, requesterName, + activityRegex); + }, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..51eac5b454 --- /dev/null +++ b/catalogue/retrywrappers/RequesterActivityMountRuleCatalogueRetryWrapper.hpp @@ -0,0 +1,64 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterActivityMountRuleCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class RequesterActivityMountRuleCatalogueRetryWrapper : public RequesterActivityMountRuleCatalogue { +public: + RequesterActivityMountRuleCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~RequesterActivityMountRuleCatalogueRetryWrapper() override = default; + + void modifyRequesterActivityMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &mountPolicy) override; + + void modifyRequesterActivityMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &activityRegex, + const std::string &comment) override; + + void createRequesterActivityMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &activityRegex, const std::string &comment) override; + + std::list<common::dataStructures::RequesterActivityMountRule> getRequesterActivityMountRules() const override; + + void deleteRequesterActivityMountRule(const std::string &diskInstanceName, const std::string &requesterName, + const std::string &activityRegex) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..c190a09560 --- /dev/null +++ b/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.cpp @@ -0,0 +1,74 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/RequesterGroupMountRule.hpp" + +namespace cta { +namespace catalogue { + +RequesterGroupMountRuleCatalogueRetryWrapper::RequesterGroupMountRuleCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void RequesterGroupMountRuleCatalogueRetryWrapper::modifyRequesterGroupMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &mountPolicy) { + return retryOnLostConnection(m_log, [&] { + return m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRulePolicy(admin, instanceName, + requesterGroupName, mountPolicy);}, m_maxTriesToConnect); +} + +void RequesterGroupMountRuleCatalogueRetryWrapper::modifyRequesterGroupMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterGroupName, const std::string &comment) { + return retryOnLostConnection(m_log, [&] { + return m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRuleComment(admin, instanceName, + requesterGroupName, comment);}, m_maxTriesToConnect); +} + +void RequesterGroupMountRuleCatalogueRetryWrapper::createRequesterGroupMountRule( + const common::dataStructures::SecurityIdentity &admin, const std::string &mountPolicyName, + const std::string &diskInstanceName, const std::string &requesterGroupName, const std::string &comment) { + return retryOnLostConnection(m_log, [&] { + return m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(admin, mountPolicyName, + diskInstanceName, requesterGroupName, comment);}, m_maxTriesToConnect); +} + +std::list<common::dataStructures::RequesterGroupMountRule> + RequesterGroupMountRuleCatalogueRetryWrapper::getRequesterGroupMountRules() const { + return retryOnLostConnection(m_log, [&] { + return m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules();}, m_maxTriesToConnect); +} + + +void RequesterGroupMountRuleCatalogueRetryWrapper::deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) { + return retryOnLostConnection(m_log, [&] { + return m_catalogue->RequesterGroupMountRule()->deleteRequesterGroupMountRule(diskInstanceName, + requesterGroupName);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..0d8c340095 --- /dev/null +++ b/catalogue/retrywrappers/RequesterGroupMountRuleCatalogueRetryWrapper.hpp @@ -0,0 +1,63 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterGroupMountRuleCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class RequesterGroupMountRuleCatalogueRetryWrapper : public RequesterGroupMountRuleCatalogue { +public: + RequesterGroupMountRuleCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~RequesterGroupMountRuleCatalogueRetryWrapper() override = default; + + void modifyRequesterGroupMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &mountPolicy) override; + + void modifyRequesterGroupMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterGroupName, const std::string &comment) override; + + void createRequesterGroupMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstanceName, const std::string &requesterGroupName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterGroupMountRule> getRequesterGroupMountRules() const override; + + + void deleteRequesterGroupMountRule(const std::string &diskInstanceName, + const std::string &requesterGroupName) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..77f24e51a2 --- /dev/null +++ b/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.cpp @@ -0,0 +1,73 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" + +namespace cta { +namespace catalogue { + +RequesterMountRuleCatalogueRetryWrapper::RequesterMountRuleCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) {} + +void RequesterMountRuleCatalogueRetryWrapper::modifyRequesterMountRulePolicy( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &mountPolicy) { + return retryOnLostConnection(m_log, [&]() { + m_catalogue->RequesterMountRule()->modifyRequesterMountRulePolicy(admin, instanceName, requesterName, mountPolicy); + }, m_maxTriesToConnect); +} + +void RequesterMountRuleCatalogueRetryWrapper::modifyRequesteMountRuleComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &instanceName, + const std::string &requesterName, const std::string &comment) { + return retryOnLostConnection(m_log, [&]() { + m_catalogue->RequesterMountRule()->modifyRequesteMountRuleComment(admin, instanceName, requesterName, comment); + }, m_maxTriesToConnect); +} + +void RequesterMountRuleCatalogueRetryWrapper::createRequesterMountRule( + const common::dataStructures::SecurityIdentity &admin, const std::string &mountPolicyName, + const std::string &diskInstance, const std::string &requesterName, const std::string &comment) { + return retryOnLostConnection(m_log, [&]() { + m_catalogue->RequesterMountRule()->createRequesterMountRule(admin, mountPolicyName, diskInstance, requesterName, comment); + }, m_maxTriesToConnect); +} + +std::list<common::dataStructures::RequesterMountRule> RequesterMountRuleCatalogueRetryWrapper::getRequesterMountRules() const { + return retryOnLostConnection(m_log, [&]() { + return m_catalogue->RequesterMountRule()->getRequesterMountRules(); + }, m_maxTriesToConnect); +} + +void RequesterMountRuleCatalogueRetryWrapper::deleteRequesterMountRule(const std::string &diskInstanceName, + const std::string &requesterName) { + return retryOnLostConnection(m_log, [&]() { + m_catalogue->RequesterMountRule()->deleteRequesterMountRule(diskInstanceName, requesterName); + }, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..1084f195af --- /dev/null +++ b/catalogue/retrywrappers/RequesterMountRuleCatalogueRetryWrapper.hpp @@ -0,0 +1,61 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/RequesterMountRuleCatalogue.hpp" + +namespace cta { + +namespace log { +class Logger; +} + +namespace catalogue { + +class Catalogue; + +class RequesterMountRuleCatalogueRetryWrapper : public RequesterMountRuleCatalogue { +public: + RequesterMountRuleCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~RequesterMountRuleCatalogueRetryWrapper() override = default; + + void modifyRequesterMountRulePolicy(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &mountPolicy) override; + + void modifyRequesteMountRuleComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &instanceName, const std::string &requesterName, const std::string &comment) override; + + void createRequesterMountRule(const common::dataStructures::SecurityIdentity &admin, + const std::string &mountPolicyName, const std::string &diskInstance, const std::string &requesterName, + const std::string &comment) override; + + std::list<common::dataStructures::RequesterMountRule> getRequesterMountRules() const override; + + void deleteRequesterMountRule(const std::string &diskInstanceName, const std::string &requesterName) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..1d04b4d988 --- /dev/null +++ b/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.cpp @@ -0,0 +1,46 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp" +#include "catalogue/SchemaVersion.hpp" + +namespace cta { +namespace catalogue { + +SchemaCatalogueRetryWrapper::SchemaCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +SchemaVersion SchemaCatalogueRetryWrapper::getSchemaVersion() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Schema()->getSchemaVersion();}, m_maxTriesToConnect); +} + +void SchemaCatalogueRetryWrapper::verifySchemaVersion() { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Schema()->verifySchemaVersion();}, m_maxTriesToConnect); +} + +void SchemaCatalogueRetryWrapper::ping() { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Schema()->ping();}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..94e87407c7 --- /dev/null +++ b/catalogue/retrywrappers/SchemaCatalogueRetryWrapper.hpp @@ -0,0 +1,49 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/SchemaCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; +class SchemaVersion; + +class SchemaCatalogueRetryWrapper: public SchemaCatalogue { +public: + SchemaCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~SchemaCatalogueRetryWrapper() override = default; + + SchemaVersion getSchemaVersion() const override; + + void verifySchemaVersion() override; + + void ping() override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..fe2d92bbc5 --- /dev/null +++ b/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.cpp @@ -0,0 +1,84 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp" +#include "common/dataStructures/StorageClass.hpp" + +namespace cta { +namespace catalogue { + +StorageClassCatalogueRetryWrapper::StorageClassCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void StorageClassCatalogueRetryWrapper::createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->createStorageClass(admin, storageClass);}, + m_maxTriesToConnect); +} + +void StorageClassCatalogueRetryWrapper::deleteStorageClass(const std::string &storageClassName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->deleteStorageClass(storageClassName);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::StorageClass> StorageClassCatalogueRetryWrapper::getStorageClasses() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->getStorageClasses();}, + m_maxTriesToConnect); +} + +common::dataStructures::StorageClass StorageClassCatalogueRetryWrapper::getStorageClass(const std::string &name) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->getStorageClass(name);}, + m_maxTriesToConnect); +} + +void StorageClassCatalogueRetryWrapper::modifyStorageClassNbCopies( + const common::dataStructures::SecurityIdentity &admin, const std::string &name, const uint64_t nbCopies) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->modifyStorageClassNbCopies(admin, name, + nbCopies);}, + m_maxTriesToConnect); +} + +void StorageClassCatalogueRetryWrapper::modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->modifyStorageClassComment(admin, name, + comment);}, + m_maxTriesToConnect); +} + +void StorageClassCatalogueRetryWrapper::modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->modifyStorageClassVo(admin, name, vo);}, + m_maxTriesToConnect); +} + +void StorageClassCatalogueRetryWrapper::modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->StorageClass()->modifyStorageClassName(admin, currentName, + newName);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..0462e0905b --- /dev/null +++ b/catalogue/retrywrappers/StorageClassCatalogueRetryWrapper.hpp @@ -0,0 +1,67 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/interfaces/StorageClassCatalogue.hpp" +#include "common/log/Logger.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; + +class StorageClassCatalogueRetryWrapper: public StorageClassCatalogue { +public: + StorageClassCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~StorageClassCatalogueRetryWrapper() override = default; + + void createStorageClass( + const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::StorageClass &storageClass) override; + + void deleteStorageClass(const std::string &storageClassName) override; + + std::list<common::dataStructures::StorageClass> getStorageClasses() const override; + + common::dataStructures::StorageClass getStorageClass(const std::string &name) const override; + + void modifyStorageClassNbCopies(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbCopies) override; + + void modifyStorageClassComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) override; + + void modifyStorageClassVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyStorageClassName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class StorageClassCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/TapeCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/TapeCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..ae5c7db332 --- /dev/null +++ b/catalogue/retrywrappers/TapeCatalogueRetryWrapper.cpp @@ -0,0 +1,191 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp" +#include "catalogue/TapeForWriting.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" + +namespace cta { +namespace catalogue { + +TapeCatalogueRetryWrapper::TapeCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, + const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void TapeCatalogueRetryWrapper::createTape(const common::dataStructures::SecurityIdentity &admin, + const CreateTapeAttributes & tape) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->createTape(admin, tape);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::deleteTape(const std::string &vid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->deleteTape(vid);}, m_maxTriesToConnect); +} + +std::list<common::dataStructures::Tape> TapeCatalogueRetryWrapper::getTapes( + const TapeSearchCriteria &searchCriteria) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getTapes(searchCriteria);}, m_maxTriesToConnect); +} + +common::dataStructures::VidToTapeMap TapeCatalogueRetryWrapper::getTapesByVid(const std::string& vid) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getTapesByVid(vid);}, m_maxTriesToConnect); +} + +common::dataStructures::VidToTapeMap TapeCatalogueRetryWrapper::getTapesByVid(const std::set<std::string> &vids) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getTapesByVid(vids);}, m_maxTriesToConnect); +} + +std::map<std::string, std::string> TapeCatalogueRetryWrapper::getVidToLogicalLibrary( + const std::set<std::string> &vids) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getVidToLogicalLibrary(vids);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::reclaimTape(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, cta::log::LogContext & lc) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->reclaimTape(admin, vid, lc);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::checkTapeForLabel(const std::string &vid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->checkTapeForLabel(vid);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::tapeLabelled(const std::string &vid, const std::string &drive) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->tapeLabelled(vid, drive);}, m_maxTriesToConnect); +} + +uint64_t TapeCatalogueRetryWrapper::getNbFilesOnTape(const std::string &vid) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getNbFilesOnTape(vid);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &mediaType) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeMediaType(admin, vid, mediaType);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &vendor) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeVendor(admin, vid, vendor);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &logicalLibraryName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeLogicalLibraryName(admin, vid, + logicalLibraryName);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &tapePoolName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeTapePoolName(admin, vid, + tapePoolName);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &encryptionKeyName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeEncryptionKeyName(admin, vid, + encryptionKeyName);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string &verificationStatus) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeVerificationStatus(admin, vid, + verificationStatus);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeState(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeState(admin,vid, state, prev_state, + stateReason);}, m_maxTriesToConnect); +} + +bool TapeCatalogueRetryWrapper::tapeExists(const std::string &vid) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->tapeExists(vid);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeFull(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const bool fullValue) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeFull(admin, vid, fullValue);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string & reason) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeRepackingDisabled(admin, vid, reason);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeDirty(admin, vid, dirtyValue);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeIsFromCastorInUnitTests(const std::string &vid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeIsFromCastorInUnitTests(vid);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::string & reason) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeDisabled(admin, vid, reason);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::setTapeDirty(const std::string & vid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->setTapeDirty(vid);}, m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &vid, const std::optional<std::string> &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->modifyTapeComment(admin, vid, comment);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::tapeMountedForArchive(const std::string &vid, const std::string &drive) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->tapeMountedForArchive(vid, drive);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::tapeMountedForRetrieve(const std::string &vid, const std::string &drive) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->tapeMountedForRetrieve(vid, drive);}, + m_maxTriesToConnect); +} + +void TapeCatalogueRetryWrapper::noSpaceLeftOnTape(const std::string &vid) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->noSpaceLeftOnTape(vid);}, m_maxTriesToConnect); +} + +std::list<TapeForWriting> TapeCatalogueRetryWrapper::getTapesForWriting(const std::string &logicalLibraryName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getTapesForWriting(logicalLibraryName);}, + m_maxTriesToConnect); +} + +common::dataStructures::Label::Format TapeCatalogueRetryWrapper::getTapeLabelFormat(const std::string& vid) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->Tape()->getTapeLabelFormat(vid);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..0c45d2a7da --- /dev/null +++ b/catalogue/retrywrappers/TapeCatalogueRetryWrapper.hpp @@ -0,0 +1,118 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/TapeCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; +class SchemaVersion; + +class TapeCatalogueRetryWrapper: public TapeCatalogue { +public: + TapeCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~TapeCatalogueRetryWrapper() override = default; + + void createTape(const common::dataStructures::SecurityIdentity &admin, const CreateTapeAttributes & tape) override; + + void deleteTape(const std::string &vid) override; + + std::list<common::dataStructures::Tape> getTapes(const TapeSearchCriteria &searchCriteria) const override; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::string& vid) const override; + + common::dataStructures::VidToTapeMap getTapesByVid(const std::set<std::string> &vids) const override; + + std::map<std::string, std::string> getVidToLogicalLibrary(const std::set<std::string> &vids) const override; + + void reclaimTape(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + cta::log::LogContext & lc) override; + + void checkTapeForLabel(const std::string &vid) override; + + void tapeLabelled(const std::string &vid, const std::string &drive) override; + + uint64_t getNbFilesOnTape(const std::string &vid) const override; + + void modifyTapeMediaType(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &mediaType) override; + + void modifyTapeVendor(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &vendor) override; + + void modifyTapeLogicalLibraryName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &logicalLibraryName) override; + + void modifyTapeTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &tapePoolName) override; + + void modifyTapeEncryptionKeyName(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &encryptionKeyName) override; + + void modifyTapeVerificationStatus(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string &verificationStatus) override; + + void modifyTapeState(const common::dataStructures::SecurityIdentity &admin,const std::string &vid, + const common::dataStructures::Tape::State & state, + const std::optional<common::dataStructures::Tape::State> & prev_state, + const std::optional<std::string> & stateReason) override; + + bool tapeExists(const std::string &vid) const override; + + void setTapeFull(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool fullValue) override; + + void setTapeDirty(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const bool dirtyValue) override; + + void setTapeIsFromCastorInUnitTests(const std::string &vid) override; + + void setTapeDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) override; + + void setTapeRepackingDisabled(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::string & reason) override; + + void setTapeDirty(const std::string & vid) override; + + void modifyTapeComment(const common::dataStructures::SecurityIdentity &admin, const std::string &vid, + const std::optional<std::string> &comment) override; + + void tapeMountedForArchive(const std::string &vid, const std::string &drive) override; + + void tapeMountedForRetrieve(const std::string &vid, const std::string &drive) override; + + void noSpaceLeftOnTape(const std::string &vid) override; + + std::list<TapeForWriting> getTapesForWriting(const std::string &logicalLibraryName) const override; + + common::dataStructures::Label::Format getTapeLabelFormat(const std::string& vid) const override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..b06c7b9fca --- /dev/null +++ b/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.cpp @@ -0,0 +1,55 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" + +namespace cta { +namespace catalogue { + +TapeFileCatalogueRetryWrapper::TapeFileCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void TapeFileCatalogueRetryWrapper::filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapeFile()->filesWrittenToTape(event);}, + m_maxTriesToConnect); +} + +void TapeFileCatalogueRetryWrapper::deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, + const std::string &reason) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapeFile()->deleteTapeFileCopy(file, reason);}, + m_maxTriesToConnect); +} + +common::dataStructures::RetrieveFileQueueCriteria TapeFileCatalogueRetryWrapper::prepareToRetrieveFile( + const std::string &diskInstanceName, const uint64_t archiveFileId, + const common::dataStructures::RequesterIdentity &user, const std::optional<std::string> & activity, + log::LogContext &lc, const std::optional<std::string> &mountPolicyName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName, + archiveFileId, user, activity, lc, mountPolicyName);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta diff --git a/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..a1ec374968 --- /dev/null +++ b/catalogue/retrywrappers/TapeFileCatalogueRetryWrapper.hpp @@ -0,0 +1,51 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/TapeFileCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; + +class TapeFileCatalogueRetryWrapper: public TapeFileCatalogue { +public: + TapeFileCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~TapeFileCatalogueRetryWrapper() override = default; + + void filesWrittenToTape(const std::set<TapeItemWrittenPointer> &event) override; + + void deleteTapeFileCopy(common::dataStructures::ArchiveFile &file, const std::string &reason) override; + + common::dataStructures::RetrieveFileQueueCriteria prepareToRetrieveFile(const std::string &diskInstanceName, + const uint64_t archiveFileId, const common::dataStructures::RequesterIdentity &user, + const std::optional<std::string> & activity, log::LogContext &lc, + const std::optional<std::string> &mountPolicyName = std::nullopt) override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..12d916ab4d --- /dev/null +++ b/catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp @@ -0,0 +1,75 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> +#include <optional> +#include <string> +#include <list> + +#include "catalogue/interfaces/TapePoolCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; + +class TapePoolCatalogueRetryWrapper: public TapePoolCatalogue { +public: + TapePoolCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~TapePoolCatalogueRetryWrapper() override = default; + + void createTapePool(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) override; + + void deleteTapePool(const std::string &name) override; + + std::list<TapePool> getTapePools(const TapePoolSearchCriteria &searchCriteria) const override; + + std::optional<TapePool> getTapePool(const std::string &tapePoolName) const override; + + void modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &vo) override; + + void modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const uint64_t nbPartialTapes) override; + + void modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, const std::string &name, + const std::string &comment) override; + + 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; + + void modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, const std::string ¤tName, + const std::string &newName) override; + + bool tapePoolExists(const std::string &tapePoolName) const override; + +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/TapePoolRetryCatalogueWrapper.cpp b/catalogue/retrywrappers/TapePoolRetryCatalogueWrapper.cpp new file mode 100644 index 0000000000..f0f0da6452 --- /dev/null +++ b/catalogue/retrywrappers/TapePoolRetryCatalogueWrapper.cpp @@ -0,0 +1,96 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/TapePoolCatalogueRetryWrapper.hpp" + +namespace cta { +namespace catalogue { + +TapePoolCatalogueRetryWrapper::TapePoolCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, + log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void TapePoolCatalogueRetryWrapper::createTapePool(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo, const uint64_t nbPartialTapes, const bool encryptionValue, + const std::optional<std::string> &supply, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->createTapePool(admin, name, vo, + nbPartialTapes, encryptionValue, supply, comment);}, m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::deleteTapePool(const std::string &name) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->deleteTapePool(name);}, m_maxTriesToConnect); +} + +std::list<TapePool> TapePoolCatalogueRetryWrapper::getTapePools(const TapePoolSearchCriteria &searchCriteria) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->getTapePools(searchCriteria);}, + m_maxTriesToConnect); +} + +std::optional<TapePool> TapePoolCatalogueRetryWrapper::getTapePool(const std::string &tapePoolName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->getTapePool(tapePoolName);}, + m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::modifyTapePoolVo(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &vo) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->modifyTapePoolVo(admin, name, vo);}, + m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::modifyTapePoolNbPartialTapes(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const uint64_t nbPartialTapes) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->modifyTapePoolNbPartialTapes(admin, name, + nbPartialTapes);}, m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::modifyTapePoolComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->modifyTapePoolComment(admin, name, comment);}, + m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::setTapePoolEncryption(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const bool encryptionValue) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->setTapePoolEncryption(admin, name, + encryptionValue);}, m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::modifyTapePoolSupply(const common::dataStructures::SecurityIdentity &admin, + const std::string &name, const std::string &supply) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->modifyTapePoolSupply(admin, name, supply);}, + m_maxTriesToConnect); +} + +void TapePoolCatalogueRetryWrapper::modifyTapePoolName(const common::dataStructures::SecurityIdentity &admin, + const std::string ¤tName, const std::string &newName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->modifyTapePoolName(admin, currentName, + newName);}, m_maxTriesToConnect); +} + +bool TapePoolCatalogueRetryWrapper::tapePoolExists(const std::string &tapePoolName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->TapePool()->tapePoolExists(tapePoolName);}, + m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.cpp b/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.cpp new file mode 100644 index 0000000000..05d6ad918f --- /dev/null +++ b/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.cpp @@ -0,0 +1,98 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/retrywrappers/retryOnLostConnection.hpp" +#include "catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" + +namespace cta { +namespace catalogue { + +VirtualOrganizationCatalogueRetryWrapper::VirtualOrganizationCatalogueRetryWrapper( + const std::unique_ptr<Catalogue>& catalogue, log::Logger &log, const uint32_t maxTriesToConnect) + : m_catalogue(catalogue), m_log(log), m_maxTriesToConnect(maxTriesToConnect) { +} + +void VirtualOrganizationCatalogueRetryWrapper::createVirtualOrganization( + const common::dataStructures::SecurityIdentity &admin, const common::dataStructures::VirtualOrganization &vo) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->createVirtualOrganization(admin, vo);}, + m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::deleteVirtualOrganization(const std::string &voName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->deleteVirtualOrganization(voName);}, + m_maxTriesToConnect); +} + +std::list<common::dataStructures::VirtualOrganization> VirtualOrganizationCatalogueRetryWrapper::getVirtualOrganizations() const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->getVirtualOrganizations();}, m_maxTriesToConnect); +} + +common::dataStructures::VirtualOrganization VirtualOrganizationCatalogueRetryWrapper::getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->getVirtualOrganizationOfTapepool(tapepoolName);}, + m_maxTriesToConnect); +} + +common::dataStructures::VirtualOrganization VirtualOrganizationCatalogueRetryWrapper::getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->getCachedVirtualOrganizationOfTapepool(tapepoolName);}, + m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationName(admin, currentVoName, + newVoName);}, m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationReadMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t readMaxDrives) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationReadMaxDrives(admin, voName, + readMaxDrives);}, m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationWriteMaxDrives( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t writeMaxDrives) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationWriteMaxDrives(admin, voName, + writeMaxDrives);}, m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationMaxFileSize( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const uint64_t maxFileSize) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationMaxFileSize(admin, voName, + maxFileSize);}, m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationComment( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &comment) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationComment(admin, voName, + comment);}, m_maxTriesToConnect); +} + +void VirtualOrganizationCatalogueRetryWrapper::modifyVirtualOrganizationDiskInstanceName( + const common::dataStructures::SecurityIdentity &admin, const std::string &voName, const std::string &diskInstance) { + return retryOnLostConnection(m_log, [&]{return m_catalogue->VO()->modifyVirtualOrganizationDiskInstanceName(admin, + voName, diskInstance);}, m_maxTriesToConnect); +} + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp b/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp new file mode 100644 index 0000000000..216247e7a1 --- /dev/null +++ b/catalogue/retrywrappers/VirtualOrganizationCatalogueRetryWrapper.hpp @@ -0,0 +1,73 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <memory> + +#include "catalogue/interfaces/VirtualOrganizationCatalogue.hpp" + +namespace cta { +namespace catalogue { + +class Catalogue; +class SchemaVersion; + +class VirtualOrganizationCatalogueRetryWrapper: public VirtualOrganizationCatalogue { +public: + VirtualOrganizationCatalogueRetryWrapper(const std::unique_ptr<Catalogue>& catalogue, log::Logger &m_log, + const uint32_t maxTriesToConnect); + ~VirtualOrganizationCatalogueRetryWrapper() override = default; + + void createVirtualOrganization(const common::dataStructures::SecurityIdentity &admin, + const common::dataStructures::VirtualOrganization &vo) override; + + void deleteVirtualOrganization(const std::string &voName) override; + std::list<common::dataStructures::VirtualOrganization> getVirtualOrganizations() const override; + + common::dataStructures::VirtualOrganization getVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + common::dataStructures::VirtualOrganization getCachedVirtualOrganizationOfTapepool( + const std::string & tapepoolName) const override; + + void modifyVirtualOrganizationName( + const common::dataStructures::SecurityIdentity &admin, const std::string ¤tVoName, + const std::string &newVoName) override; + + void modifyVirtualOrganizationReadMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t readMaxDrives) override; + + void modifyVirtualOrganizationWriteMaxDrives(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t writeMaxDrives) override; + + void modifyVirtualOrganizationMaxFileSize(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const uint64_t maxFileSize) override; + + void modifyVirtualOrganizationComment(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &comment) override; + + void modifyVirtualOrganizationDiskInstanceName(const common::dataStructures::SecurityIdentity &admin, + const std::string &voName, const std::string &diskInstance) override; +private: + const std::unique_ptr<Catalogue>& m_catalogue; + log::Logger &m_log; + uint32_t m_maxTriesToConnect; +}; // class SchemaCatalogueRetryWrapper + +} // namespace catalogue +} // namespace cta \ No newline at end of file diff --git a/catalogue/retryOnLostConnection.hpp b/catalogue/retrywrappers/retryOnLostConnection.hpp similarity index 94% rename from catalogue/retryOnLostConnection.hpp rename to catalogue/retrywrappers/retryOnLostConnection.hpp index 08214bcbfd..df2cd0ac39 100644 --- a/catalogue/retryOnLostConnection.hpp +++ b/catalogue/retrywrappers/retryOnLostConnection.hpp @@ -17,16 +17,14 @@ #pragma once -#include "common/exception/Exception.hpp" -#include "common/exception/LostDatabaseConnection.hpp" -//#include "common/checksum/ChecksumTypeMismatch.hpp" -//#include "common/checksum/ChecksumValueMismatch.hpp" -#include "common/log/Logger.hpp" - #include <list> #include <stdint.h> #include <type_traits> +#include "common/exception/Exception.hpp" +#include "common/exception/LostDatabaseConnection.hpp" +#include "common/log/Logger.hpp" + namespace cta { namespace catalogue { @@ -68,5 +66,5 @@ typename std::result_of<T()>::type retryOnLostConnection(log::Logger &log, const } } -} // namespace catalogue -} // namespace cta +} // namespace catalogue +} // namespace cta diff --git a/catalogue/tests/CatalogueTestUtils.cpp b/catalogue/tests/CatalogueTestUtils.cpp new file mode 100644 index 0000000000..ee80b31a45 --- /dev/null +++ b/catalogue/tests/CatalogueTestUtils.cpp @@ -0,0 +1,511 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <list> +#include <iostream> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/DiskInstanceSpace.hpp" +#include "common/dataStructures/EntryLog.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/dataStructures/LogicalLibrary.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/RequesterGroupMountRule.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/Tape.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/DummyLogger.hpp" +#include "disk/DiskSystem.hpp" + +namespace unitTests { + +std::unique_ptr<cta::catalogue::Catalogue> CatalogueTestUtils::createCatalogue( + cta::catalogue::CatalogueFactory *const *const catalogueFactoryPtrPtr, cta::log::LogContext *lc) { + try { + if (nullptr == catalogueFactoryPtrPtr) { + throw cta::exception::Exception("Global pointer to the catalogue factory pointer for unit-tests in null"); + } + if (nullptr == (*catalogueFactoryPtrPtr)) { + throw cta::exception::Exception("Global pointer to the catalogue factoryfor unit-tests in null"); + } + + auto catalogue = (*catalogueFactoryPtrPtr)->create(); + CatalogueTestUtils::wipeDatabase(catalogue.get(), lc); + return catalogue; + } catch(cta::exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +void CatalogueTestUtils::wipeDatabase(cta::catalogue::Catalogue *catalogue, cta::log::LogContext *lc) { + { + const auto adminUsers = catalogue->AdminUser()->getAdminUsers(); + for(auto &adminUser: adminUsers) { + catalogue->AdminUser()->deleteAdminUser(adminUser.name); + } + } + { + const auto archiveRoutes = catalogue->ArchiveRoute()->getArchiveRoutes(); + for(auto &archiveRoute: archiveRoutes) { + catalogue->ArchiveRoute()->deleteArchiveRoute(archiveRoute.storageClassName, + archiveRoute.copyNb); + } + } + { + const auto rules = catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + for(const auto &rule: rules) { + catalogue->RequesterActivityMountRule()->deleteRequesterActivityMountRule(rule.diskInstance, rule.name, + rule.activityRegex); + } + } + { + const auto rules = catalogue->RequesterMountRule()->getRequesterMountRules(); + for(const auto &rule: rules) { + catalogue->RequesterMountRule()->deleteRequesterMountRule(rule.diskInstance, rule.name); + } + } + { + const auto rules = catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + for(const auto &rule: rules) { + catalogue->RequesterGroupMountRule()->deleteRequesterGroupMountRule(rule.diskInstance, rule.name); + } + } + { + // The iterator returned from catalogue->ArchiveFile()->getArchiveFilesItor() will lock + // an SQLite file database, so copy all of its results into a list in + // order to release the lock before moving on to deleting database rows + auto itor = catalogue->ArchiveFile()->getArchiveFilesItor(); + std::list<cta::common::dataStructures::ArchiveFile> archiveFiles; + while(itor.hasMore()) { + archiveFiles.push_back(itor.next()); + } + + for(const auto &archiveFile: archiveFiles) { + catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(archiveFile.diskInstance, + archiveFile.archiveFileID, *lc); + } + } + + { + //Delete all the entries from the recycle log table + auto itor = catalogue->FileRecycleLog()->getFileRecycleLogItor(); + while(itor.hasMore()){ + catalogue->FileRecycleLog()->deleteFilesFromRecycleLog(itor.next().vid, *lc); + } + } + { + const auto tapes = catalogue->Tape()->getTapes(); + for(const auto &tape: tapes) { + catalogue->Tape()->deleteTape(tape.vid); + } + } + { + const auto mediaTypes = catalogue->MediaType()->getMediaTypes(); + for(const auto &mediaType: mediaTypes) { + catalogue->MediaType()->deleteMediaType(mediaType.name); + } + } + { + const auto storageClasses = catalogue->StorageClass()->getStorageClasses(); + for(const auto &storageClass: storageClasses) { + catalogue->StorageClass()->deleteStorageClass(storageClass.name); + } + } + { + const auto tapePools = catalogue->TapePool()->getTapePools(); + for(const auto &tapePool: tapePools) { + catalogue->TapePool()->deleteTapePool(tapePool.name); + } + } + { + const auto logicalLibraries = catalogue->LogicalLibrary()->getLogicalLibraries(); + for(const auto &logicalLibrary: logicalLibraries) { + catalogue->LogicalLibrary()->deleteLogicalLibrary(logicalLibrary.name); + } + } + { + const auto mountPolicies = catalogue->MountPolicy()->getMountPolicies(); + for(const auto &mountPolicy: mountPolicies) { + catalogue->MountPolicy()->deleteMountPolicy(mountPolicy.name); + } + } + { + const auto diskSystems = catalogue->DiskSystem()->getAllDiskSystems(); + for(const auto &ds: diskSystems) { + catalogue->DiskSystem()->deleteDiskSystem(ds.name); + } + } + { + const auto diskInstanceSpaces = catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + for(const auto &dis: diskInstanceSpaces) { + catalogue->DiskInstanceSpace()->deleteDiskInstanceSpace(dis.name, dis.diskInstance); + } + } + { + const auto virtualOrganizations = catalogue->VO()->getVirtualOrganizations(); + for(const auto &vo: virtualOrganizations) { + catalogue->VO()->deleteVirtualOrganization(vo.name); + } + } + { + const auto diskInstances = catalogue->DiskInstance()->getAllDiskInstances(); + for(const auto &di: diskInstances) { + catalogue->DiskInstance()->deleteDiskInstance(di.name); + } + } + checkWipedDatabase(catalogue); +} + +void CatalogueTestUtils::checkWipedDatabase(cta::catalogue::Catalogue *catalogue) { + if(!catalogue->AdminUser()->getAdminUsers().empty()) { + throw cta::exception::Exception("Found one of more admin users after emptying the database"); + } + + if(catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()) { + throw cta::exception::Exception("Found one of more archive files after emptying the database"); + } + + if(!catalogue->ArchiveRoute()->getArchiveRoutes().empty()) { + throw cta::exception::Exception("Found one of more archive routes after emptying the database"); + } + + if(catalogue->FileRecycleLog()->getFileRecycleLogItor().hasMore()){ + throw cta::exception::Exception("Found one or more files in the file recycle log after emptying the database"); + } + + if(!catalogue->DiskSystem()->getAllDiskSystems().empty()) { + throw cta::exception::Exception("Found one of more disk systems after emptying the database"); + } + + if (!catalogue->DiskInstance()->getAllDiskInstances().empty()) { + throw cta::exception::Exception("Found one of more disk instances after emptying the database"); + } + + if(!catalogue->LogicalLibrary()->getLogicalLibraries().empty()) { + throw cta::exception::Exception("Found one of more logical libraries after emptying the database"); + } + + if(!catalogue->MediaType()->getMediaTypes().empty()) { + throw cta::exception::Exception("Found one of more media types after emptying the database"); + } + + if(!catalogue->MountPolicy()->getMountPolicies().empty()) { + throw cta::exception::Exception("Found one of more mount policies after emptying the database"); + } + + if(!catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()) { + throw cta::exception::Exception("Found one of more requester group mount rules after emptying the database"); + } + + if(!catalogue->RequesterMountRule()->getRequesterMountRules().empty()) { + throw cta::exception::Exception("Found one of more requester mount rules after emptying the database"); + } + + if(!catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()) { + throw cta::exception::Exception("Found one of more requester activity mount rules after emptying the database"); + } + + if(!catalogue->StorageClass()->getStorageClasses().empty()) { + throw cta::exception::Exception("Found one of more storage classes after emptying the database"); + } + + if(!catalogue->Tape()->getTapes().empty()) { + throw cta::exception::Exception("Found one of more tapes after emptying the database"); + } + + if(!catalogue->TapePool()->getTapePools().empty()) { + throw cta::exception::Exception("Found one of more tape pools after emptying the database"); + } + + if(!catalogue->VO()->getVirtualOrganizations().empty()) { + throw cta::exception::Exception("Found one of more virtual organizations after emptying the database"); + } +} + +cta::common::dataStructures::SecurityIdentity CatalogueTestUtils::getLocalAdmin() { + cta::common::dataStructures::SecurityIdentity localAdmin; + localAdmin.username = "local_admin_user"; + localAdmin.host = "local_admin_host"; + + return localAdmin; +} + +cta::common::dataStructures::SecurityIdentity CatalogueTestUtils::getAdmin() { + cta::common::dataStructures::SecurityIdentity admin; + admin.username = "admin_user_name"; + admin.host = "admin_host"; + + return admin; +} + +cta::common::dataStructures::DiskInstance CatalogueTestUtils::getDiskInstance() { + cta::common::dataStructures::DiskInstance di; + di.name = "disk instance"; + di.comment = "Creation of disk instance"; + return di; +} + +cta::common::dataStructures::VirtualOrganization CatalogueTestUtils::getVo() { + cta::common::dataStructures::VirtualOrganization vo; + vo.name = "vo"; + vo.comment = "Creation of virtual organization vo"; + vo.readMaxDrives = 1; + vo.writeMaxDrives = 1; + vo.maxFileSize = 0; + vo.diskInstanceName = getDiskInstance().name; + return vo; +} + +cta::common::dataStructures::VirtualOrganization CatalogueTestUtils::getAnotherVo() { + cta::common::dataStructures::VirtualOrganization vo; + vo.name = "anotherVo"; + vo.comment = "Creation of another virtual organization vo"; + vo.readMaxDrives = 1; + vo.writeMaxDrives = 1; + vo.maxFileSize = 0; + vo.diskInstanceName = getDiskInstance().name; + return vo; +} + +cta::common::dataStructures::StorageClass CatalogueTestUtils::getStorageClass() { + cta::common::dataStructures::StorageClass storageClass; + storageClass.name = "storage_class_single_copy"; + storageClass.nbCopies = 1; + storageClass.vo.name = getVo().name; + storageClass.comment = "Creation of storage class with 1 copy on tape"; + return storageClass; +} + +cta::common::dataStructures::StorageClass CatalogueTestUtils::getAnotherStorageClass() { + cta::common::dataStructures::StorageClass storageClass; + storageClass.name = "another_storage_class"; + storageClass.nbCopies = 1; + storageClass.vo.name = getVo().name; + storageClass.comment = "Creation of another storage class"; + return storageClass; +} + +cta::common::dataStructures::StorageClass CatalogueTestUtils::getStorageClassDualCopy() { + cta::common::dataStructures::StorageClass storageClass; + storageClass.name = "storage_class_dual_copy"; + storageClass.nbCopies = 2; + storageClass.vo.name = getVo().name; + storageClass.comment = "Creation of storage class with 2 copies on tape"; + return storageClass; +} + +cta::common::dataStructures::StorageClass CatalogueTestUtils::getStorageClassTripleCopy() { + cta::common::dataStructures::StorageClass storageClass; + storageClass.name = "storage_class_triple_copy"; + storageClass.nbCopies = 3; + storageClass.vo.name = getVo().name; + storageClass.comment = "Creation of storage class with 3 copies on tape"; + return storageClass; +} + +cta::catalogue::MediaType CatalogueTestUtils::getMediaType() { + cta::catalogue::MediaType mediaType; + mediaType.name = "media_type"; + mediaType.capacityInBytes = (uint64_t)10 * 1000 * 1000 * 1000 * 1000; + mediaType.cartridge = "cartridge"; + mediaType.comment = "comment"; + mediaType.maxLPos = 100; + mediaType.minLPos = 1; + mediaType.nbWraps = 500; + mediaType.primaryDensityCode = 50; + mediaType.secondaryDensityCode = 50; + return mediaType; +} + +cta::catalogue::CreateTapeAttributes CatalogueTestUtils::getTape1() { + cta::catalogue::CreateTapeAttributes tape; + tape.vid = "VIDONE"; + tape.mediaType = getMediaType().name; + tape.vendor = "vendor"; + tape.logicalLibraryName = "logical_library"; + tape.tapePoolName = "tape_pool"; + tape.full = false; + tape.state = cta::common::dataStructures::Tape::ACTIVE; + tape.comment = "Creation of tape one"; + return tape; +} + +cta::catalogue::CreateTapeAttributes CatalogueTestUtils::getTape2() { + // Tape 2 is an exact copy of tape 1 except for its VID and comment + auto tape = getTape1(); + tape.vid = "VIDTWO"; + tape.comment = "Creation of tape two"; + return tape; +} + +cta::catalogue::CreateTapeAttributes CatalogueTestUtils::getTape3() { + // Tape 3 is an exact copy of tape 1 except for its VID and comment + auto tape = getTape1(); + tape.vid = "VIDTHREE"; + tape.comment = "Creation of tape three"; + return tape; +} + +cta::catalogue::CreateMountPolicyAttributes CatalogueTestUtils::getMountPolicy1() { + cta::catalogue::CreateMountPolicyAttributes mountPolicy; + mountPolicy.name = "mount_policy"; + mountPolicy.archivePriority = 1; + mountPolicy.minArchiveRequestAge = 2; + mountPolicy.retrievePriority = 3; + mountPolicy.minRetrieveRequestAge = 4; + mountPolicy.comment = "Create mount policy"; + return mountPolicy; +} + +cta::catalogue::CreateMountPolicyAttributes CatalogueTestUtils::getMountPolicy2() { + // Higher priority mount policy + cta::catalogue::CreateMountPolicyAttributes mountPolicy; + mountPolicy.name = "mount_policy_2"; + mountPolicy.archivePriority = 2; + mountPolicy.minArchiveRequestAge = 1; + mountPolicy.retrievePriority = 4; + mountPolicy.minRetrieveRequestAge = 3; + mountPolicy.comment = "Create mount policy"; + return mountPolicy; +} + +std::map<std::string, cta::catalogue::TapePool> CatalogueTestUtils::tapePoolListToMap( + const std::list<cta::catalogue::TapePool> &listOfTapePools) { + using namespace cta; + + try { + std::map<std::string, cta::catalogue::TapePool> m; + + for(auto &tapePool: listOfTapePools) { + if(m.end() != m.find(tapePool.name)) { + exception::Exception ex; + ex.getMessage() << "Tape pool " << tapePool.name << " is a duplicate"; + throw ex; + } + m[tapePool.name] = tapePool; + } + + return m; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +std::map<std::string, cta::common::dataStructures::Tape> CatalogueTestUtils::tapeListToMap( + const std::list<cta::common::dataStructures::Tape> &listOfTapes) { + using namespace cta; + + try { + std::map<std::string, cta::common::dataStructures::Tape> vidToTape; + + for (auto &tape: listOfTapes) { + if(vidToTape.end() != vidToTape.find(tape.vid)) { + throw exception::Exception(std::string("Duplicate VID: value=") + tape.vid); + } + vidToTape[tape.vid] = tape; + } + + return vidToTape; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +std::map<uint64_t, cta::common::dataStructures::ArchiveFile> CatalogueTestUtils::archiveFileItorToMap( + cta::catalogue::ArchiveFileItor &itor) { + using namespace cta; + + try { + std::map<uint64_t, common::dataStructures::ArchiveFile> m; + while(itor.hasMore()) { + const auto archiveFile = itor.next(); + if(m.end() != m.find(archiveFile.archiveFileID)) { + exception::Exception ex; + ex.getMessage() << "Archive file with ID " << archiveFile.archiveFileID << " is a duplicate"; + throw ex; + } + m[archiveFile.archiveFileID] = archiveFile; + } + return m; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +std::map<uint64_t, cta::common::dataStructures::ArchiveFile> CatalogueTestUtils::archiveFileListToMap( + const std::list<cta::common::dataStructures::ArchiveFile> &listOfArchiveFiles) { + using namespace cta; + + try { + std::map<uint64_t, common::dataStructures::ArchiveFile> archiveIdToArchiveFile; + + for (auto &archiveFile: listOfArchiveFiles) { + if(archiveIdToArchiveFile.end() != archiveIdToArchiveFile.find(archiveFile.archiveFileID)) { + throw exception::Exception(std::string("Duplicate archive file ID: value=") + std::to_string(archiveFile.archiveFileID)); + } + archiveIdToArchiveFile[archiveFile.archiveFileID] = archiveFile; + } + + return archiveIdToArchiveFile; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +std::map<std::string, cta::common::dataStructures::AdminUser> CatalogueTestUtils::adminUserListToMap( + const std::list<cta::common::dataStructures::AdminUser> &listOfAdminUsers) { + using namespace cta; + + try { + std::map<std::string, common::dataStructures::AdminUser> m; + + for(auto &adminUser: listOfAdminUsers) { + if(m.end() != m.find(adminUser.name)) { + exception::Exception ex; + ex.getMessage() << "Admin user " << adminUser.name << " is a duplicate"; + throw ex; + } + m[adminUser.name] = adminUser; + } + return m; + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/CatalogueTestUtils.hpp b/catalogue/tests/CatalogueTestUtils.hpp new file mode 100644 index 0000000000..897d38df02 --- /dev/null +++ b/catalogue/tests/CatalogueTestUtils.hpp @@ -0,0 +1,106 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <list> +#include <map> + +namespace cta { +namespace catalogue { +class Catalogue; +class CatalogueFactory; +template <typename Item> +class CatalogueItor; +class CreateMountPolicyAttributes; +class CreateTapeAttributes; +class MediaType; +class TapePool; +} // namespace catalogue + +namespace common { +namespace dataStructures { +class AdminUser; +class ArchiveFile; +class DiskInstance; +class LogicalLibrary; +class SecurityIdentity; +class StorageClass; +class Tape; +class VirtualOrganization; +} // namespace dataStructures +} // namespace common + +namespace log { +class LogContext; +} // namespace log +} // namespace cta + +namespace unitTests { + +const uint32_t PUBLIC_DISK_USER = 9751; +const uint32_t PUBLIC_DISK_GROUP = 9752; +const uint32_t DISK_FILE_OWNER_UID = 9753; +const uint32_t DISK_FILE_GID = 9754; +const uint32_t NON_EXISTENT_DISK_FILE_OWNER_UID = 9755; +const uint32_t NON_EXISTENT_DISK_FILE_GID = 9756; + +class CatalogueTestUtils { +public: + static std::unique_ptr<cta::catalogue::Catalogue> createCatalogue( + cta::catalogue::CatalogueFactory *const *const catalogueFactoryPtrPtr, cta::log::LogContext *lc); + static cta::common::dataStructures::SecurityIdentity getLocalAdmin(); + static cta::common::dataStructures::SecurityIdentity getAdmin(); + static cta::common::dataStructures::DiskInstance getDiskInstance(); + static cta::common::dataStructures::VirtualOrganization getVo(); + static cta::common::dataStructures::VirtualOrganization getAnotherVo(); + static cta::common::dataStructures::StorageClass getStorageClass(); + static cta::common::dataStructures::StorageClass getAnotherStorageClass(); + static cta::common::dataStructures::StorageClass getStorageClassDualCopy(); + static cta::common::dataStructures::StorageClass getStorageClassTripleCopy(); + static cta::catalogue::MediaType getMediaType(); + static cta::catalogue::CreateTapeAttributes getTape1(); + static cta::catalogue::CreateTapeAttributes getTape2(); + static cta::catalogue::CreateTapeAttributes getTape3(); + static cta::catalogue::CreateMountPolicyAttributes getMountPolicy1(); + static cta::catalogue::CreateMountPolicyAttributes getMountPolicy2(); + + static std::map<std::string, cta::catalogue::TapePool> tapePoolListToMap( + const std::list<cta::catalogue::TapePool> &listOfTapePools); + + static std::map<std::string, cta::common::dataStructures::LogicalLibrary> logicalLibraryListToMap( + const std::list<cta::common::dataStructures::LogicalLibrary> &listOfLibs); + + + static std::map<std::string, cta::common::dataStructures::Tape> tapeListToMap( + const std::list<cta::common::dataStructures::Tape> &listOfTapes); + + static std::map<uint64_t, cta::common::dataStructures::ArchiveFile> archiveFileItorToMap( + cta::catalogue::CatalogueItor<cta::common::dataStructures::ArchiveFile> &itor); + + static std::map<uint64_t, cta::common::dataStructures::ArchiveFile> archiveFileListToMap( + const std::list<cta::common::dataStructures::ArchiveFile> &listOfArchiveFiles); + + static std::map<std::string, cta::common::dataStructures::AdminUser> adminUserListToMap( + const std::list<cta::common::dataStructures::AdminUser> &listOfAdminUsers); + +private: + static void wipeDatabase(cta::catalogue::Catalogue *catalogue, cta::log::LogContext *lc); + static void checkWipedDatabase(cta::catalogue::Catalogue *catalogue); +}; + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/DbConfigVersionOfCatalogueTest.cpp b/catalogue/tests/DbConfigVersionOfCatalogueTest.cpp new file mode 100644 index 0000000000..56f4fab812 --- /dev/null +++ b/catalogue/tests/DbConfigVersionOfCatalogueTest.cpp @@ -0,0 +1,65 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/tests/modules/AdminUserCatalogueTest.hpp" +#include "catalogue/tests/modules/ArchiveFileCatalogueTest.hpp" +#include "catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskInstanceCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskSystemCatalogueTest.hpp" +#include "catalogue/tests/modules/DriveConfigCatalogueTest.hpp" +#include "catalogue/tests/modules/DriveStateCatalogueTest.hpp" +#include "catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp" +#include "catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp" +#include "catalogue/tests/modules/MediaTypeCatalogueTest.hpp" +#include "catalogue/tests/modules/MountPolicyCatalogueTest.hpp" +#include "catalogue/tests/modules/RequesterActivityMountRuleTest.hpp" +#include "catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp" +#include "catalogue/tests/modules/RequesterMountRuleTest.hpp" +#include "catalogue/tests/modules/SchemaCatalogueTest.hpp" +#include "catalogue/tests/modules/StorageClassCatalogueTest.hpp" +#include "catalogue/tests/modules/TapeCatalogueTest.hpp" +#include "catalogue/tests/modules/TapeFileCatalogueTest.hpp" +#include "catalogue/tests/modules/TapePoolCatalogueTest.hpp" +#include "catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp" +#include "tests/GlobalCatalogueFactoryForUnitTests.hpp" + +namespace unitTests { + +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_SchemaTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_AdminUserTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_DiskSystemTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_DiskInstanceTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_DiskInstanceSpaceTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_VirtualOrganizationTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_ArchiveRouteTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_MediaTypeTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_StorageClassTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_TapePoolTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_TapeTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_MountPolicyTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_RequesterActivityMountRuleTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_RequesterMountRuleTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_RequesterGroupMountRuleTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_LogicalLibraryTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_TapeFileTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_FileRecycleLogTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_DriveConfigTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_DriveStateTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); +INSTANTIATE_TEST_CASE_P(DbConfigFile, cta_catalogue_ArchiveFileTest, ::testing::Values(&g_catalogueFactoryForUnitTests)); + +} // namespace unitTests diff --git a/catalogue/tests/DriveConfigCatalogueTest.cpp b/catalogue/tests/DriveConfigCatalogueTest.cpp new file mode 100644 index 0000000000..53aa7b4efc --- /dev/null +++ b/catalogue/tests/DriveConfigCatalogueTest.cpp @@ -0,0 +1,287 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/tests/DriveConfigCatalogueTest.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" +#include "common/SourcedParameter.hpp" + +namespace unitTests { + +cta_catalogue_DriveConfigTest::cta_catalogue_DriveConfigTest() + : m_dummyLog("dummy", "dummy") { +} + +void cta_catalogue_DriveConfigTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + try { + cta::catalogue::CatalogueFactory *const *const catalogueFactoryPtrPtr = GetParam(); + + if (nullptr == catalogueFactoryPtrPtr) { + throw cta::exception::Exception("Global pointer to the catalogue factory pointer for unit-tests in null"); + } + + if (nullptr == (*catalogueFactoryPtrPtr)) { + throw cta::exception::Exception("Global pointer to the catalogue factoryfor unit-tests in null"); + } + + m_catalogue = (*catalogueFactoryPtrPtr)->create(); + + { + const auto configurationTapeNamesAndKeys = m_catalogue->DriveConfig()->getTapeDriveConfigNamesAndKeys(); + for (const auto& nameAndKey : configurationTapeNamesAndKeys) { + m_catalogue->DriveConfig()->deleteTapeDriveConfig(nameAndKey.first, nameAndKey.second); + } + } + } catch(cta::exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +void cta_catalogue_DriveConfigTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DriveConfigTest, getTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, getAllDrivesConfigs) { + std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> tapeDriveConfigs; + // Create 100 tape drives + for (size_t i = 0; i < 100; i++) { + std::stringstream ss; + ss << "VDSTK" << std::setw(5) << std::setfill('0') << i; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(ss.str(), daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + tapeDriveConfigs.push_back({ss.str(), daemonUserName.category(), daemonUserName.key(), daemonUserName.value(), + daemonUserName.source()}); + cta::SourcedParameter<std::string> defaultConfig { + "taped", "defaultConfig", "cta", "Random Default Config for Testing"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(ss.str(), defaultConfig.category(), defaultConfig.key(), + defaultConfig.value(), defaultConfig.source()); + tapeDriveConfigs.push_back({ss.str(), defaultConfig.category(), defaultConfig.key(), defaultConfig.value(), + defaultConfig.source()}); + } + const auto drivesConfigs = m_catalogue->DriveConfig()->getTapeDriveConfigs(); + ASSERT_EQ(tapeDriveConfigs.size(), drivesConfigs.size()); + for (const auto& dc : drivesConfigs) { + m_catalogue->DriveConfig()->deleteTapeDriveConfig(dc.tapeDriveName, dc.keyName); + } +} + +TEST_P(cta_catalogue_DriveConfigTest, setSourcedParameterWithEmptyValue) { + const std::string tapeDriveName = "VDSTK11"; + + cta::SourcedParameter<std::string> raoLtoOptions { + "taped", "RAOLTOAlgorithmOptions", "", "Compile time default" + }; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, raoLtoOptions.category(), raoLtoOptions.key(), + raoLtoOptions.value(), raoLtoOptions.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, raoLtoOptions.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(raoLtoOptions.category(), category); + ASSERT_EQ("", value); + ASSERT_EQ(raoLtoOptions.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, raoLtoOptions.key()); + + cta::SourcedParameter<std::string> backendPath{ + "ObjectStore", "BackendPath"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, backendPath.category(), backendPath.key(), + backendPath.value(), backendPath.source()); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, backendPath.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(backendPath.category(), category); + ASSERT_EQ("", value); + ASSERT_EQ("", source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, backendPath.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, failTogetTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const std::string wrongKey = "wrongKey"; + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(wrongName, daemonUserName.key()); + ASSERT_FALSE(driveConfig); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, wrongKey); + ASSERT_FALSE(driveConfig); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(wrongName, wrongKey); + ASSERT_FALSE(driveConfig); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, failTodeleteTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const std::string wrongKey = "wrongKey"; + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(wrongName, daemonUserName.key()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, wrongKey); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(wrongName, wrongKey); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + // Good deletion + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_FALSE(driveConfig); +} + +TEST_P(cta_catalogue_DriveConfigTest, multipleDriveConfig) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + cta::SourcedParameter<std::string> daemonGroupName { + "taped", "DaemonGroupName", "tape", "Compile time default"}; + + // Combinations of tapeDriveName1/2 and daemonUserName and daemonGroupName + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + auto driveConfig1UserName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName1, daemonUserName.key()); + auto driveConfig2UserName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName2, daemonUserName.key()); + auto driveConfig1GroupName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName1, daemonGroupName.key()); + auto driveConfig2GroupName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName2, daemonGroupName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig1UserName)); + ASSERT_TRUE(static_cast<bool>(driveConfig2UserName)); + ASSERT_TRUE(static_cast<bool>(driveConfig1GroupName)); + ASSERT_TRUE(static_cast<bool>(driveConfig2GroupName)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig1UserName.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + std::tie(category, value, source) = driveConfig2UserName.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + std::tie(category, value, source) = driveConfig1GroupName.value(); + ASSERT_EQ(daemonGroupName.category(), category); + ASSERT_EQ(daemonGroupName.value(), value); + ASSERT_EQ(daemonGroupName.source(), source); + std::tie(category, value, source) = driveConfig2GroupName.value(); + ASSERT_EQ(daemonGroupName.category(), category); + ASSERT_EQ(daemonGroupName.value(), value); + ASSERT_EQ(daemonGroupName.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName1, daemonUserName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName1, daemonGroupName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName2, daemonUserName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName2, daemonGroupName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, getNamesAndKeysOfMultipleDriveConfig) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + cta::SourcedParameter<std::string> daemonGroupName { + "taped", "DaemonGroupName", "tape", "Compile time default"}; + + // Combinations of tapeDriveName1/2 and daemonUserName and daemonGroupName + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + + const auto configurationTapeNamesAndKeys = m_catalogue->DriveConfig()->getTapeDriveConfigNamesAndKeys(); + + for (const auto& nameAndKey : configurationTapeNamesAndKeys) { + m_catalogue->DriveConfig()->deleteTapeDriveConfig(nameAndKey.first, nameAndKey.second); + } +} + +TEST_P(cta_catalogue_DriveConfigTest, modifyTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + // Both share same key + cta::SourcedParameter<std::string> daemonUserName1 { + "taped1", "DaemonUserName", "cta1", "Compile time1 default"}; + cta::SourcedParameter<std::string> daemonUserName2 { + "taped2", "DaemonUserName", "cta2", "Compile time2 default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName1.category(), daemonUserName1.key(), + daemonUserName1.value(), daemonUserName1.source()); + const auto driveConfig1 = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName1.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig1)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig1.value(); + ASSERT_NE(daemonUserName2.category(), category); + ASSERT_NE(daemonUserName2.value(), value); + ASSERT_NE(daemonUserName2.source(), source); + m_catalogue->DriveConfig()->modifyTapeDriveConfig(tapeDriveName, daemonUserName2.category(), daemonUserName2.key(), + daemonUserName2.value(), daemonUserName2.source()); + const auto driveConfig2 = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName1.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig2)); + std::tie(category, value, source) = driveConfig2.value(); + ASSERT_EQ(daemonUserName2.category(), category); + ASSERT_EQ(daemonUserName2.value(), value); + ASSERT_EQ(daemonUserName2.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName1.key()); +} + +} // namespace unitTests diff --git a/catalogue/tests/DriveConfigCatalogueTest.hpp b/catalogue/tests/DriveConfigCatalogueTest.hpp new file mode 100644 index 0000000000..c03102f6c9 --- /dev/null +++ b/catalogue/tests/DriveConfigCatalogueTest.hpp @@ -0,0 +1,42 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DriveConfigTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DriveConfigTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; +}; + +} // namespace unitTests diff --git a/catalogue/tests/DriveStateCatalogueTest.cpp b/catalogue/tests/DriveStateCatalogueTest.cpp new file mode 100644 index 0000000000..743c1fa550 --- /dev/null +++ b/catalogue/tests/DriveStateCatalogueTest.cpp @@ -0,0 +1,1547 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/TapeDrivesCatalogueState.hpp" +#include "catalogue/tests/DriveStateCatalogueTest.hpp" +#include "common/dataStructures/DesiredDriveState.hpp" +#include "common/dataStructures/DriveInfo.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" +#include "common/SourcedParameter.hpp" + +namespace unitTests { + +namespace { +cta::common::dataStructures::SecurityIdentity getAdmin() { + cta::common::dataStructures::SecurityIdentity admin; + admin.username = "admin_user_name"; + admin.host = "admin_host"; + return admin; +} + +cta::common::dataStructures::TapeDrive getTapeDriveWithMandatoryElements(const std::string &driveName) { + cta::common::dataStructures::TapeDrive tapeDrive; + tapeDrive.driveName = driveName; + tapeDrive.host = "admin_host"; + tapeDrive.logicalLibrary = "VLSTK10"; + tapeDrive.mountType = cta::common::dataStructures::MountType::NoMount; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + tapeDrive.desiredUp = false; + tapeDrive.desiredForceDown = false; + return tapeDrive; +} + +cta::common::dataStructures::TapeDrive getTapeDriveWithAllElements(const std::string &driveName) { + cta::common::dataStructures::TapeDrive tapeDrive; + tapeDrive.driveName = driveName; + tapeDrive.host = "admin_host"; + tapeDrive.logicalLibrary = "VLSTK10"; + tapeDrive.mountType = cta::common::dataStructures::MountType::NoMount; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + tapeDrive.desiredUp = false; + tapeDrive.desiredForceDown = false; + tapeDrive.diskSystemName = "dummyDiskSystemName"; + tapeDrive.reservedBytes = 694498291384; + tapeDrive.reservationSessionId = 0; + + tapeDrive.sessionStartTime = 1001; + tapeDrive.mountStartTime = 1002; + tapeDrive.transferStartTime = 1003; + tapeDrive.unloadStartTime = 1004; + tapeDrive.unmountStartTime = 1005; + tapeDrive.drainingStartTime = 1006; + tapeDrive.downOrUpStartTime = 1007; + tapeDrive.probeStartTime = 1008; + tapeDrive.cleanupStartTime = 1009; + tapeDrive.startStartTime = 1010; + tapeDrive.shutdownTime = 1011; + + tapeDrive.reasonUpDown = "Random Reason"; + + tapeDrive.currentVid = "VIDONE"; + tapeDrive.ctaVersion = "v1.0.0"; + tapeDrive.currentPriority = 3; + tapeDrive.currentActivity = "Activity1"; + tapeDrive.currentTapePool = "tape_pool_0"; + tapeDrive.nextMountType = cta::common::dataStructures::MountType::Retrieve; + tapeDrive.nextVid = "VIDTWO"; + tapeDrive.nextTapePool = "tape_pool_1"; + tapeDrive.nextPriority = 1; + tapeDrive.nextActivity = "Activity2"; + + tapeDrive.devFileName = "fileName"; + tapeDrive.rawLibrarySlot = "librarySlot1"; + + tapeDrive.currentVo = "VO_ONE"; + tapeDrive.nextVo = "VO_TWO"; + + tapeDrive.userComment = "Random comment"; + tapeDrive.creationLog = cta::common::dataStructures::EntryLog("user_name_1", "host_1", 100002); + tapeDrive.lastModificationLog = cta::common::dataStructures::EntryLog("user_name_2", "host_2", 10032131); + + return tapeDrive; +} +} // namespace + +cta_catalogue_DriveStateTest::cta_catalogue_DriveStateTest() + : m_dummyLog("dummy", "dummy"), + m_admin(getAdmin()) { +} + +void cta_catalogue_DriveStateTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + try { + cta::catalogue::CatalogueFactory *const *const catalogueFactoryPtrPtr = GetParam(); + + if (nullptr == catalogueFactoryPtrPtr) { + throw cta::exception::Exception("Global pointer to the catalogue factory pointer for unit-tests in null"); + } + + if (nullptr == (*catalogueFactoryPtrPtr)) { + throw cta::exception::Exception("Global pointer to the catalogue factoryfor unit-tests in null"); + } + + m_catalogue = (*catalogueFactoryPtrPtr)->create(); + + { + const auto tapeDriveNames = m_catalogue->DriveState()->getTapeDriveNames(); + for (const auto& name : tapeDriveNames) { + m_catalogue->DriveState()->deleteTapeDrive(name); + } + } + } catch(cta::exception::Exception &ex) { + ex.getMessage().str(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + throw; + } +} + +void cta_catalogue_DriveStateTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveNames) { + const std::list<std::string> tapeDriveNames = {"VDSTK11", "VDSTK12", "VDSTK21", "VDSTK22"}; + for (const auto& name : tapeDriveNames) { + const auto tapeDrive = getTapeDriveWithMandatoryElements(name); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + } + const auto storedTapeDriveNames = m_catalogue->DriveState()->getTapeDriveNames(); + ASSERT_EQ(tapeDriveNames, storedTapeDriveNames); + for (const auto& name : tapeDriveNames) { + m_catalogue->DriveState()->deleteTapeDrive(name); + } +} + +TEST_P(cta_catalogue_DriveStateTest, getAllTapeDrives) { + std::list<std::string> tapeDriveNames; + // Create 100 tape drives + for (size_t i = 0; i < 100; i++) { + std::stringstream ss; + ss << "VDSTK" << std::setw(5) << std::setfill('0') << i; + tapeDriveNames.push_back(ss.str()); + } + std::list<cta::common::dataStructures::TapeDrive> tapeDrives; + for (const auto& name : tapeDriveNames) { + const auto tapeDrive = getTapeDriveWithMandatoryElements(name); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + tapeDrives.push_back(tapeDrive); + } + auto storedTapeDrives = m_catalogue->DriveState()->getTapeDrives(); + ASSERT_EQ(tapeDriveNames.size(), storedTapeDrives.size()); + while (!storedTapeDrives.empty()) { + const auto storedTapeDrive = storedTapeDrives.front(); + const auto tapeDrive = tapeDrives.front(); + storedTapeDrives.pop_front(); + tapeDrives.pop_front(); + ASSERT_EQ(tapeDrive, storedTapeDrive); + } + for (const auto& name : tapeDriveNames) { + m_catalogue->DriveState()->deleteTapeDrive(name); + } +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive, storedTapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithEmptyEntryLog) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.creationLog = cta::common::dataStructures::EntryLog("", "", 0); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().creationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithNonExistingLogicalLibrary) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().logicalLibraryDisabled); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithDisabledLogicalLibrary) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->createLogicalLibrary(m_admin, tapeDrive.logicalLibrary, true, "comment"); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(storedTapeDrive.value().logicalLibraryDisabled); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); + m_catalogue->deleteLogicalLibrary(tapeDrive.logicalLibrary); +} + + +TEST_P(cta_catalogue_DriveStateTest, failToGetTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(wrongName); + ASSERT_FALSE(storedTapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(tapeDriveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToDeleteTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(wrongName); + auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + m_catalogue->DriveState()->deleteTapeDrive(tapeDriveName); + storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithAllElements) { + const std::string tapeDriveName = "VDSTK11"; + const auto tapeDrive = getTapeDriveWithAllElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive, storedTapeDrive.value()); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, multipleTapeDrives) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + const auto tapeDrive1 = getTapeDriveWithMandatoryElements(tapeDriveName1); + const auto tapeDrive2 = getTapeDriveWithAllElements(tapeDriveName2); + m_catalogue->DriveState()->createTapeDrive(tapeDrive1); + m_catalogue->DriveState()->createTapeDrive(tapeDrive2); + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive1.driveName); + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive2.driveName); + ASSERT_EQ(tapeDrive1, storedTapeDrive1); + ASSERT_EQ(tapeDrive2, storedTapeDrive2); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive1.driveName); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive2.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateEmpty) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.reasonUpDown = "Previous reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + { + cta::common::dataStructures::DesiredDriveState desiredState; + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), tapeDrive.reasonUpDown.value()); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateWithEmptyReason) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + { + cta::common::dataStructures::DesiredDriveState desiredState; + desiredState.reason = ""; + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + // SqlLite (InMemory) returns an empty string and Oracle returns a std::nullopt + if (storedTapeDrive.value().reasonUpDown) { + ASSERT_TRUE(storedTapeDrive.value().reasonUpDown.value().empty()); + } else { + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + } + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredState) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason"; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , desiredState.up); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , desiredState.forceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , desiredState.reason); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateComment) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + // It should keep this Desired Status + tapeDrive.desiredUp = true; + tapeDrive.desiredForceDown = false; + tapeDrive.reasonUpDown = "reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + // It should update only the comment + const std::string comment = "New Comment"; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason2"; + desiredState.comment = comment; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , tapeDrive.desiredUp); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , tapeDrive.desiredForceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , tapeDrive.reasonUpDown); + ASSERT_EQ(storedTapeDrive.value().userComment.value() , comment); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateEmptyComment) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + // It should keep this Desired Status + tapeDrive.desiredUp = true; + tapeDrive.desiredForceDown = false; + tapeDrive.reasonUpDown = "reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + // It should update only the comment + const std::string comment = ""; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason2"; + desiredState.comment = comment; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , tapeDrive.desiredUp); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , tapeDrive.desiredForceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , tapeDrive.reasonUpDown); + // SqlLite (InMemory) returns an empty string and Oracle returns a std::nullopt + if (storedTapeDrive.value().userComment) { + ASSERT_TRUE(storedTapeDrive.value().userComment.value().empty()); + } else { + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().userComment)); + } + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setTapeDriveStatistics) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Transferring; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatsInputs inputs; + inputs.reportTime = time(nullptr); + inputs.bytesTransferred = 123456789; + inputs.filesTransferred = 987654321; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatistics(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().bytesTransferedInSession.value(), inputs.bytesTransferred); + ASSERT_EQ(storedTapeDrive.value().filesTransferedInSession.value(), inputs.filesTransferred); + const auto lastModificationLog = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, + inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value() , lastModificationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setTapeDriveStatisticsInNoTransferingStatus) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::ReportDriveStatsInputs inputs; + inputs.reportTime = time(nullptr); + inputs.bytesTransferred = 123456789; + inputs.filesTransferred = 987654321; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatistics(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().bytesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().filesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().lastModificationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusSameAsPrevious) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + // We update keeping the same status, so it has to update only the lastModificationLog + cta::ReportDriveStatusInputs inputs; + inputs.status = tapeDrive.driveStatus; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 123456; + inputs.filesTransferred = 987654; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(driveInfo.driveName, storedTapeDrive.value().driveName); + ASSERT_EQ(inputs.status, storedTapeDrive.value().driveStatus); + ASSERT_NE(inputs.mountType, storedTapeDrive.value().mountType); // Not update this value + ASSERT_EQ(driveInfo.host, storedTapeDrive.value().host); + ASSERT_EQ(driveInfo.logicalLibrary, storedTapeDrive.value().logicalLibrary); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(log, storedTapeDrive.value().lastModificationLog.value()); + ASSERT_FALSE(storedTapeDrive.value().bytesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().filesTransferedInSession); + // Disk reservations are not updated by updateTapeDriveStatus() + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusSameTransferingAsPrevious) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Transferring; + tapeDrive.sessionStartTime = time(nullptr); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto test = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive.sessionStartTime, test.value().sessionStartTime.value()); + // We update keeping the same status, so it has to update only the lastModificationLog + const uint64_t elapsedTime = 1000; + cta::ReportDriveStatusInputs inputs; + inputs.status = tapeDrive.driveStatus; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = tapeDrive.sessionStartTime.value() + elapsedTime; + inputs.mountSessionId = 0; + inputs.byteTransferred = 123456; + inputs.filesTransferred = 987654; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(driveInfo.driveName, storedTapeDrive.value().driveName); + ASSERT_EQ(inputs.status, storedTapeDrive.value().driveStatus); + ASSERT_NE(inputs.mountType, storedTapeDrive.value().mountType); // Not update this value + ASSERT_EQ(driveInfo.host, storedTapeDrive.value().host); + ASSERT_EQ(driveInfo.logicalLibrary, storedTapeDrive.value().logicalLibrary); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(log, storedTapeDrive.value().lastModificationLog.value()); + ASSERT_EQ(inputs.byteTransferred, storedTapeDrive.value().bytesTransferedInSession.value()); + ASSERT_EQ(inputs.filesTransferred, storedTapeDrive.value().filesTransferedInSession.value()); + // It will keep names and bytes, because it isn't in state UP + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + // Check elapsed time + ASSERT_EQ(storedTapeDrive.value().sessionElapsedTime.value(), inputs.reportTime - tapeDrive.sessionStartTime.value()); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusDown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Down; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_EQ(storedTapeDrive.value().downOrUpStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, cta::common::dataStructures::MountType::NoMount); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Down); + ASSERT_EQ(storedTapeDrive.value().desiredUp, false); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown, false); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), inputs.reason); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUp) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.desiredUp = true; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_EQ(storedTapeDrive.value().downOrUpStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, cta::common::dataStructures::MountType::NoMount); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Up); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpButDesiredIsDown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::DrainingToDisk; // To force a change of state + tapeDrive.desiredUp = false; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Down); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), inputs.reason); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpCleanSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + tapeDrive.diskSystemName = "DISK_SYSTEM_NAME"; + tapeDrive.reservedBytes = 123456789; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpDontCleanSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusProbing) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Probing; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_EQ(storedTapeDrive.value().probeStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusStarting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Starting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_EQ(storedTapeDrive.value().sessionStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_EQ(storedTapeDrive.value().currentActivity.value(), inputs.activity); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusMounting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Mounting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_EQ(storedTapeDrive.value().mountStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusTransfering) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Transferring; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_EQ(storedTapeDrive.value().bytesTransferedInSession.value(), inputs.byteTransferred); + ASSERT_EQ(storedTapeDrive.value().filesTransferedInSession.value(), inputs.filesTransferred); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_EQ(storedTapeDrive.value().sessionElapsedTime.value(), 0); // Because it's starting + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_EQ(storedTapeDrive.value().transferStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUnloading) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Unloading; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_EQ(storedTapeDrive.value().unloadStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUnmounting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Unmounting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_EQ(storedTapeDrive.value().unmountStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusDrainingToDisk) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::DrainingToDisk; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_EQ(storedTapeDrive.value().drainingStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusCleaningUp) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::CleaningUp; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_EQ(storedTapeDrive.value().cleanupStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusShutdown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Shutdown; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_EQ(storedTapeDrive.value().shutdownTime.value(), inputs.reportTime); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + + +TEST_P(cta_catalogue_DriveStateTest, addDiskSpaceReservationWhenItsNull) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = "space1"; + const uint64_t reservedBytes = 987654; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 123; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, incrementAnExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 852; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes + tapeDrive.reservedBytes.value()); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, decrementANonExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = "space1"; + const uint64_t reservedBytes = 852; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 123; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, decrementAExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request1; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 852; + request1.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request1, dummyLc); + + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive1.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive1.value().reservedBytes.value(), tapeDrive.reservedBytes.value() - reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive1.value().reservationSessionId.value(), mountId); + + cta::DiskSpaceReservationRequest request2; + request2.addRequest(tapeDrive.diskSystemName.value(), tapeDrive.reservedBytes.value() - reservedBytes); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request2, dummyLc); + + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive2.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive2.value().reservedBytes.value(), 0); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive2.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, incrementAnExistingDiskSpaceReservationAndThenLargerDecrement) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 10; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest increaseRequest; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 20; + increaseRequest.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, increaseRequest, dummyLc); + + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive1.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive1.value().reservedBytes.value(), reservedBytes + tapeDrive.reservedBytes.value()); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive1.value().reservationSessionId.value(), mountId); + + cta::DiskSpaceReservationRequest decreaseRequest; + decreaseRequest.addRequest(tapeDrive.diskSystemName.value(), 100000); // Decrease a bigger number of reserved bytes + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, decreaseRequest, dummyLc); + + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive2.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive2.value().reservedBytes.value(), 0); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive2.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToIncrementAnOldDiskSystem) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "old_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest newRequest; + const std::string spaceName = "new_space"; + const uint64_t reservedBytes = 345; + newRequest.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, newRequest, dummyLc); + + // Decrease Old Space + cta::DiskSpaceReservationRequest oldRequest; + oldRequest.addRequest(tapeDrive.diskSystemName.value(), tapeDrive.reservedBytes.value()); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, tapeDrive.reservationSessionId.value(), oldRequest, + dummyLc); + + // Check it keeps the new disk space system values + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, sameSystemNameButDifferentMountID) { + const std::string tapeDriveName = "VDSTK11"; + const std::string diskSystemName = "space_name"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = diskSystemName; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest request; + const std::string spaceName = diskSystemName; + const uint64_t reservedBytes = 345; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + // Check it keeps the new disk space system values + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToDecrementAnOldMountIDAndDecrementNewAgain) { + const std::string tapeDriveName = "VDSTK11"; + const std::string diskSystemName = "space_name"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = diskSystemName; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest newRequest; + const uint64_t reservedBytes = 345; + newRequest.addRequest(diskSystemName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, newRequest, dummyLc); + + // Decrease Old Space + cta::DiskSpaceReservationRequest oldRequest; + oldRequest.addRequest(diskSystemName, tapeDrive.reservedBytes.value()); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, tapeDrive.reservationSessionId.value(), oldRequest, dummyLc); + + // Check it keeps the new disk space system values + auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + // Decrease New Space + cta::DiskSpaceReservationRequest decreaseRequest; + const uint64_t decreasedBytes = 10; + decreaseRequest.addRequest(diskSystemName, decreasedBytes); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, decreaseRequest, dummyLc); + + // Check it keeps the new disk space system values + storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes - decreasedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +} // namespace unitTests diff --git a/catalogue/tests/DriveStateCatalogueTest.hpp b/catalogue/tests/DriveStateCatalogueTest.hpp new file mode 100644 index 0000000000..1d9f1aa16e --- /dev/null +++ b/catalogue/tests/DriveStateCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DriveStateTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DriveStateTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/InMemoryCatalogueTest.cpp b/catalogue/tests/InMemoryCatalogueTest.cpp similarity index 94% rename from catalogue/InMemoryCatalogueTest.cpp rename to catalogue/tests/InMemoryCatalogueTest.cpp index 1686837930..650ea4affa 100644 --- a/catalogue/InMemoryCatalogueTest.cpp +++ b/catalogue/tests/InMemoryCatalogueTest.cpp @@ -16,6 +16,7 @@ */ #include "catalogue/InMemoryCatalogue.hpp" +#include "catalogue/rdbms/RdbmsSchemaCatalogue.hpp" #include "common/log/DummyLogger.hpp" #include <gtest/gtest.h> @@ -58,7 +59,7 @@ TEST_F(cta_catalogue_InMemoryCatalogue, schemaTables) { const uint64_t nbArchiveFileListingConns = 0; catalogue::InMemoryCatalogue inMemoryCatalogue(dummyLog, nbConns, nbArchiveFileListingConns); - const auto tableNameList = inMemoryCatalogue.getTableNames(); + const auto tableNameList = static_cast<catalogue::RdbmsSchemaCatalogue*>(inMemoryCatalogue.Schema().get())->getTableNames(); std::set<std::string> tableNameSet; std::map<std::string, uint32_t> tableNameToListPos; diff --git a/catalogue/tests/InMemoryVersionOfCatalogueTest.cpp b/catalogue/tests/InMemoryVersionOfCatalogueTest.cpp new file mode 100644 index 0000000000..3550827235 --- /dev/null +++ b/catalogue/tests/InMemoryVersionOfCatalogueTest.cpp @@ -0,0 +1,88 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include "catalogue/InMemoryCatalogueFactory.hpp" +#include "catalogue/tests/modules/AdminUserCatalogueTest.hpp" +#include "catalogue/tests/modules/ArchiveFileCatalogueTest.hpp" +#include "catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskInstanceCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp" +#include "catalogue/tests/modules/DiskSystemCatalogueTest.hpp" +#include "catalogue/tests/modules/DriveConfigCatalogueTest.hpp" +#include "catalogue/tests/modules/DriveStateCatalogueTest.hpp" +#include "catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp" +#include "catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp" +#include "catalogue/tests/modules/MediaTypeCatalogueTest.hpp" +#include "catalogue/tests/modules/MountPolicyCatalogueTest.hpp" +#include "catalogue/tests/modules/RequesterActivityMountRuleTest.hpp" +#include "catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp" +#include "catalogue/tests/modules/RequesterMountRuleTest.hpp" +#include "catalogue/tests/modules/SchemaCatalogueTest.hpp" +#include "catalogue/tests/modules/StorageClassCatalogueTest.hpp" +#include "catalogue/tests/modules/TapeCatalogueTest.hpp" +#include "catalogue/tests/modules/TapeFileCatalogueTest.hpp" +#include "catalogue/tests/modules/TapePoolCatalogueTest.hpp" +#include "catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp" +#ifdef STDOUT_LOGGING +#include "common/log/StdoutLogger.hpp" +#else +#include "common/log/DummyLogger.hpp" +#endif + +namespace unitTests { + +namespace { + +const uint64_t g_in_memory_CatalogueTest_nbConn = 1; +const uint64_t g_in_memory_nbArchiveFileListingConns = 1; +const uint64_t g_in_memory_maxTriesToConnect = 1; +#ifdef STDOUT_LOGGING +cta::log::StdoutLogger g_in_memory_CatalogueTest_dummyLogger("stdout", "stdout"); +#else +cta::log::DummyLogger g_in_memory_CatalogueTest_dummyLogger("dummy", "dummy"); +#endif + +cta::catalogue::InMemoryCatalogueFactory g_inMemoryCatalogueFactory(g_in_memory_CatalogueTest_dummyLogger, + g_in_memory_CatalogueTest_nbConn, g_in_memory_nbArchiveFileListingConns, g_in_memory_maxTriesToConnect); + +cta::catalogue::CatalogueFactory *g_inMemoryCatalogueFactoryPtr = &g_inMemoryCatalogueFactory; + +} // anonymous namespace + +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_SchemaTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_AdminUserTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_DiskSystemTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_DiskInstanceTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_DiskInstanceSpaceTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_VirtualOrganizationTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_ArchiveRouteTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_MediaTypeTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_StorageClassTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_TapePoolTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_TapeTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_MountPolicyTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_RequesterActivityMountRuleTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_RequesterMountRuleTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_RequesterGroupMountRuleTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_LogicalLibraryTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_TapeFileTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_FileRecycleLogTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_DriveConfigTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_DriveStateTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); +INSTANTIATE_TEST_CASE_P(InMemory, cta_catalogue_ArchiveFileTest, ::testing::Values(&g_inMemoryCatalogueFactoryPtr)); + +} // namespace unitTests diff --git a/catalogue/tests/modules/AdminUserCatalogueTest.cpp b/catalogue/tests/modules/AdminUserCatalogueTest.cpp new file mode 100644 index 0000000000..ad870eb9f1 --- /dev/null +++ b/catalogue/tests/modules/AdminUserCatalogueTest.cpp @@ -0,0 +1,214 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/AdminUserCatalogueTest.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_AdminUserTest::cta_catalogue_AdminUserTest() + : m_dummyLog("dummy", "dummy"), + m_localAdmin(CatalogueTestUtils::getLocalAdmin()), + m_admin(CatalogueTestUtils::getAdmin()) { +} + +void cta_catalogue_AdminUserTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_AdminUserTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_AdminUserTest, createAdminUser) { + const std::string createAdminUserComment = "Create admin user"; + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const auto& a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(createAdminUserComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } +} + +TEST_P(cta_catalogue_AdminUserTest, createAdminUser_same_twice) { + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, "comment 1"); + + ASSERT_THROW(m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, "comment 2"), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_AdminUserTest, deleteAdminUser) { + const std::string createAdminUserComment = "Create admin user"; + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const auto& a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(createAdminUserComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } + + m_catalogue->AdminUser()->deleteAdminUser(m_admin.username); + + ASSERT_TRUE(m_catalogue->AdminUser()->getAdminUsers().empty()); +} + +TEST_P(cta_catalogue_AdminUserTest, createAdminUser_emptyStringUsername) { + const std::string adminUsername = ""; + const std::string createAdminUserComment = "Create admin user"; + ASSERT_THROW(m_catalogue->AdminUser()->createAdminUser(m_localAdmin, adminUsername, createAdminUserComment), + cta::catalogue::UserSpecifiedAnEmptyStringUsername); +} + +TEST_P(cta_catalogue_AdminUserTest, createAdminUser_emptyStringComment) { + const std::string createAdminUserComment = ""; + ASSERT_THROW(m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_AdminUserTest, deleteAdminUser_non_existent) { + ASSERT_THROW(m_catalogue->AdminUser()->deleteAdminUser("non_existent_admin_user"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_AdminUserTest, modifyAdminUserComment) { + const std::string createAdminUserComment = "Create admin user"; + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const auto& a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(createAdminUserComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->AdminUser()->modifyAdminUserComment(m_localAdmin, m_admin.username, modifiedComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const auto& a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(modifiedComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } +} + +TEST_P(cta_catalogue_AdminUserTest, modifyAdminUserComment_emptyStringUsername) { + const std::string adminUsername = ""; + const std::string modifiedComment = "Modified comment"; + ASSERT_THROW(m_catalogue->AdminUser()->modifyAdminUserComment(m_localAdmin, adminUsername, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringUsername); +} + +TEST_P(cta_catalogue_AdminUserTest, modifyAdminUserComment_emptyStringComment) { + const std::string createAdminUserComment = "Create admin user"; + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const cta::common::dataStructures::AdminUser a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(createAdminUserComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } + + const std::string modifiedComment = ""; + ASSERT_THROW(m_catalogue->AdminUser()->modifyAdminUserComment(m_localAdmin, m_admin.username, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_AdminUserTest, modifyAdminUserComment_nonExtistentAdminUser) { + const std::string modifiedComment = "Modified comment"; + ASSERT_THROW(m_catalogue->AdminUser()->modifyAdminUserComment(m_localAdmin, m_admin.username, modifiedComment), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_AdminUserTest, isAdmin_false) { + ASSERT_FALSE(m_catalogue->AdminUser()->isAdmin(m_admin)); +} + +TEST_P(cta_catalogue_AdminUserTest, isAdmin_true) { + const std::string createAdminUserComment = "Create admin user"; + m_catalogue->AdminUser()->createAdminUser(m_localAdmin, m_admin.username, createAdminUserComment); + + { + std::list<cta::common::dataStructures::AdminUser> admins; + admins = m_catalogue->AdminUser()->getAdminUsers(); + ASSERT_EQ(1, admins.size()); + + const auto& a = admins.front(); + + ASSERT_EQ(m_admin.username, a.name); + ASSERT_EQ(createAdminUserComment, a.comment); + ASSERT_EQ(m_localAdmin.username, a.creationLog.username); + ASSERT_EQ(m_localAdmin.host, a.creationLog.host); + ASSERT_EQ(m_localAdmin.username, a.lastModificationLog.username); + ASSERT_EQ(m_localAdmin.host, a.lastModificationLog.host); + } + + ASSERT_TRUE(m_catalogue->AdminUser()->isAdmin(m_admin)); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/AdminUserCatalogueTest.hpp b/catalogue/tests/modules/AdminUserCatalogueTest.hpp new file mode 100644 index 0000000000..78a165fadb --- /dev/null +++ b/catalogue/tests/modules/AdminUserCatalogueTest.hpp @@ -0,0 +1,46 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_AdminUserTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_AdminUserTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_localAdmin; + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/ArchiveFileCatalogueTest.cpp b/catalogue/tests/modules/ArchiveFileCatalogueTest.cpp new file mode 100644 index 0000000000..87e75888ca --- /dev/null +++ b/catalogue/tests/modules/ArchiveFileCatalogueTest.cpp @@ -0,0 +1,4897 @@ +#include <gtest/gtest.h> + +#include <list> +#include <map> +#include <memory> +#include <set> +#include <string> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/TapeFileSearchCriteria.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/ArchiveFileCatalogueTest.hpp" +#include "common/dataStructures/AdminUser.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/ArchiveFileQueueCriteria.hpp" +#include "common/dataStructures/ArchiveFileSummary.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/RequesterGroupMountRule.hpp" +#include "common/dataStructures/RequesterIdentity.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/TapeFile.hpp" +#include "common/exception/FileSizeMismatch.hpp" +#include "common/exception/TapeFseqMismatch.hpp" +#include "common/exception/UserErrorWithCacheInfo.hpp" +#include "common/log/LogContext.hpp" +#include "common/threading/Mutex.hpp" +#include "common/threading/MutexLocker.hpp" +#include "common/threading/Thread.hpp" + +namespace unitTests { + +cta_catalogue_ArchiveFileTest::cta_catalogue_ArchiveFileTest() + : m_dummyLog("dummy", "dummy"), + m_tape1(CatalogueTestUtils::getTape1()), + m_tape2(CatalogueTestUtils::getTape2()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_storageClassDualCopy(CatalogueTestUtils::getStorageClassDualCopy()) { +} + +void cta_catalogue_ArchiveFileTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_ArchiveFileTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_no_archive_routes) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, + comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + + const std::string diskInstance = m_diskInstance.name; + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + ASSERT_THROW(m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstance, m_storageClassSingleCopy.name, + requesterIdentity), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_no_mount_rules) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + const std::string requesterName = "requester_name"; + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + ASSERT_THROW(m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstance, m_storageClassSingleCopy.name, + requesterIdentity), cta::exception::UserErrorWithCacheInfo); +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_after_cached_and_then_deleted_requester_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + // Get an archive ID which should pouplate for the first time the user mount + // rule cache + m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity); + + // Delete the user mount rule which should immediately invalidate the user + // mount rule cache + m_catalogue->RequesterMountRule()->deleteRequesterMountRule(diskInstanceName, requesterName); + + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + // Try to get an archive ID which should now fail because there is no user + // mount rule and the invalidated user mount rule cache should not hide this + // fact + ASSERT_THROW(m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, m_storageClassSingleCopy.name, requesterIdentity), cta::exception::UserErrorWithCacheInfo); +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_requester_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + std::set<uint64_t> archiveFileIds; + for(uint64_t i = 0; i<10; i++) { + const uint64_t archiveFileId = + m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity); + + const bool archiveFileIdIsNew = archiveFileIds.end() == archiveFileIds.find(archiveFileId); + ASSERT_TRUE(archiveFileIdIsNew); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_requester_group_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = "username"; + requesterIdentity.group = requesterGroupName; + + std::set<uint64_t> archiveFileIds; + for(uint64_t i = 0; i<10; i++) { + const uint64_t archiveFileId = m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, + m_storageClassSingleCopy.name, requesterIdentity); + + const bool archiveFileIdIsNew = archiveFileIds.end() == archiveFileIds.find(archiveFileId); + ASSERT_TRUE(archiveFileIdIsNew); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_after_cached_and_then_deleted_requester_group_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = "username"; + requesterIdentity.group = requesterGroupName; + + // Get an archive ID which should populate for the first time the group mount + // rule cache + m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity); + + // Delete the group mount rule which should immediately invalidate the group + // mount rule cache + m_catalogue->RequesterGroupMountRule()->deleteRequesterGroupMountRule(diskInstanceName, requesterGroupName); + + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + // Try to get an archive ID which should now fail because there is no group + // mount rule and the invalidated group mount rule cache should not hide this + // fact + ASSERT_THROW(m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity), cta::exception::UserErrorWithCacheInfo); +} + +TEST_P(cta_catalogue_ArchiveFileTest, checkAndGetNextArchiveFileId_requester_mount_rule_overide) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string requesterRuleComment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, + requesterRuleComment); + + const auto requesterRules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, requesterRules.size()); + + const cta::common::dataStructures::RequesterMountRule requesterRule = requesterRules.front(); + + ASSERT_EQ(requesterName, requesterRule.name); + ASSERT_EQ(mountPolicyName, requesterRule.mountPolicy); + ASSERT_EQ(requesterRuleComment, requesterRule.comment); + ASSERT_EQ(m_admin.username, requesterRule.creationLog.username); + ASSERT_EQ(m_admin.host, requesterRule.creationLog.host); + ASSERT_EQ(requesterRule.creationLog, requesterRule.lastModificationLog); + + const std::string requesterGroupRuleComment = "Create mount rule for requester group"; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterName, requesterGroupRuleComment); + + const auto requesterGroupRules = + m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, requesterGroupRules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule requesterGroupRule = requesterGroupRules.front(); + + ASSERT_EQ(requesterName, requesterGroupRule.name); + ASSERT_EQ(mountPolicyName, requesterGroupRule.mountPolicy); + ASSERT_EQ(requesterGroupRuleComment, requesterGroupRule.comment); + ASSERT_EQ(m_admin.username, requesterGroupRule.creationLog.username); + ASSERT_EQ(m_admin.host, requesterGroupRule.creationLog.host); + ASSERT_EQ(requesterGroupRule.creationLog, requesterGroupRule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + std::set<uint64_t> archiveFileIds; + for(uint64_t i = 0; i<10; i++) { + const uint64_t archiveFileId = m_catalogue->ArchiveFile()->checkAndGetNextArchiveFileId(diskInstanceName, + m_storageClassSingleCopy.name, requesterIdentity); + + const bool archiveFileIdIsNew = archiveFileIds.end() == archiveFileIds.find(archiveFileId); + ASSERT_TRUE(archiveFileIdIsNew); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFileQueueCriteria_no_archive_routes) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileQueueCriteria(diskInstanceName, m_storageClassSingleCopy.name, requesterIdentity), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFileQueueCriteria_requester_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + m_catalogue->ArchiveFile()->getArchiveFileQueueCriteria(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFileQueueCriteria_requester_group_mount_rule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = "username"; + requesterIdentity.group = requesterGroupName; + m_catalogue->ArchiveFile()->getArchiveFileQueueCriteria(diskInstanceName, m_storageClassSingleCopy.name, requesterIdentity); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFileQueueCriteria_requester_mount_rule_overide) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string requesterRuleComment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName, requesterName, + requesterRuleComment); + + const auto requesterRules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, requesterRules.size()); + + const cta::common::dataStructures::RequesterMountRule requesterRule = requesterRules.front(); + + ASSERT_EQ(requesterName, requesterRule.name); + ASSERT_EQ(mountPolicyName, requesterRule.mountPolicy); + ASSERT_EQ(requesterRuleComment, requesterRule.comment); + ASSERT_EQ(m_admin.username, requesterRule.creationLog.username); + ASSERT_EQ(m_admin.host, requesterRule.creationLog.host); + ASSERT_EQ(requesterRule.creationLog, requesterRule.lastModificationLog); + + const std::string requesterGroupRuleComment = "Create mount rule for requester group"; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterName, requesterGroupRuleComment); + + const auto requesterGroupRules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, requesterGroupRules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule requesterGroupRule = requesterGroupRules.front(); + + ASSERT_EQ(requesterName, requesterGroupRule.name); + ASSERT_EQ(mountPolicyName, requesterGroupRule.mountPolicy); + ASSERT_EQ(requesterGroupRuleComment, requesterGroupRule.comment); + ASSERT_EQ(m_admin.username, requesterGroupRule.creationLog.username); + ASSERT_EQ(m_admin.host, requesterGroupRule.creationLog.host); + ASSERT_EQ(requesterGroupRule.creationLog, requesterGroupRule.lastModificationLog); + + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string archiveRouteComment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, archiveRouteComment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(archiveRouteComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + m_catalogue->ArchiveFile()->getArchiveFileQueueCriteria(diskInstanceName, m_storageClassSingleCopy.name, + requesterIdentity); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFiles_non_existance_archiveFileId) { + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1234; + + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFiles_fSeq_without_vid) { + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.fSeq = 1234; + + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFiles_disk_file_id_without_instance) { + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + + cta::catalogue::TapeFileSearchCriteria searchCriteria; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("disk_file_id"); + searchCriteria.diskFileIds = diskFileIds; + + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFiles_existent_storage_class_without_disk_instance) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::list<cta::common::dataStructures::StorageClass> storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + { + const auto s = storageClasses.front(); + + ASSERT_EQ(m_storageClassSingleCopy.name, s.name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, s.nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, s.comment); + + const cta::common::dataStructures::EntryLog creationLog = s.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = s.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); +} + +TEST_P(cta_catalogue_ArchiveFileTest, getArchiveFiles_non_existent_vid) { + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = "non_existent_vid"; + + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, updateDiskFileId) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + const std::string newDiskFileId = "9012"; + m_catalogue->ArchiveFile()->updateDiskFileId(file1Written.archiveFileId, file1Written.diskInstance, newDiskFileId); + + { + const auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(newDiskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_many_archive_files) { + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + m_catalogue->Tape()->createTape(m_admin, tape1); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(1, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape2 = m_tape2; + tape2.tapePoolName = tapePoolName2; + m_catalogue->Tape()->createTape(m_admin, tape2); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(1, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + { + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const auto vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(tape1.vid); + ASSERT_NE(vidToTape.end(), it); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(tape1.vid, tape.vid); + ASSERT_EQ(tape1.mediaType, tape.mediaType); + ASSERT_EQ(tape1.vendor, tape.vendor); + ASSERT_EQ(tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(tapePoolName1, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(tape2.vid); + ASSERT_NE(vidToTape.end(), it); + const auto &tape = it->second; + ASSERT_EQ(tape2.vid, tape.vid); + ASSERT_EQ(tape2.mediaType, tape.mediaType); + ASSERT_EQ(tape2.vendor, tape.vendor); + ASSERT_EQ(tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + const std::string tapeDrive = "tape_drive"; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t nbArchiveFiles = 10; // Must be a multiple of 2 for this test + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + std::set<cta::catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + // Tape copy 1 written to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(2, tapes.size()); + { + auto it = vidToTape.find(tape1.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape1.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + { + auto it = vidToTape.find(tape2.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape2.vid, it->second.vid); + ASSERT_EQ(0, it->second.lastFSeq); + } + } + + std::set<cta::catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy2; + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + // Tape copy 2 written to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy2.emplace(fileWrittenUP.release()); + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy2); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(2, tapes.size()); + { + auto it = vidToTape.find(tape1.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape1.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + { + auto it = vidToTape.find(tape2.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape2.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + searchCriteria.diskInstance = diskInstance; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("12345678"); + searchCriteria.diskFileIds = diskFileIds; + searchCriteria.vid = tape1.vid; + + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + + const auto idAndFile = m.find(1); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(searchCriteria.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(searchCriteria.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(searchCriteria.diskFileIds->front(), archiveFile.diskFileId); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + ASSERT_EQ(searchCriteria.vid, archiveFile.tapeFiles.begin()->vid); + } + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten1.storageClassName = m_storageClassDualCopy.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = i; + fileWritten1.blockId = i * 100; + fileWritten1.copyNb = 1; + + cta::catalogue::TapeFileWritten fileWritten2 = fileWritten1; + fileWritten2.vid = tape2.vid; + fileWritten2.copyNb = 2; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(m_storageClassDualCopy.nbCopies, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + + // Tape copy 2 + { + const auto it = archiveFile.tapeFiles.find(2); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten2.vid, it->vid); + ASSERT_EQ(fileWritten2.fSeq, it->fSeq); + ASSERT_EQ(fileWritten2.blockId, it->blockId); + ASSERT_EQ(fileWritten2.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten2.copyNb, it->copyNb); + } + } + } + + // Look at all files on tape 1 + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = tape1.vid; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten1.storageClassName = m_storageClassDualCopy.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = i; + fileWritten1.blockId = i * 100; + fileWritten1.copyNb = 1; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + } + } + + // Look at all files on tape 1 + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = tape1.vid; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten1.storageClassName = m_storageClassDualCopy.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = i; + fileWritten1.blockId = i * 100; + fileWritten1.copyNb = 1; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + } + } + + // Look at all files on tape 2 + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = tape2.vid; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten2; + fileWritten2.archiveFileId = i; + fileWritten2.diskInstance = diskInstance; + fileWritten2.diskFileId = diskFileId.str(); + + fileWritten2.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten2.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten2.size = archiveFileSize; + fileWritten2.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten2.storageClassName = m_storageClassDualCopy.name; + fileWritten2.vid = tape2.vid; + fileWritten2.fSeq = i; + fileWritten2.blockId = i * 100; + fileWritten2.copyNb = 2; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten2.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten2.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten2.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten2.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten2.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten2.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten2.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten2.storageClassName, archiveFile.storageClass); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + // Tape copy 2 + { + const auto it = archiveFile.tapeFiles.find(2); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten2.vid, it->vid); + ASSERT_EQ(fileWritten2.fSeq, it->fSeq); + ASSERT_EQ(fileWritten2.blockId, it->blockId); + ASSERT_EQ(fileWritten2.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten2.copyNb, it->copyNb); + } + } + } + + { + const uint64_t startFseq = 1; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesForRepackItor(tape1.vid, startFseq); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten1.storageClassName = m_storageClassDualCopy.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = i; + fileWritten1.blockId = i * 100; + fileWritten1.copyNb = 1; + + cta::catalogue::TapeFileWritten fileWritten2 = fileWritten1; + fileWritten2.vid = tape2.vid; + fileWritten2.copyNb = 2; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(m_storageClassDualCopy.nbCopies, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + + // Tape copy 2 + { + const auto it = archiveFile.tapeFiles.find(2); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten2.vid, it->vid); + ASSERT_EQ(fileWritten2.fSeq, it->fSeq); + ASSERT_EQ(fileWritten2.blockId, it->blockId); + ASSERT_EQ(fileWritten2.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten2.copyNb, it->copyNb); + } + } + } + + for(uint32_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = 1; + const uint64_t maxNbFiles = nbArchiveFiles; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + for(uint32_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = 1; + const uint64_t maxNbFiles = nbArchiveFiles / 2; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles / 2, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles / 2; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + for(uint32_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = nbArchiveFiles / 2 + 1; + const uint64_t maxNbFiles = nbArchiveFiles / 2; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles / 2, m.size()); + + for(uint64_t i = nbArchiveFiles / 2 + 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 10; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + ASSERT_EQ(10, m.begin()->first); + ASSERT_EQ(10, m.begin()->second.archiveFileID); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(m_storageClassDualCopy.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(m_storageClassDualCopy.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.diskInstance = diskInstance; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * m_storageClassDualCopy.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles * m_storageClassDualCopy.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.diskInstance = diskInstance; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("12345687"); + searchCriteria.diskFileIds = diskFileIds; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + ASSERT_EQ("12345687", m.begin()->second.diskFileId); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(m_storageClassDualCopy.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(m_storageClassDualCopy.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * m_storageClassDualCopy.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles * m_storageClassDualCopy.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = tape1.vid; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = nbArchiveFiles + 1234; + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(0, summary.totalBytes); + ASSERT_EQ(0, summary.totalFiles); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->setTapeDisabled(m_admin, tape1.vid, "unit Test"); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(1, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(0, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::ACTIVE, std::nullopt, + std::nullopt); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, true); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(1, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(0, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, false); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(0, pool.nbEmptyTapes); + ASSERT_EQ(0, pool.nbDisabledTapes); + ASSERT_EQ(0, pool.nbFullTapes); + ASSERT_EQ(0, pool.nbReadOnlyTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } +} + + +TEST_P(cta_catalogue_ArchiveFileTest, DISABLED_concurrent_filesWrittenToTape_many_archive_files) { + std::unique_ptr<cta::catalogue::Catalogue> catalogue2; + + try { + cta::catalogue::CatalogueFactory *const *const catalogueFactoryPtrPtr = GetParam(); + + if(nullptr == catalogueFactoryPtrPtr) { + throw cta::exception::Exception("Global pointer to the catalogue factory pointer for unit-tests in null"); + } + + if(nullptr == (*catalogueFactoryPtrPtr)) { + throw cta::exception::Exception("Global pointer to the catalogue factoryfor unit-tests in null"); + } + + catalogue2 = (*catalogueFactoryPtrPtr)->create(); + + } catch(cta::exception::Exception &ex) { + throw cta::exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } + + class Barrier { + public: + Barrier(unsigned int count) : m_exited(false) { + pthread_barrier_init(&m_barrier, nullptr, count); + } + ~Barrier() { + pthread_barrier_destroy(&m_barrier); + } + void wait() { + pthread_barrier_wait(&m_barrier); + } + void exit() { + cta::threading::MutexLocker lock(m_mtx); + m_exited = true; + } + + bool hasExited() { + cta::threading::MutexLocker lock(m_mtx); + return m_exited; + } + + cta::threading::Mutex m_mtx; + pthread_barrier_t m_barrier; + bool m_exited; + }; + + class filesWrittenThread : public cta::threading::Thread { + public: + filesWrittenThread( + cta::catalogue::Catalogue *const cat, + Barrier &barrier, + const uint64_t nbArchiveFiles, + const uint64_t batchSize, + const cta::common::dataStructures::StorageClass &storageClass, + const uint64_t &archiveFileSize, + const cta::checksum::ChecksumBlob &checksumBlob, + const std::string &vid, + const uint64_t ©Nb, + const std::string &tapeDrive, + const std::string &diskInstance) : + m_cat(cat), m_barrier(barrier), m_nbArchiveFiles(nbArchiveFiles), m_batchSize(batchSize), m_storageClass(storageClass), m_archiveFileSize(archiveFileSize), + m_checksumBlob(checksumBlob), m_vid(vid), m_copyNb(copyNb), m_tapeDrive(tapeDrive),m_diskInstance(diskInstance) { } + + void run() override { + for(uint64_t batch=0;batch< 1 + (m_nbArchiveFiles-1)/m_batchSize;++batch) { + uint64_t bs = m_nbArchiveFiles - (m_batchSize*batch); + if (bs> m_batchSize) { + bs = m_batchSize; + } + std::set<cta::catalogue::TapeItemWrittenPointer> tapeFilesWritten; + for(uint64_t i= 0 ; i < bs; i++) { + // calculate this file's archive_file_id and fseq numbers + const uint64_t fn_afid = 1 + m_batchSize*batch + i; + const uint64_t fn_seq = (m_copyNb == 1) ? fn_afid : 1 + m_batchSize*batch + (bs-i-1); + std::ostringstream diskFileId; + diskFileId << (12345677 + fn_afid); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << fn_afid; + + // Tape this batch to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = fn_afid; + fileWritten.diskInstance = m_diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = m_archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClass.name; + fileWritten.vid = m_vid; + fileWritten.fSeq = fn_seq; + fileWritten.blockId = fn_seq * 100; + fileWritten.copyNb = m_copyNb; + fileWritten.tapeDrive = m_tapeDrive; + tapeFilesWritten.emplace(fileWrittenUP.release()); + } + m_barrier.wait(); + try { + m_cat->TapeFile()->filesWrittenToTape(tapeFilesWritten); + } catch(std::exception &) { + m_barrier.exit(); + m_barrier.wait(); + throw; + } + m_barrier.wait(); + if (m_barrier.hasExited()) { + return; + } + } + } + + cta::catalogue::Catalogue *const m_cat; + Barrier &m_barrier; + const uint64_t m_nbArchiveFiles; + const uint64_t m_batchSize; + const cta::common::dataStructures::StorageClass m_storageClass; + const uint64_t m_archiveFileSize; + const cta::checksum::ChecksumBlob m_checksumBlob; + const std::string m_vid; + const uint64_t m_copyNb; + const std::string m_tapeDrive; + const std::string m_diskInstance; + }; + + class filesWrittenRunner { + public: + filesWrittenRunner(filesWrittenThread &th) : m_th(th), m_waited(false) { m_th.start(); } + ~filesWrittenRunner() { + if (!m_waited) { + try { + m_th.wait(); + } catch(...) { + // nothing + } + } + } + void wait() { + m_waited = true; + m_th.wait(); + } + filesWrittenThread &m_th; + bool m_waited; + }; + + const std::string vid1 = "VID123"; + const std::string vid2 = "VID456"; + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + m_catalogue->Tape()->createTape(m_admin, tape1); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape2 = m_tape2; + tape2.tapePoolName = tapePoolName2; + m_catalogue->Tape()->createTape(m_admin, tape2); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + { + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const auto vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(vid1); + ASSERT_NE(vidToTape.end(), it); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(tape1.vid, tape.vid); + ASSERT_EQ(tape1.mediaType, tape.mediaType); + ASSERT_EQ(tape1.vendor, tape.vendor); + ASSERT_EQ(tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(tapePoolName1, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(vid2); + ASSERT_NE(vidToTape.end(), it); + const auto &tape = it->second; + ASSERT_EQ(tape2.vid, tape.vid); + ASSERT_EQ(tape2.mediaType, tape.mediaType); + ASSERT_EQ(tape2.vendor, tape.vendor); + ASSERT_EQ(tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(tapePoolName2, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + cta::common::dataStructures::StorageClass storageClass; + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapeDrive1 = "tape_drive1"; + const std::string tapeDrive2 = "tape_drive2"; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t nbArchiveFiles = 200; // Must be a multiple of batchsize for this test + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + const uint64_t batchsize = 20; + + cta::checksum::ChecksumBlob checksumBlob; + checksumBlob.insert(cta::checksum::ADLER32, "9876"); + + { + Barrier barrier(2); + filesWrittenThread a(m_catalogue.get(), barrier, nbArchiveFiles, batchsize, storageClass, archiveFileSize, checksumBlob, vid1, 1, tapeDrive1,diskInstance); + filesWrittenThread b(catalogue2.get(), barrier, nbArchiveFiles, batchsize, storageClass, archiveFileSize, checksumBlob, vid2, 2, tapeDrive2,diskInstance); + + filesWrittenRunner r1(a); + filesWrittenRunner r2(b); + r1.wait(); + r2.wait(); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName1); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName1, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(2, tapes.size()); + { + auto it = vidToTape.find(tape1.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape1.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + { + auto it = vidToTape.find(tape2.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape2.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(2, pools.size()); + + const auto tapePoolMap = CatalogueTestUtils::tapePoolListToMap(pools); + auto tapePoolMapItor = tapePoolMap.find(tapePoolName2); + ASSERT_NE(tapePoolMapItor, tapePoolMap.end()); + const auto &pool = tapePoolMapItor->second; + + ASSERT_EQ(tapePoolName2, pool.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, pool.dataBytes); + ASSERT_EQ(nbArchiveFiles, pool.nbPhysicalFiles); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(2, tapes.size()); + { + auto it = vidToTape.find(tape1.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape1.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + { + auto it = vidToTape.find(tape2.vid); + ASSERT_NE(vidToTape.end(), it); + ASSERT_EQ(tape2.vid, it->second.vid); + ASSERT_EQ(nbArchiveFiles, it->second.lastFSeq); + } + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + searchCriteria.diskInstance = diskInstance; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("12345678"); + searchCriteria.diskFileIds = diskFileIds; + searchCriteria.vid = tape1.vid; + + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + + const auto idAndFile = m.find(1); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(searchCriteria.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(searchCriteria.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(searchCriteria.diskFileIds->front(), archiveFile.diskFileId); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + ASSERT_EQ(searchCriteria.vid, archiveFile.tapeFiles.begin()->vid); + } + + auto afidToSeq = [](const uint64_t l_nbTot, const uint64_t l_batchsize, const uint64_t l_afid, uint64_t &l_seq1, uint64_t &l_seq2) { + l_seq1 = l_afid; + uint64_t batch = (l_afid-1)/l_batchsize; + uint64_t bidx = (l_afid-1)%l_batchsize; + uint64_t bs = l_nbTot - batch*l_batchsize; + if (bs>l_batchsize) { + bs = l_batchsize; + } + l_seq2 = batch*l_batchsize + (bs-bidx); + }; + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + std::map<uint64_t, cta::common::dataStructures::ArchiveFile> m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + uint64_t seq1,seq2; + afidToSeq(nbArchiveFiles, batchsize, i, seq1, seq2); + + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "2468"); + fileWritten1.storageClassName = storageClass.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = seq1; + fileWritten1.blockId = seq1 * 100; + fileWritten1.copyNb = 1; + + cta::catalogue::TapeFileWritten fileWritten2 = fileWritten1; + fileWritten2.vid = tape2.vid; + fileWritten2.fSeq = seq2; + fileWritten2.blockId = seq2 * 100; + fileWritten2.copyNb = 2; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(storageClass.nbCopies, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + + // Tape copy 2 + { + const auto it = archiveFile.tapeFiles.find(2); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten2.vid, it->vid); + ASSERT_EQ(fileWritten2.fSeq, it->fSeq); + ASSERT_EQ(fileWritten2.blockId, it->blockId); + ASSERT_EQ(fileWritten2.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten2.copyNb, it->copyNb); + } + } + } + + { + const uint64_t startFseq = 1; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesForRepackItor(tape1.vid, startFseq); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + uint64_t seq1,seq2; + afidToSeq(nbArchiveFiles, batchsize, i, seq1, seq2); + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten1; + fileWritten1.archiveFileId = i; + fileWritten1.diskInstance = diskInstance; + fileWritten1.diskFileId = diskFileId.str(); + + fileWritten1.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten1.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten1.size = archiveFileSize; + fileWritten1.checksumBlob.insert(cta::checksum::ADLER32, "2468"); + fileWritten1.storageClassName = storageClass.name; + fileWritten1.vid = tape1.vid; + fileWritten1.fSeq = seq1; + fileWritten1.blockId = seq1 * 100; + fileWritten1.copyNb = 1; + + cta::catalogue::TapeFileWritten fileWritten2 = fileWritten1; + fileWritten2.vid = tape2.vid; + fileWritten2.fSeq = seq2; + fileWritten2.blockId = seq2 * 100; + fileWritten2.copyNb = 2; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten1.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten1.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten1.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten1.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten1.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten1.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten1.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten1.storageClassName, archiveFile.storageClass); + ASSERT_EQ(storageClass.nbCopies, archiveFile.tapeFiles.size()); + + // Tape copy 1 + { + const auto it = archiveFile.tapeFiles.find(1); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten1.vid, it->vid); + ASSERT_EQ(fileWritten1.fSeq, it->fSeq); + ASSERT_EQ(fileWritten1.blockId, it->blockId); + ASSERT_EQ(fileWritten1.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten1.copyNb, it->copyNb); + } + + // Tape copy 2 + { + const auto it = archiveFile.tapeFiles.find(2); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten2.vid, it->vid); + ASSERT_EQ(fileWritten2.fSeq, it->fSeq); + ASSERT_EQ(fileWritten2.blockId, it->blockId); + ASSERT_EQ(fileWritten2.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten2.copyNb, it->copyNb); + } + } + } + + for(uint64_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = 1; + const uint64_t maxNbFiles = nbArchiveFiles; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + uint64_t seq1,seq2; + afidToSeq(nbArchiveFiles, batchsize, i, seq1, seq2); + uint64_t seq = (copyNb==1) ? seq1 : seq2; + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = storageClass.name; + fileWritten.vid = vid; + fileWritten.fSeq = seq; + fileWritten.blockId = seq * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + for(uint64_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = 1; + const uint64_t maxNbFiles = nbArchiveFiles / 2; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles / 2, m.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles / 2; i++) { + uint64_t seq1,seq2; + afidToSeq(nbArchiveFiles, batchsize, i, seq1, seq2); + uint64_t seq = (copyNb==1) ? seq1 : seq2; + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = storageClass.name; + fileWritten.vid = vid; + fileWritten.fSeq = seq; + fileWritten.blockId = seq * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + for(uint64_t copyNb = 1; copyNb <= 2; copyNb++) { + const std::string vid = copyNb == 1 ? tape1.vid : tape2.vid; + const uint64_t startFseq = nbArchiveFiles / 2 + 1; + const uint64_t maxNbFiles = nbArchiveFiles / 2; + const auto archiveFiles = m_catalogue->ArchiveFile()->getFilesForRepack(vid, startFseq, maxNbFiles); + const auto m = CatalogueTestUtils::archiveFileListToMap(archiveFiles); + ASSERT_EQ(nbArchiveFiles / 2, m.size()); + + for(uint64_t i = nbArchiveFiles / 2 + 1; i <= nbArchiveFiles; i++) { + uint64_t seq1,seq2; + afidToSeq(nbArchiveFiles, batchsize, i, seq1, seq2); + uint64_t seq = (copyNb==1) ? seq1 : seq2; + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + std::ostringstream diskFilePath; + diskFilePath << "/public_dir/public_file_" << i; + + cta::catalogue::TapeFileWritten fileWritten; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(cta::checksum::ADLER32, "1357"); + fileWritten.storageClassName = storageClass.name; + fileWritten.vid = vid; + fileWritten.fSeq = seq; + fileWritten.blockId = seq * 100; + fileWritten.copyNb = copyNb; + + const auto idAndFile = m.find(i); + ASSERT_NE(m.end(), idAndFile); + const cta::common::dataStructures::ArchiveFile archiveFile = idAndFile->second; + ASSERT_EQ(fileWritten.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(fileWritten.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(fileWritten.diskFileId, archiveFile.diskFileId); + + ASSERT_EQ(fileWritten.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(fileWritten.diskFileGid, archiveFile.diskFileInfo.gid); + ASSERT_EQ(fileWritten.size, archiveFile.fileSize); + ASSERT_EQ(fileWritten.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(fileWritten.storageClassName, archiveFile.storageClass); + + // There is only one tape copy because repack only want the tape file on a + // single tape + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + + { + const auto it = archiveFile.tapeFiles.find(copyNb); + ASSERT_NE(archiveFile.tapeFiles.end(), it); + ASSERT_EQ(fileWritten.vid, it->vid); + ASSERT_EQ(fileWritten.fSeq, it->fSeq); + ASSERT_EQ(fileWritten.blockId, it->blockId); + ASSERT_EQ(fileWritten.checksumBlob, it->checksumBlob); + ASSERT_EQ(fileWritten.copyNb, it->copyNb); + } + } + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 10; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + ASSERT_EQ(10, m.begin()->first); + ASSERT_EQ(10, m.begin()->second.archiveFileID); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(storageClass.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(storageClass.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.diskInstance = diskInstance; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * storageClass.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles * storageClass.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.diskInstance = diskInstance; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("12345687"); + searchCriteria.diskFileIds = diskFileIds; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + ASSERT_EQ("12345687", m.begin()->second.diskFileId); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(storageClass.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(storageClass.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.diskInstance = diskInstance; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + ASSERT_EQ("/public_dir/public_file_10", m.begin()->second.diskFileInfo.path); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(storageClass.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(storageClass.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * storageClass.nbCopies * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles * storageClass.nbCopies, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.vid = tape1.vid; + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(nbArchiveFiles, m.size()); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(nbArchiveFiles * archiveFileSize, summary.totalBytes); + ASSERT_EQ(nbArchiveFiles, summary.totalFiles); + } + + { + cta::catalogue::TapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = nbArchiveFiles + 1234; + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria), cta::exception::UserError); + + const cta::common::dataStructures::ArchiveFileSummary summary = m_catalogue->ArchiveFile()->getTapeFileSummary(searchCriteria); + ASSERT_EQ(0, summary.totalBytes); + ASSERT_EQ(0, summary.totalFiles); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_1_tape_copy) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_1_tape_copy_deleteStorageClass) { + const std::string diskInstance = m_diskInstance.name; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::catalogue::UserSpecifiedStorageClassUsedByArchiveFiles); + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_file_recycle_log_deleteStorageClass) { + cta::log::LogContext dummyLc(m_dummyLog); + + const std::string diskInstance = m_diskInstance.name; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + ASSERT_EQ(1, tapes.size()); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + cta::common::dataStructures::DeleteArchiveRequest deletedArchiveReq; + deletedArchiveReq.archiveFile = archiveFile; + deletedArchiveReq.diskInstance = diskInstance; + deletedArchiveReq.archiveFileID = archiveFileId; + deletedArchiveReq.diskFileId = file1Written.diskFileId; + deletedArchiveReq.recycleTime = time(nullptr); + deletedArchiveReq.requester = cta::common::dataStructures::RequesterIdentity(m_admin.username,"group"); + deletedArchiveReq.diskFilePath = "/path/"; + m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(deletedArchiveReq,dummyLc); + } + + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::catalogue::UserSpecifiedStorageClassUsedByFileRecycleLogs); + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::exception::UserError); + + { + //reclaim the tape to delete the files from the recycle log and delete the storage class + m_catalogue->Tape()->setTapeFull(m_admin,m_tape1.vid,true); + m_catalogue->Tape()->reclaimTape(m_admin,m_tape1.vid,dummyLc); + } + + ASSERT_NO_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name)); +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + ASSERT_EQ(2, m_catalogue->Tape()->getTapes().size()); + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file2Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_same_copy_number) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 1; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + ASSERT_EQ(2, m_catalogue->Tape()->getTapes().size()); + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file2Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + const auto &tapeFile = *archiveFile.tapeFiles.begin(); + + ASSERT_TRUE(file1Written.vid == tapeFile.vid || file2Written.vid == tapeFile.vid); + + { + const auto &fileWritten = file1Written.vid == tapeFile.vid ? file1Written : file2Written; + + ASSERT_EQ(fileWritten.vid, tapeFile.vid); + ASSERT_EQ(fileWritten.fSeq, tapeFile.fSeq); + ASSERT_EQ(fileWritten.blockId, tapeFile.blockId); + ASSERT_EQ(fileWritten.checksumBlob, tapeFile.checksumBlob); + ASSERT_EQ(fileWritten.copyNb, tapeFile.copyNb); + } + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_same_copy_number_same_tape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape1.vid; + file2Written.fSeq = 2; + file2Written.blockId = 4331; + file2Written.copyNb = 1; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + ASSERT_EQ(1, m_catalogue->Tape()->getTapes().size()); + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file2Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(2, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + const auto &tapeFile = *archiveFile.tapeFiles.begin(); + + ASSERT_TRUE(file1Written.fSeq == tapeFile.fSeq || file2Written.fSeq == tapeFile.fSeq); + + { + const auto &fileWritten = file1Written.fSeq == tapeFile.fSeq ? file1Written : file2Written; + + ASSERT_EQ(fileWritten.vid, tapeFile.vid); + ASSERT_EQ(fileWritten.fSeq, tapeFile.fSeq); + ASSERT_EQ(fileWritten.blockId, tapeFile.blockId); + ASSERT_EQ(fileWritten.checksumBlob, tapeFile.checksumBlob); + ASSERT_EQ(fileWritten.copyNb, tapeFile.copyNb); + } + } +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_same_fseq_same_tape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape1.vid; + file2Written.fSeq = file1Written.fSeq; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + ASSERT_THROW(m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet), cta::exception::TapeFseqMismatch); +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_different_sizes) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize1 = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize1; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + const uint64_t archiveFileSize2 = 2; + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize2; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + ASSERT_THROW(m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet), cta::catalogue::FileSizeMismatch); +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_different_checksum_types) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob.insert(cta::checksum::CRC32, "1234"); + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + ASSERT_THROW(m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet), cta::exception::ChecksumTypeMismatch); +} + +TEST_P(cta_catalogue_ArchiveFileTest, filesWrittenToTape_1_archive_file_2_tape_copies_different_checksum_values) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob.insert(cta::checksum::ADLER32, "5678"); + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + ASSERT_THROW(m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet), cta::exception::ChecksumValueMismatch); +} + +TEST_P(cta_catalogue_ArchiveFileTest, deleteArchiveFile) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + auto mItor = m.find(file1Written.archiveFileId); + ASSERT_NE(m.end(), mItor); + + const cta::common::dataStructures::ArchiveFile archiveFile = mItor->second; + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + ASSERT_EQ(2, m_catalogue->Tape()->getTapes().size()); + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file2Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + + { + auto mItor = m.find(file1Written.archiveFileId); + ASSERT_NE(m.end(), mItor); + + const cta::common::dataStructures::ArchiveFile archiveFile = mItor->second; + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(diskInstance, archiveFileId, dummyLc); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); +} + +TEST_P(cta_catalogue_ArchiveFileTest, deleteArchiveFile_by_archive_file_id_of_another_disk_instance) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(2, tapes.size()); + + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassDualCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file1Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + auto mItor = m.find(file1Written.archiveFileId); + ASSERT_NE(m.end(), mItor); + + const cta::common::dataStructures::ArchiveFile archiveFile = mItor->second; + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file2Written.storageClassName = m_storageClassDualCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + ASSERT_EQ(2, m_catalogue->Tape()->getTapes().size()); + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = file2Written.vid; + std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape &tape = tapes.front(); + ASSERT_EQ(1, tape.lastFSeq); + } + + { + auto archiveFileItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + const auto m = CatalogueTestUtils::archiveFileItorToMap(archiveFileItor); + ASSERT_EQ(1, m.size()); + + { + auto mItor = m.find(file1Written.archiveFileId); + ASSERT_NE(m.end(), mItor); + + const cta::common::dataStructures::ArchiveFile archiveFile = mItor->second; + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } + } + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } + + cta::log::LogContext dummyLc(m_dummyLog); + ASSERT_THROW(m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE("another_disk_instance", archiveFileId, dummyLc), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveFileTest, deleteArchiveFile_by_archive_file_id_non_existent) { + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE("disk_instance", 12345678, dummyLc); +} + + +} // namespace unitTests diff --git a/catalogue/tests/modules/ArchiveFileCatalogueTest.hpp b/catalogue/tests/modules/ArchiveFileCatalogueTest.hpp new file mode 100644 index 0000000000..da6516c647 --- /dev/null +++ b/catalogue/tests/modules/ArchiveFileCatalogueTest.hpp @@ -0,0 +1,57 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_ArchiveFileTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_ArchiveFileTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::catalogue::CreateTapeAttributes m_tape1; + const cta::catalogue::CreateTapeAttributes m_tape2; + const cta::catalogue::MediaType m_mediaType; + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::StorageClass m_storageClassDualCopy; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/ArchiveRouteCatalogueTest.cpp b/catalogue/tests/modules/ArchiveRouteCatalogueTest.cpp new file mode 100644 index 0000000000..31785650e6 --- /dev/null +++ b/catalogue/tests/modules/ArchiveRouteCatalogueTest.cpp @@ -0,0 +1,483 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_ArchiveRouteTest::cta_catalogue_ArchiveRouteTest() + : m_dummyLog("dummy", "dummy"), + m_tape1(CatalogueTestUtils::getTape1()), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()) { +} + +void cta_catalogue_ArchiveRouteTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_ArchiveRouteTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, comment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(m_storageClassSingleCopy.name, tapePoolName); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_emptyStringStorageClassName) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + + cta::common::dataStructures::StorageClass storageClass; + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const std::string storageClassName = ""; + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, storageClassName, copyNb, + tapePoolName, comment), cta::catalogue::UserSpecifiedAnEmptyStringStorageClassName); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_zeroCopyNb) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 0; + const std::string comment = "Create archive route"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, + m_tape1.tapePoolName, comment), cta::catalogue::UserSpecifiedAZeroCopyNb); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_emptyStringTapePoolName) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = ""; + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, comment), cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_emptyStringComment) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = ""; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, + m_tape1.tapePoolName, comment), cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_non_existent_storage_class) { + const std::string storageClassName = "storage_class"; + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, storageClassName, copyNb, m_tape1.tapePoolName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_non_existent_tape_pool) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "non_existent_tape_pool"; + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_same_twice) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment), cta::exception::Exception); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_two_routes_same_pool) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb1 = 1; + const std::string comment1 = "Create archive route for copy 1"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb1, m_tape1.tapePoolName, comment1); + + const uint32_t copyNb2 = 2; + const std::string comment2 = "Create archive route for copy 2"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb2, m_tape1.tapePoolName, comment2), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, deleteArchiveRoute) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->ArchiveRoute()->deleteArchiveRoute(m_storageClassSingleCopy.name, copyNb); + + ASSERT_TRUE(m_catalogue->ArchiveRoute()->getArchiveRoutes().empty()); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, deleteArchiveRoute_non_existent) { + ASSERT_THROW(m_catalogue->ArchiveRoute()->deleteArchiveRoute("non_existent_storage_class", 1234), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, createArchiveRoute_deleteStorageClass) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::catalogue::UserSpecifiedStorageClassUsedByArchiveRoutes); + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, modifyArchiveRouteTapePoolName) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const std::string anotherTapePoolName = "another_tape_pool"; + m_catalogue->TapePool()->createTapePool(m_admin, anotherTapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create another tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->ArchiveRoute()->modifyArchiveRouteTapePoolName(m_admin, m_storageClassSingleCopy.name, copyNb, anotherTapePoolName); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(anotherTapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_ArchiveRouteTest, modifyArchiveRouteTapePoolName_nonExistentTapePool) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const std::string anotherTapePoolName = "another_tape_pool"; + m_catalogue->TapePool()->createTapePool(m_admin, anotherTapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create another tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_THROW(m_catalogue->ArchiveRoute()->modifyArchiveRouteTapePoolName(m_admin, m_storageClassSingleCopy.name, copyNb, "non_existent_tape_pool"), cta::catalogue::UserSpecifiedANonExistentTapePool); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, modifyArchiveRouteTapePoolName_nonExistentArchiveRoute) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + ASSERT_THROW(m_catalogue->ArchiveRoute()->modifyArchiveRouteTapePoolName(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName), cta::catalogue::UserSpecifiedANonExistentArchiveRoute); +} + +TEST_P(cta_catalogue_ArchiveRouteTest, modifyArchiveRouteComment) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, m_tape1.tapePoolName, comment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->ArchiveRoute()->modifyArchiveRouteComment(m_admin, m_storageClassSingleCopy.name, copyNb, modifiedComment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(m_tape1.tapePoolName, route.tapePoolName); + ASSERT_EQ(modifiedComment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_ArchiveRouteTest, modifyArchiveRouteComment_nonExistentArchiveRoute) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Comment"; + ASSERT_THROW(m_catalogue->ArchiveRoute()->modifyArchiveRouteComment(m_admin, m_storageClassSingleCopy.name, copyNb, comment), cta::exception::UserError); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp b/catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp new file mode 100644 index 0000000000..c35e2adb1d --- /dev/null +++ b/catalogue/tests/modules/ArchiveRouteCatalogueTest.hpp @@ -0,0 +1,53 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_ArchiveRouteTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_ArchiveRouteTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::catalogue::CreateTapeAttributes m_tape1; + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/DiskInstanceCatalogueTest.cpp b/catalogue/tests/modules/DiskInstanceCatalogueTest.cpp new file mode 100644 index 0000000000..cc3a3027ce --- /dev/null +++ b/catalogue/tests/modules/DiskInstanceCatalogueTest.cpp @@ -0,0 +1,230 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/DiskInstanceCatalogueTest.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_DiskInstanceTest::cta_catalogue_DiskInstanceTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()) { +} + +void cta_catalogue_DiskInstanceTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_DiskInstanceTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DiskInstanceTest, getAllDiskInstances_empty) { + ASSERT_TRUE(m_catalogue->DiskInstance()->getAllDiskInstances().empty()); +} + +TEST_P(cta_catalogue_DiskInstanceTest, createDiskInstance) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_DiskInstanceTest, createDiskInstance_twice) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + ASSERT_THROW(m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_DiskInstanceTest, createDiskInstance_emptyName) { + const std::string comment = "disk_instance_comment"; + ASSERT_THROW(m_catalogue->DiskInstance()->createDiskInstance(m_admin, "", comment), + cta::catalogue::UserSpecifiedAnEmptyStringDiskInstanceName); +} + +TEST_P(cta_catalogue_DiskInstanceTest, createDiskInstance_emptyComment) { + const std::string name = "disk_instance_name"; + ASSERT_THROW(m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, ""), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_DiskInstanceTest, deleteDiskInstance) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->DiskInstance()->deleteDiskInstance(name); + ASSERT_TRUE(m_catalogue->DiskInstance()->getAllDiskInstances().empty()); +} + +TEST_P(cta_catalogue_DiskInstanceTest, deleteDiskInstance_nonExisting) { + const std::string name = "disk_instance_name"; + ASSERT_THROW(m_catalogue->DiskInstance()->deleteDiskInstance(name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_DiskInstanceTest, modifyDiskInstanceComment) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + { + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "modified_disk_instance_comment"; + m_catalogue->DiskInstance()->modifyDiskInstanceComment(m_admin, name, modifiedComment); + + { + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, modifiedComment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskInstanceTest, modifyDiskInstanceComment_emptyName) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + { + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_THROW(m_catalogue->DiskInstance()->modifyDiskInstanceComment(m_admin, "", comment), + cta::catalogue::UserSpecifiedAnEmptyStringDiskInstanceName); +} + +TEST_P(cta_catalogue_DiskInstanceTest, modifyDiskInstanceComment_emptyComment) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, name, comment); + { + const auto diskInstanceList = m_catalogue->DiskInstance()->getAllDiskInstances(); + ASSERT_EQ(1, diskInstanceList.size()); + + const auto &diskInstance = diskInstanceList.front(); + ASSERT_EQ(diskInstance.name, name); + ASSERT_EQ(diskInstance.comment, comment); + + const auto creationLog = diskInstance.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstance.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_THROW(m_catalogue->DiskInstance()->modifyDiskInstanceComment(m_admin, name, ""), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_DiskInstanceTest, modifyDiskInstanceComment_nonExisting) { + const std::string name = "disk_instance_name"; + const std::string comment = "disk_instance_comment"; + + ASSERT_THROW(m_catalogue->DiskInstance()->modifyDiskInstanceComment(m_admin, name, comment), + cta::catalogue::UserSpecifiedANonExistentDiskInstance); +} + + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/DiskInstanceCatalogueTest.hpp b/catalogue/tests/modules/DiskInstanceCatalogueTest.hpp new file mode 100644 index 0000000000..3119f05039 --- /dev/null +++ b/catalogue/tests/modules/DiskInstanceCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DiskInstanceTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DiskInstanceTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.cpp b/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.cpp new file mode 100644 index 0000000000..40f5ac0b2a --- /dev/null +++ b/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.cpp @@ -0,0 +1,620 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/DiskInstanceSpace.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_DiskInstanceSpaceTest::cta_catalogue_DiskInstanceSpaceTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()) { +} + +void cta_catalogue_DiskInstanceSpaceTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_DiskInstanceSpaceTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_twice) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_nonExistantDiskInstance) { + const std::string diskInstance = "disk_instance_name"; + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_emptyName) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, "", diskInstance, freeSpaceQueryURL, + refreshInterval, comment), cta::catalogue::UserSpecifiedAnEmptyStringDiskInstanceSpaceName); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_emptyComment) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, ""), cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_emptyFreeSpaceQueryURL) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, "", + refreshInterval, comment), cta::catalogue::UserSpecifiedAnEmptyStringFreeSpaceQueryURL); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, createDiskInstanceSpace_zeroRefreshInterval) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const std::string comment = "disk_instance_space_comment"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + 0, comment), cta::catalogue::UserSpecifiedAZeroRefreshInterval); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceComment) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + + const std::string newDiskInstanceSpaceComment = "disk_instance_comment_2"; + m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceComment(m_admin, name, diskInstance, + newDiskInstanceSpaceComment); + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, newDiskInstanceSpaceComment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceComment_empty) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceComment(m_admin, name, diskInstance, ""), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceComment_nonExistingSpace) { + const std::string name = "disk_instance_space_name"; + const std::string diskInstance = "disk_instance_name"; + const std::string comment = "disk_instance_space_comment"; + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceComment(m_admin, name, diskInstance, comment), + cta::catalogue::UserSpecifiedANonExistentDiskInstanceSpace); +} + + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceQueryURL) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + + const std::string newFreeSpaceQueryURL = "new_free_space_query_URL"; + m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceQueryURL(m_admin, name, diskInstance, newFreeSpaceQueryURL); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, newFreeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceQueryURL_empty) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceQueryURL(m_admin, name, diskInstance, ""), + cta::catalogue::UserSpecifiedAnEmptyStringFreeSpaceQueryURL); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceQueryURL_nonExistingSpace) { + const std::string name = "disk_instance_space_name"; + const std::string diskInstance = "disk_instance_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceQueryURL(m_admin, name, diskInstance, + freeSpaceQueryURL), cta::catalogue::UserSpecifiedANonExistentDiskInstanceSpace); +} + + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceRefreshInterval) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + + const uint64_t newRefreshInterval = 35; + m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceRefreshInterval(m_admin, name, diskInstance, + newRefreshInterval); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, newRefreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceRefreshInterval_zeroInterval) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceRefreshInterval(m_admin, name, diskInstance, 0), + cta::catalogue::UserSpecifiedAZeroRefreshInterval); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceRefreshInterval_nonExistingSpace) { + const std::string name = "disk_instance_space_name"; + const std::string diskInstance = "disk_instance_name"; + const uint64_t refreshInterval = 32; + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceRefreshInterval(m_admin, name, diskInstance, + refreshInterval), cta::catalogue::UserSpecifiedANonExistentDiskInstanceSpace); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, modifyDiskInstanceSpaceFreeSpace) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + } + + const uint64_t newFreeSpace = 300; + m_catalogue->DiskInstanceSpace()->modifyDiskInstanceSpaceFreeSpace(name, diskInstance, newFreeSpace); + + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_NE(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, newFreeSpace); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, deleteDiskInstanceSpace) { + const std::string diskInstance = "disk_instance_name"; + const std::string diskInstanceComment = "disk_instance_comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, diskInstanceComment); + + const std::string name = "disk_instance_space_name"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const std::string comment = "disk_instance_space_comment"; + + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + { + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(1, diskInstanceSpaceList.size()); + + const auto &diskInstanceSpace = diskInstanceSpaceList.front(); + ASSERT_EQ(diskInstanceSpace.name, name); + ASSERT_EQ(diskInstanceSpace.diskInstance, diskInstance); + ASSERT_EQ(diskInstanceSpace.freeSpaceQueryURL, freeSpaceQueryURL); + ASSERT_EQ(diskInstanceSpace.refreshInterval, refreshInterval); + ASSERT_EQ(diskInstanceSpace.lastRefreshTime, 0); + ASSERT_EQ(diskInstanceSpace.freeSpace, 0); + + ASSERT_EQ(diskInstanceSpace.comment, comment); + + const auto creationLog = diskInstanceSpace.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskInstanceSpace.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + m_catalogue->DiskInstanceSpace()->deleteDiskInstanceSpace(name, diskInstance); + const auto diskInstanceSpaceList = m_catalogue->DiskInstanceSpace()->getAllDiskInstanceSpaces(); + ASSERT_EQ(0, diskInstanceSpaceList.size()); +} + +TEST_P(cta_catalogue_DiskInstanceSpaceTest, deleteDiskInstanceSpace_notExisting) { + const std::string diskInstance = "disk_instance_name"; + const std::string name = "disk_instance_space_name"; + + ASSERT_THROW(m_catalogue->DiskInstanceSpace()->deleteDiskInstanceSpace(name, diskInstance), + cta::catalogue::UserSpecifiedANonExistentDiskInstanceSpace); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp b/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp new file mode 100644 index 0000000000..c9882342b9 --- /dev/null +++ b/catalogue/tests/modules/DiskInstanceSpaceCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DiskInstanceSpaceTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DiskInstanceSpaceTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/DiskSystemCatalogueTest.cpp b/catalogue/tests/modules/DiskSystemCatalogueTest.cpp new file mode 100644 index 0000000000..e673ab83a4 --- /dev/null +++ b/catalogue/tests/modules/DiskSystemCatalogueTest.cpp @@ -0,0 +1,714 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/DiskSystemCatalogueTest.hpp" +#include "common/log/LogContext.hpp" +#include "disk/DiskSystem.hpp" + +namespace unitTests { + +cta_catalogue_DiskSystemTest::cta_catalogue_DiskSystemTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()) { +} + +void cta_catalogue_DiskSystemTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_DiskSystemTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DiskSystemTest, getAllDiskSystems_no_systems) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); +} + +TEST_P(cta_catalogue_DiskSystemTest, getAllDiskSystems_many_diskSystems) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + + const uint32_t nbDiskSystems = 16; + + std::string diskInstanceName = "DiskInstanceName"; + std::string diskInstanceComment = "Comment"; + std::string diskInstanceSpaceName = "DiskInstanceSpace"; + std::string diskInstanceSpaceComment = "Comment"; + + // create disk instance + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstanceName, diskInstanceComment); + // create disk instance space + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpaceName, diskInstanceName, + freeSpaceQueryURL, refreshInterval, diskInstanceSpaceComment); + + + for(uint32_t i = 0; i < nbDiskSystems; i++) { + std::ostringstream name; + name << "DiskSystem" << std::setfill('0') << std::setw(5) << i; + const std::string diskSystemComment = "Create disk system " + name.str(); + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name.str(), diskInstanceName, diskInstanceSpaceName, + fileRegexp, targetedFreeSpace + i, sleepTime + i, diskSystemComment); + + } + + auto diskSystemsList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(nbDiskSystems, diskSystemsList.size()); + + for(size_t i = 0; i < nbDiskSystems; i++) { + std::ostringstream name; + name << "DiskSystem" << std::setfill('0') << std::setw(5) << i; + const std::string diskSystemComment = "Create disk system " + name.str(); + ASSERT_NO_THROW(diskSystemsList.at(name.str())); + const auto diskSystem = diskSystemsList.at(name.str()); + + ASSERT_EQ(name.str(), diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval ); + + ASSERT_EQ(targetedFreeSpace + i, diskSystem.targetedFreeSpace); + ASSERT_EQ(sleepTime + i, diskSystem.sleepTime); + ASSERT_EQ(diskSystemComment, diskSystem.comment); + } +} + +TEST_P(cta_catalogue_DiskSystemTest, diskSystemExists_emptyString) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = ""; + + ASSERT_THROW(m_catalogue->DiskSystem()->diskSystemExists(name), cta::exception::Exception); +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_emptyStringDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = ""; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "Create disk system"; + + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, + fileRegexp, targetedFreeSpace, sleepTime, comment), cta::catalogue::UserSpecifiedAnEmptyStringDiskSystemName); + +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_emptyStringFileRegexp) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = ""; + const std::string freeSpaceQueryURL = "free_space_query_URL"; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "Create disk system"; + + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, + fileRegexp, targetedFreeSpace, sleepTime, comment), cta::catalogue::UserSpecifiedAnEmptyStringFileRegexp); + +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_zeroTargetedFreeSpace) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t targetedFreeSpace = 0; + const uint64_t sleepTime = 15*60; + const std::string comment = "Create disk system"; + + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, + fileRegexp, targetedFreeSpace, sleepTime, comment), cta::catalogue::UserSpecifiedAZeroTargetedFreeSpace); +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_emptyStringComment) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = ""; + + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, + fileRegexp, targetedFreeSpace, sleepTime, comment), cta::catalogue::UserSpecifiedAnEmptyStringComment); + +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_9_exabytes_targetedFreeSpace) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 9L * 1000 * 1000 * 1000 * 1000 * 1000 * 1000; + const uint64_t sleepTime = 15*60; + const std::string comment = "comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + + ASSERT_EQ(1, diskSystemList.size()); + + { + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(diskInstance, diskSystem.diskInstanceSpace.diskInstance); + ASSERT_EQ(diskInstanceSpace, diskSystem.diskInstanceSpace.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(sleepTime, diskSystem.sleepTime); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_sleepTimeHandling) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 0; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment), cta::catalogue::UserSpecifiedAZeroSleepTime); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, std::numeric_limits<int64_t>::max(), comment); + + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + + ASSERT_EQ(1, diskSystemList.size()); + + { + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(std::numeric_limits<int64_t>::max(), diskSystem.sleepTime); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + + +TEST_P(cta_catalogue_DiskSystemTest, createDiskSystem_same_twice) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + + ASSERT_EQ(1, diskSystemList.size()); + ASSERT_THROW(m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_DiskSystemTest, deleteDiskSystem) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->DiskSystem()->deleteDiskSystem(diskSystem.name); + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); +} + +TEST_P(cta_catalogue_DiskSystemTest, deleteDiskSystem_non_existent) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + ASSERT_THROW(m_catalogue->DiskSystem()->deleteDiskSystem("non_existent_disk_system"), + cta::catalogue::UserSpecifiedANonExistentDiskSystem); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemFileRegexp) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedFileRegexp = "modified_fileRegexp"; + m_catalogue->DiskSystem()->modifyDiskSystemFileRegexp(m_admin, name, modifiedFileRegexp); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(modifiedFileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemFileRegexp_emptyStringDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = ""; + const std::string modifiedFileRegexp = "modified_fileRegexp"; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemFileRegexp(m_admin, diskSystemName, modifiedFileRegexp), + cta::catalogue::UserSpecifiedAnEmptyStringDiskSystemName); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemFileRegexp_nonExistentDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = "dummyDiskSystemName"; + const std::string modifiedFileRegexp = "modified_fileRegexp"; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemFileRegexp(m_admin, diskSystemName, modifiedFileRegexp), + cta::catalogue::UserSpecifiedANonExistentDiskSystem); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemFileRegexp_emptyStringFileRegexp) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, + freeSpaceQueryURL, refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedFileRegexp = ""; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemFileRegexp(m_admin, name, modifiedFileRegexp), + cta::catalogue::UserSpecifiedAnEmptyStringFileRegexp); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemTargetedFreeSpace) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, + freeSpaceQueryURL, refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedTargetedFreeSpace = 128; + m_catalogue->DiskSystem()->modifyDiskSystemTargetedFreeSpace(m_admin, name, modifiedTargetedFreeSpace); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(modifiedTargetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemTargetedFreeSpace_emptyStringDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = ""; + const uint64_t modifiedTargetedFreeSpace = 128; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemTargetedFreeSpace(m_admin, diskSystemName, + modifiedTargetedFreeSpace), cta::catalogue::UserSpecifiedAnEmptyStringDiskSystemName); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemTargetedFreeSpace_nonExistentDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = "dummyDiskSystemName"; + const uint64_t modifiedTargetedFreeSpace = 128; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemTargetedFreeSpace(m_admin, diskSystemName, + modifiedTargetedFreeSpace), cta::catalogue::UserSpecifiedANonExistentDiskSystem); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemTargetedFreeSpace_zeroTargetedFreeSpace) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, + freeSpaceQueryURL, refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedTargetedFreeSpace = 0; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemTargetedFreeSpace(m_admin, name, modifiedTargetedFreeSpace), + cta::catalogue::UserSpecifiedAZeroTargetedFreeSpace); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemComment) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, + freeSpaceQueryURL, refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "modified_comment"; + m_catalogue->DiskSystem()->modifyDiskSystemComment(m_admin, name, modifiedComment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(modifiedComment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemComment_emptyStringDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = ""; + const std::string modifiedComment = "modified_comment"; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemComment(m_admin, diskSystemName, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringDiskSystemName); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemComment_nonExistentDiskSystemName) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string diskSystemName = "dummyDiskSystemName"; + const std::string modifiedComment = "modified_comment"; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemComment(m_admin, diskSystemName, modifiedComment), + cta::catalogue::UserSpecifiedANonExistentDiskSystem); +} + +TEST_P(cta_catalogue_DiskSystemTest, modifyDiskSystemCommentL_emptyStringComment) { + ASSERT_TRUE(m_catalogue->DiskSystem()->getAllDiskSystems().empty()); + + const std::string name = "disk_system_name"; + const std::string diskInstance = "disk_instance"; + const std::string diskInstanceSpace = "disk_instance_space"; + const std::string fileRegexp = "file_regexp"; + const std::string freeSpaceQueryURL = "free_space_query_url"; + const uint64_t refreshInterval = 32; + const uint64_t targetedFreeSpace = 64; + const uint64_t sleepTime = 15*60; + const std::string comment = "disk system comment"; + + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstance, comment); + m_catalogue->DiskInstanceSpace()->createDiskInstanceSpace(m_admin, diskInstanceSpace, diskInstance, + freeSpaceQueryURL, refreshInterval, comment); + + m_catalogue->DiskSystem()->createDiskSystem(m_admin, name, diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); + + { + const auto diskSystemList = m_catalogue->DiskSystem()->getAllDiskSystems(); + ASSERT_EQ(1, diskSystemList.size()); + + const auto &diskSystem = diskSystemList.front(); + ASSERT_EQ(name, diskSystem.name); + ASSERT_EQ(fileRegexp, diskSystem.fileRegexp); + ASSERT_EQ(freeSpaceQueryURL, diskSystem.diskInstanceSpace.freeSpaceQueryURL); + ASSERT_EQ(refreshInterval, diskSystem.diskInstanceSpace.refreshInterval); + ASSERT_EQ(targetedFreeSpace, diskSystem.targetedFreeSpace); + ASSERT_EQ(comment, diskSystem.comment); + + const auto creationLog = diskSystem.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = diskSystem.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = ""; + ASSERT_THROW(m_catalogue->DiskSystem()->modifyDiskSystemComment(m_admin, name, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/DiskSystemCatalogueTest.hpp b/catalogue/tests/modules/DiskSystemCatalogueTest.hpp new file mode 100644 index 0000000000..e9939918b4 --- /dev/null +++ b/catalogue/tests/modules/DiskSystemCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DiskSystemTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DiskSystemTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/DriveConfigCatalogueTest.cpp b/catalogue/tests/modules/DriveConfigCatalogueTest.cpp new file mode 100644 index 0000000000..5f2e4090e6 --- /dev/null +++ b/catalogue/tests/modules/DriveConfigCatalogueTest.cpp @@ -0,0 +1,266 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/DriveConfigCatalogueTest.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" +#include "common/SourcedParameter.hpp" + +namespace unitTests { + +cta_catalogue_DriveConfigTest::cta_catalogue_DriveConfigTest() + : m_dummyLog("dummy", "dummy") { +} + +void cta_catalogue_DriveConfigTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_DriveConfigTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DriveConfigTest, getTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, getAllDrivesConfigs) { + std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> tapeDriveConfigs; + // Create 100 tape drives + for (size_t i = 0; i < 100; i++) { + std::stringstream ss; + ss << "VDSTK" << std::setw(5) << std::setfill('0') << i; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(ss.str(), daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + tapeDriveConfigs.push_back({ss.str(), daemonUserName.category(), daemonUserName.key(), daemonUserName.value(), + daemonUserName.source()}); + cta::SourcedParameter<std::string> defaultConfig { + "taped", "defaultConfig", "cta", "Random Default Config for Testing"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(ss.str(), defaultConfig.category(), defaultConfig.key(), + defaultConfig.value(), defaultConfig.source()); + tapeDriveConfigs.push_back({ss.str(), defaultConfig.category(), defaultConfig.key(), defaultConfig.value(), + defaultConfig.source()}); + } + const auto drivesConfigs = m_catalogue->DriveConfig()->getTapeDriveConfigs(); + ASSERT_EQ(tapeDriveConfigs.size(), drivesConfigs.size()); + for (const auto& dc : drivesConfigs) { + m_catalogue->DriveConfig()->deleteTapeDriveConfig(dc.tapeDriveName, dc.keyName); + } +} + +TEST_P(cta_catalogue_DriveConfigTest, setSourcedParameterWithEmptyValue) { + const std::string tapeDriveName = "VDSTK11"; + + cta::SourcedParameter<std::string> raoLtoOptions { + "taped", "RAOLTOAlgorithmOptions", "", "Compile time default" + }; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, raoLtoOptions.category(), raoLtoOptions.key(), + raoLtoOptions.value(), raoLtoOptions.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, raoLtoOptions.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(raoLtoOptions.category(), category); + ASSERT_EQ("", value); + ASSERT_EQ(raoLtoOptions.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, raoLtoOptions.key()); + + cta::SourcedParameter<std::string> backendPath{ + "ObjectStore", "BackendPath"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, backendPath.category(), backendPath.key(), + backendPath.value(), backendPath.source()); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, backendPath.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + std::tie(category, value, source) = driveConfig.value(); + ASSERT_EQ(backendPath.category(), category); + ASSERT_EQ("", value); + ASSERT_EQ("", source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, backendPath.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, failTogetTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const std::string wrongKey = "wrongKey"; + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(wrongName, daemonUserName.key()); + ASSERT_FALSE(driveConfig); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, wrongKey); + ASSERT_FALSE(driveConfig); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(wrongName, wrongKey); + ASSERT_FALSE(driveConfig); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, failTodeleteTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const std::string wrongKey = "wrongKey"; + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(wrongName, daemonUserName.key()); + auto driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, wrongKey); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(wrongName, wrongKey); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig)); + // Good deletion + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName.key()); + driveConfig = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName.key()); + ASSERT_FALSE(driveConfig); +} + +TEST_P(cta_catalogue_DriveConfigTest, multipleDriveConfig) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + cta::SourcedParameter<std::string> daemonGroupName { + "taped", "DaemonGroupName", "tape", "Compile time default"}; + + // Combinations of tapeDriveName1/2 and daemonUserName and daemonGroupName + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + auto driveConfig1UserName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName1, daemonUserName.key()); + auto driveConfig2UserName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName2, daemonUserName.key()); + auto driveConfig1GroupName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName1, daemonGroupName.key()); + auto driveConfig2GroupName = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName2, daemonGroupName.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig1UserName)); + ASSERT_TRUE(static_cast<bool>(driveConfig2UserName)); + ASSERT_TRUE(static_cast<bool>(driveConfig1GroupName)); + ASSERT_TRUE(static_cast<bool>(driveConfig2GroupName)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig1UserName.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + std::tie(category, value, source) = driveConfig2UserName.value(); + ASSERT_EQ(daemonUserName.category(), category); + ASSERT_EQ(daemonUserName.value(), value); + ASSERT_EQ(daemonUserName.source(), source); + std::tie(category, value, source) = driveConfig1GroupName.value(); + ASSERT_EQ(daemonGroupName.category(), category); + ASSERT_EQ(daemonGroupName.value(), value); + ASSERT_EQ(daemonGroupName.source(), source); + std::tie(category, value, source) = driveConfig2GroupName.value(); + ASSERT_EQ(daemonGroupName.category(), category); + ASSERT_EQ(daemonGroupName.value(), value); + ASSERT_EQ(daemonGroupName.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName1, daemonUserName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName1, daemonGroupName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName2, daemonUserName.key()); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName2, daemonGroupName.key()); +} + +TEST_P(cta_catalogue_DriveConfigTest, getNamesAndKeysOfMultipleDriveConfig) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + + cta::SourcedParameter<std::string> daemonUserName { + "taped", "DaemonUserName", "cta", "Compile time default"}; + cta::SourcedParameter<std::string> daemonGroupName { + "taped", "DaemonGroupName", "tape", "Compile time default"}; + + // Combinations of tapeDriveName1/2 and daemonUserName and daemonGroupName + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName1, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonUserName.category(), daemonUserName.key(), + daemonUserName.value(), daemonUserName.source()); + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName2, daemonGroupName.category(), daemonGroupName.key(), + daemonGroupName.value(), daemonGroupName.source()); + + const auto configurationTapeNamesAndKeys = m_catalogue->DriveConfig()->getTapeDriveConfigNamesAndKeys(); + + for (const auto& nameAndKey : configurationTapeNamesAndKeys) { + m_catalogue->DriveConfig()->deleteTapeDriveConfig(nameAndKey.first, nameAndKey.second); + } +} + +TEST_P(cta_catalogue_DriveConfigTest, modifyTapeDriveConfig) { + const std::string tapeDriveName = "VDSTK11"; + // Both share same key + cta::SourcedParameter<std::string> daemonUserName1 { + "taped1", "DaemonUserName", "cta1", "Compile time1 default"}; + cta::SourcedParameter<std::string> daemonUserName2 { + "taped2", "DaemonUserName", "cta2", "Compile time2 default"}; + + m_catalogue->DriveConfig()->createTapeDriveConfig(tapeDriveName, daemonUserName1.category(), daemonUserName1.key(), + daemonUserName1.value(), daemonUserName1.source()); + const auto driveConfig1 = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName1.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig1)); + std::string category, value, source; + std::tie(category, value, source) = driveConfig1.value(); + ASSERT_NE(daemonUserName2.category(), category); + ASSERT_NE(daemonUserName2.value(), value); + ASSERT_NE(daemonUserName2.source(), source); + m_catalogue->DriveConfig()->modifyTapeDriveConfig(tapeDriveName, daemonUserName2.category(), daemonUserName2.key(), + daemonUserName2.value(), daemonUserName2.source()); + const auto driveConfig2 = m_catalogue->DriveConfig()->getTapeDriveConfig(tapeDriveName, daemonUserName1.key()); + ASSERT_TRUE(static_cast<bool>(driveConfig2)); + std::tie(category, value, source) = driveConfig2.value(); + ASSERT_EQ(daemonUserName2.category(), category); + ASSERT_EQ(daemonUserName2.value(), value); + ASSERT_EQ(daemonUserName2.source(), source); + m_catalogue->DriveConfig()->deleteTapeDriveConfig(tapeDriveName, daemonUserName1.key()); +} + +} // namespace unitTests diff --git a/catalogue/tests/modules/DriveConfigCatalogueTest.hpp b/catalogue/tests/modules/DriveConfigCatalogueTest.hpp new file mode 100644 index 0000000000..c03102f6c9 --- /dev/null +++ b/catalogue/tests/modules/DriveConfigCatalogueTest.hpp @@ -0,0 +1,42 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DriveConfigTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DriveConfigTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/DriveStateCatalogueTest.cpp b/catalogue/tests/modules/DriveStateCatalogueTest.cpp new file mode 100644 index 0000000000..2d1343aa25 --- /dev/null +++ b/catalogue/tests/modules/DriveStateCatalogueTest.cpp @@ -0,0 +1,1526 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/TapeDrivesCatalogueState.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/DriveStateCatalogueTest.hpp" +#include "common/dataStructures/DesiredDriveState.hpp" +#include "common/dataStructures/DriveInfo.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/TapeDrive.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" +#include "common/SourcedParameter.hpp" + +namespace unitTests { + +namespace { +cta::common::dataStructures::SecurityIdentity getAdmin() { + cta::common::dataStructures::SecurityIdentity admin; + admin.username = "admin_user_name"; + admin.host = "admin_host"; + return admin; +} + +cta::common::dataStructures::TapeDrive getTapeDriveWithMandatoryElements(const std::string &driveName) { + cta::common::dataStructures::TapeDrive tapeDrive; + tapeDrive.driveName = driveName; + tapeDrive.host = "admin_host"; + tapeDrive.logicalLibrary = "VLSTK10"; + tapeDrive.mountType = cta::common::dataStructures::MountType::NoMount; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + tapeDrive.desiredUp = false; + tapeDrive.desiredForceDown = false; + return tapeDrive; +} + +cta::common::dataStructures::TapeDrive getTapeDriveWithAllElements(const std::string &driveName) { + cta::common::dataStructures::TapeDrive tapeDrive; + tapeDrive.driveName = driveName; + tapeDrive.host = "admin_host"; + tapeDrive.logicalLibrary = "VLSTK10"; + tapeDrive.mountType = cta::common::dataStructures::MountType::NoMount; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + tapeDrive.desiredUp = false; + tapeDrive.desiredForceDown = false; + tapeDrive.diskSystemName = "dummyDiskSystemName"; + tapeDrive.reservedBytes = 694498291384; + tapeDrive.reservationSessionId = 0; + + tapeDrive.sessionStartTime = 1001; + tapeDrive.mountStartTime = 1002; + tapeDrive.transferStartTime = 1003; + tapeDrive.unloadStartTime = 1004; + tapeDrive.unmountStartTime = 1005; + tapeDrive.drainingStartTime = 1006; + tapeDrive.downOrUpStartTime = 1007; + tapeDrive.probeStartTime = 1008; + tapeDrive.cleanupStartTime = 1009; + tapeDrive.startStartTime = 1010; + tapeDrive.shutdownTime = 1011; + + tapeDrive.reasonUpDown = "Random Reason"; + + tapeDrive.currentVid = "VIDONE"; + tapeDrive.ctaVersion = "v1.0.0"; + tapeDrive.currentPriority = 3; + tapeDrive.currentActivity = "Activity1"; + tapeDrive.currentTapePool = "tape_pool_0"; + tapeDrive.nextMountType = cta::common::dataStructures::MountType::Retrieve; + tapeDrive.nextVid = "VIDTWO"; + tapeDrive.nextTapePool = "tape_pool_1"; + tapeDrive.nextPriority = 1; + tapeDrive.nextActivity = "Activity2"; + + tapeDrive.devFileName = "fileName"; + tapeDrive.rawLibrarySlot = "librarySlot1"; + + tapeDrive.currentVo = "VO_ONE"; + tapeDrive.nextVo = "VO_TWO"; + + tapeDrive.userComment = "Random comment"; + tapeDrive.creationLog = cta::common::dataStructures::EntryLog("user_name_1", "host_1", 100002); + tapeDrive.lastModificationLog = cta::common::dataStructures::EntryLog("user_name_2", "host_2", 10032131); + + return tapeDrive; +} +} // namespace + +cta_catalogue_DriveStateTest::cta_catalogue_DriveStateTest() + : m_dummyLog("dummy", "dummy"), + m_admin(getAdmin()) { +} + +void cta_catalogue_DriveStateTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_DriveStateTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveNames) { + const std::list<std::string> tapeDriveNames = {"VDSTK11", "VDSTK12", "VDSTK21", "VDSTK22"}; + for (const auto& name : tapeDriveNames) { + const auto tapeDrive = getTapeDriveWithMandatoryElements(name); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + } + const auto storedTapeDriveNames = m_catalogue->DriveState()->getTapeDriveNames(); + ASSERT_EQ(tapeDriveNames, storedTapeDriveNames); + for (const auto& name : tapeDriveNames) { + m_catalogue->DriveState()->deleteTapeDrive(name); + } +} + +TEST_P(cta_catalogue_DriveStateTest, getAllTapeDrives) { + std::list<std::string> tapeDriveNames; + // Create 100 tape drives + for (size_t i = 0; i < 100; i++) { + std::stringstream ss; + ss << "VDSTK" << std::setw(5) << std::setfill('0') << i; + tapeDriveNames.push_back(ss.str()); + } + std::list<cta::common::dataStructures::TapeDrive> tapeDrives; + for (const auto& name : tapeDriveNames) { + const auto tapeDrive = getTapeDriveWithMandatoryElements(name); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + tapeDrives.push_back(tapeDrive); + } + auto storedTapeDrives = m_catalogue->DriveState()->getTapeDrives(); + ASSERT_EQ(tapeDriveNames.size(), storedTapeDrives.size()); + while (!storedTapeDrives.empty()) { + const auto storedTapeDrive = storedTapeDrives.front(); + const auto tapeDrive = tapeDrives.front(); + storedTapeDrives.pop_front(); + tapeDrives.pop_front(); + ASSERT_EQ(tapeDrive, storedTapeDrive); + } + for (const auto& name : tapeDriveNames) { + m_catalogue->DriveState()->deleteTapeDrive(name); + } +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive, storedTapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithEmptyEntryLog) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.creationLog = cta::common::dataStructures::EntryLog("", "", 0); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().creationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithNonExistingLogicalLibrary) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().logicalLibraryDisabled); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithDisabledLogicalLibrary) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, tapeDrive.logicalLibrary, true, "comment"); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(storedTapeDrive.value().logicalLibraryDisabled); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); + m_catalogue->LogicalLibrary()->deleteLogicalLibrary(tapeDrive.logicalLibrary); +} + + +TEST_P(cta_catalogue_DriveStateTest, failToGetTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(wrongName); + ASSERT_FALSE(storedTapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(tapeDriveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToDeleteTapeDrive) { + const std::string tapeDriveName = "VDSTK11"; + const std::string wrongName = "VDSTK56"; + const auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + m_catalogue->DriveState()->deleteTapeDrive(wrongName); + auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + m_catalogue->DriveState()->deleteTapeDrive(tapeDriveName); + storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive); +} + +TEST_P(cta_catalogue_DriveStateTest, getTapeDriveWithAllElements) { + const std::string tapeDriveName = "VDSTK11"; + const auto tapeDrive = getTapeDriveWithAllElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive, storedTapeDrive.value()); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, multipleTapeDrives) { + const std::string tapeDriveName1 = "VDSTK11"; + const std::string tapeDriveName2 = "VDSTK12"; + const auto tapeDrive1 = getTapeDriveWithMandatoryElements(tapeDriveName1); + const auto tapeDrive2 = getTapeDriveWithAllElements(tapeDriveName2); + m_catalogue->DriveState()->createTapeDrive(tapeDrive1); + m_catalogue->DriveState()->createTapeDrive(tapeDrive2); + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive1.driveName); + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive2.driveName); + ASSERT_EQ(tapeDrive1, storedTapeDrive1); + ASSERT_EQ(tapeDrive2, storedTapeDrive2); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive1.driveName); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive2.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateEmpty) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.reasonUpDown = "Previous reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + { + cta::common::dataStructures::DesiredDriveState desiredState; + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), tapeDrive.reasonUpDown.value()); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateWithEmptyReason) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + { + cta::common::dataStructures::DesiredDriveState desiredState; + desiredState.reason = ""; + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + // SqlLite (InMemory) returns an empty string and Oracle returns a std::nullopt + if (storedTapeDrive.value().reasonUpDown) { + ASSERT_TRUE(storedTapeDrive.value().reasonUpDown.value().empty()); + } else { + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + } + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredState) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason"; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , desiredState.up); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , desiredState.forceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , desiredState.reason); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateComment) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + // It should keep this Desired Status + tapeDrive.desiredUp = true; + tapeDrive.desiredForceDown = false; + tapeDrive.reasonUpDown = "reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + // It should update only the comment + const std::string comment = "New Comment"; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason2"; + desiredState.comment = comment; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , tapeDrive.desiredUp); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , tapeDrive.desiredForceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , tapeDrive.reasonUpDown); + ASSERT_EQ(storedTapeDrive.value().userComment.value() , comment); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setDesiredStateEmptyComment) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + // It should keep this Desired Status + tapeDrive.desiredUp = true; + tapeDrive.desiredForceDown = false; + tapeDrive.reasonUpDown = "reason"; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::common::dataStructures::DesiredDriveState desiredState; + // It should update only the comment + const std::string comment = ""; + desiredState.up = false; + desiredState.forceDown = true; + desiredState.reason = "reason2"; + desiredState.comment = comment; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->setDesiredDriveState(tapeDriveName, desiredState, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().desiredUp , tapeDrive.desiredUp); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown , tapeDrive.desiredForceDown); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value() , tapeDrive.reasonUpDown); + // SqlLite (InMemory) returns an empty string and Oracle returns a std::nullopt + if (storedTapeDrive.value().userComment) { + ASSERT_TRUE(storedTapeDrive.value().userComment.value().empty()); + } else { + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().userComment)); + } + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setTapeDriveStatistics) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Transferring; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatsInputs inputs; + inputs.reportTime = time(nullptr); + inputs.bytesTransferred = 123456789; + inputs.filesTransferred = 987654321; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatistics(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(storedTapeDrive.value().bytesTransferedInSession.value(), inputs.bytesTransferred); + ASSERT_EQ(storedTapeDrive.value().filesTransferedInSession.value(), inputs.filesTransferred); + const auto lastModificationLog = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, + inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value() , lastModificationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, setTapeDriveStatisticsInNoTransferingStatus) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + cta::ReportDriveStatsInputs inputs; + inputs.reportTime = time(nullptr); + inputs.bytesTransferred = 123456789; + inputs.filesTransferred = 987654321; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatistics(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().bytesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().filesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().lastModificationLog); + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusSameAsPrevious) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + // We update keeping the same status, so it has to update only the lastModificationLog + cta::ReportDriveStatusInputs inputs; + inputs.status = tapeDrive.driveStatus; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 123456; + inputs.filesTransferred = 987654; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(driveInfo.driveName, storedTapeDrive.value().driveName); + ASSERT_EQ(inputs.status, storedTapeDrive.value().driveStatus); + ASSERT_NE(inputs.mountType, storedTapeDrive.value().mountType); // Not update this value + ASSERT_EQ(driveInfo.host, storedTapeDrive.value().host); + ASSERT_EQ(driveInfo.logicalLibrary, storedTapeDrive.value().logicalLibrary); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(log, storedTapeDrive.value().lastModificationLog.value()); + ASSERT_FALSE(storedTapeDrive.value().bytesTransferedInSession); + ASSERT_FALSE(storedTapeDrive.value().filesTransferedInSession); + // Disk reservations are not updated by updateTapeDriveStatus() + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusSameTransferingAsPrevious) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Transferring; + tapeDrive.sessionStartTime = time(nullptr); + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + const auto test = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_EQ(tapeDrive.sessionStartTime, test.value().sessionStartTime.value()); + // We update keeping the same status, so it has to update only the lastModificationLog + const uint64_t elapsedTime = 1000; + cta::ReportDriveStatusInputs inputs; + inputs.status = tapeDrive.driveStatus; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = tapeDrive.sessionStartTime.value() + elapsedTime; + inputs.mountSessionId = 0; + inputs.byteTransferred = 123456; + inputs.filesTransferred = 987654; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(driveInfo.driveName, storedTapeDrive.value().driveName); + ASSERT_EQ(inputs.status, storedTapeDrive.value().driveStatus); + ASSERT_NE(inputs.mountType, storedTapeDrive.value().mountType); // Not update this value + ASSERT_EQ(driveInfo.host, storedTapeDrive.value().host); + ASSERT_EQ(driveInfo.logicalLibrary, storedTapeDrive.value().logicalLibrary); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(log, storedTapeDrive.value().lastModificationLog.value()); + ASSERT_EQ(inputs.byteTransferred, storedTapeDrive.value().bytesTransferedInSession.value()); + ASSERT_EQ(inputs.filesTransferred, storedTapeDrive.value().filesTransferedInSession.value()); + // It will keep names and bytes, because it isn't in state UP + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + // Check elapsed time + ASSERT_EQ(storedTapeDrive.value().sessionElapsedTime.value(), inputs.reportTime - tapeDrive.sessionStartTime.value()); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusDown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Up; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Down; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_EQ(storedTapeDrive.value().downOrUpStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, cta::common::dataStructures::MountType::NoMount); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Down); + ASSERT_EQ(storedTapeDrive.value().desiredUp, false); + ASSERT_EQ(storedTapeDrive.value().desiredForceDown, false); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), inputs.reason); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUp) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.desiredUp = true; + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_EQ(storedTapeDrive.value().downOrUpStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, cta::common::dataStructures::MountType::NoMount); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Up); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reasonUpDown)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpButDesiredIsDown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::DrainingToDisk; // To force a change of state + tapeDrive.desiredUp = false; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().driveStatus, cta::common::dataStructures::DriveStatus::Down); + ASSERT_EQ(storedTapeDrive.value().reasonUpDown.value(), inputs.reason); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpCleanSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + tapeDrive.diskSystemName = "DISK_SYSTEM_NAME"; + tapeDrive.reservedBytes = 123456789; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUpDontCleanSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Up; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.reason = "testing"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(storedTapeDrive.value().diskSystemName); + ASSERT_FALSE(storedTapeDrive.value().reservedBytes); + ASSERT_FALSE(storedTapeDrive.value().reservationSessionId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusProbing) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Probing; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::NoMount; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 0; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_EQ(storedTapeDrive.value().probeStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVid)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentTapePool)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentVo)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusStarting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Starting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_EQ(storedTapeDrive.value().sessionStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_EQ(storedTapeDrive.value().currentActivity.value(), inputs.activity); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusMounting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Mounting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 0; + inputs.filesTransferred = 0; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_EQ(storedTapeDrive.value().mountStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusTransfering) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Transferring; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_EQ(storedTapeDrive.value().bytesTransferedInSession.value(), inputs.byteTransferred); + ASSERT_EQ(storedTapeDrive.value().filesTransferedInSession.value(), inputs.filesTransferred); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_EQ(storedTapeDrive.value().sessionElapsedTime.value(), 0); // Because it's starting + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_EQ(storedTapeDrive.value().transferStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUnloading) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Unloading; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_EQ(storedTapeDrive.value().unloadStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusUnmounting) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Unmounting; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_EQ(storedTapeDrive.value().unmountStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusDrainingToDisk) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::DrainingToDisk; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_EQ(storedTapeDrive.value().drainingStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusCleaningUp) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::CleaningUp; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_EQ(storedTapeDrive.value().sessionId.value(), inputs.mountSessionId); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_EQ(storedTapeDrive.value().cleanupStartTime.value(), inputs.reportTime); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().shutdownTime)); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, updateTapeDriveStatusShutdown) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.driveStatus = cta::common::dataStructures::DriveStatus::Down; // To force a change of state + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::ReportDriveStatusInputs inputs; + inputs.status = cta::common::dataStructures::DriveStatus::Shutdown; + // We use a different MountType to check it doesn't update this value in the database + inputs.mountType = cta::common::dataStructures::MountType::ArchiveForUser; + inputs.reportTime = time(nullptr); + inputs.mountSessionId = 123456; + inputs.byteTransferred = 987654; + inputs.filesTransferred = 456; + inputs.vid = "vid"; + inputs.tapepool = "tapepool"; + inputs.vo = "vo"; + inputs.activity = "activity"; + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName = tapeDrive.driveName; + driveInfo.host = tapeDrive.host; + driveInfo.logicalLibrary = tapeDrive.logicalLibrary; + { + cta::log::LogContext dummyLc(m_dummyLog); + auto tapeDrivesState = std::make_unique<cta::TapeDrivesCatalogueState>(*m_catalogue); + tapeDrivesState->updateDriveStatus(driveInfo, inputs, dummyLc); + } + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionId)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().bytesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().filesTransferedInSession)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().sessionElapsedTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().mountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().transferStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unloadStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().unmountStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().drainingStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().downOrUpStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().probeStartTime)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().cleanupStartTime)); + ASSERT_EQ(storedTapeDrive.value().shutdownTime.value(), inputs.reportTime); + const auto log = cta::common::dataStructures::EntryLog("NO_USER", driveInfo.host, inputs.reportTime); + ASSERT_EQ(storedTapeDrive.value().lastModificationLog.value(), log); + ASSERT_EQ(storedTapeDrive.value().mountType, inputs.mountType); + ASSERT_EQ(storedTapeDrive.value().driveStatus, inputs.status); + ASSERT_EQ(storedTapeDrive.value().currentVid.value(), inputs.vid); + ASSERT_EQ(storedTapeDrive.value().currentTapePool.value(), inputs.tapepool); + ASSERT_EQ(storedTapeDrive.value().currentVo.value(), inputs.vo); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().currentActivity)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + + +TEST_P(cta_catalogue_DriveStateTest, addDiskSpaceReservationWhenItsNull) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = "space1"; + const uint64_t reservedBytes = 987654; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 123; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, incrementAnExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 852; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes + tapeDrive.reservedBytes.value()); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, decrementANonExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = std::nullopt; + tapeDrive.reservedBytes = std::nullopt; + tapeDrive.reservationSessionId = std::nullopt; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request; + const std::string spaceName = "space1"; + const uint64_t reservedBytes = 852; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 123; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request, dummyLc); + + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_FALSE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, decrementAExistingDiskSpaceReservation) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest request1; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 852; + request1.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request1, dummyLc); + + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive1.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive1.value().reservedBytes.value(), tapeDrive.reservedBytes.value() - reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive1.value().reservationSessionId.value(), mountId); + + cta::DiskSpaceReservationRequest request2; + request2.addRequest(tapeDrive.diskSystemName.value(), tapeDrive.reservedBytes.value() - reservedBytes); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, request2, dummyLc); + + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive2.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive2.value().reservedBytes.value(), 0); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive2.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, incrementAnExistingDiskSpaceReservationAndThenLargerDecrement) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "existing_space"; + tapeDrive.reservedBytes = 10; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + cta::DiskSpaceReservationRequest increaseRequest; + const std::string spaceName = tapeDrive.diskSystemName.value(); + const uint64_t reservedBytes = 20; + increaseRequest.addRequest(spaceName, reservedBytes); + const uint64_t mountId = tapeDrive.reservationSessionId.value(); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, increaseRequest, dummyLc); + + const auto storedTapeDrive1 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive1.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive1.value().reservedBytes.value(), reservedBytes + tapeDrive.reservedBytes.value()); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive1.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive1.value().reservationSessionId.value(), mountId); + + cta::DiskSpaceReservationRequest decreaseRequest; + decreaseRequest.addRequest(tapeDrive.diskSystemName.value(), 100000); // Decrease a bigger number of reserved bytes + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, decreaseRequest, dummyLc); + + const auto storedTapeDrive2 = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive2.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive2.value().reservedBytes.value(), 0); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive2.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive2.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToIncrementAnOldDiskSystem) { + const std::string tapeDriveName = "VDSTK11"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = "old_space"; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest newRequest; + const std::string spaceName = "new_space"; + const uint64_t reservedBytes = 345; + newRequest.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, newRequest, dummyLc); + + // Decrease Old Space + cta::DiskSpaceReservationRequest oldRequest; + oldRequest.addRequest(tapeDrive.diskSystemName.value(), tapeDrive.reservedBytes.value()); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, tapeDrive.reservationSessionId.value(), oldRequest, + dummyLc); + + // Check it keeps the new disk space system values + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), spaceName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, sameSystemNameButDifferentMountID) { + const std::string tapeDriveName = "VDSTK11"; + const std::string diskSystemName = "space_name"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = diskSystemName; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest request; + const std::string spaceName = diskSystemName; + const uint64_t reservedBytes = 345; + request.addRequest(spaceName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, request, dummyLc); + + // Check it keeps the new disk space system values + const auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +TEST_P(cta_catalogue_DriveStateTest, failToDecrementAnOldMountIDAndDecrementNewAgain) { + const std::string tapeDriveName = "VDSTK11"; + const std::string diskSystemName = "space_name"; + auto tapeDrive = getTapeDriveWithMandatoryElements(tapeDriveName); + tapeDrive.diskSystemName = diskSystemName; + tapeDrive.reservedBytes = 1234; + tapeDrive.reservationSessionId = 9; + m_catalogue->DriveState()->createTapeDrive(tapeDrive); + + // New Disk Space + cta::DiskSpaceReservationRequest newRequest; + const uint64_t reservedBytes = 345; + newRequest.addRequest(diskSystemName, reservedBytes); + const uint64_t mountId = 3; + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->DriveState()->reserveDiskSpace(tapeDriveName, mountId, newRequest, dummyLc); + + // Decrease Old Space + cta::DiskSpaceReservationRequest oldRequest; + oldRequest.addRequest(diskSystemName, tapeDrive.reservedBytes.value()); + + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, tapeDrive.reservationSessionId.value(), oldRequest, dummyLc); + + // Check it keeps the new disk space system values + auto storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + // Decrease New Space + cta::DiskSpaceReservationRequest decreaseRequest; + const uint64_t decreasedBytes = 10; + decreaseRequest.addRequest(diskSystemName, decreasedBytes); + m_catalogue->DriveState()->releaseDiskSpace(tapeDriveName, mountId, decreaseRequest, dummyLc); + + // Check it keeps the new disk space system values + storedTapeDrive = m_catalogue->DriveState()->getTapeDrive(tapeDrive.driveName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().diskSystemName)); + ASSERT_EQ(storedTapeDrive.value().diskSystemName.value(), diskSystemName); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservedBytes)); + ASSERT_EQ(storedTapeDrive.value().reservedBytes.value(), reservedBytes - decreasedBytes); + ASSERT_TRUE(static_cast<bool>(storedTapeDrive.value().reservationSessionId)); + ASSERT_EQ(storedTapeDrive.value().reservationSessionId.value(), mountId); + + m_catalogue->DriveState()->deleteTapeDrive(tapeDrive.driveName); +} + +} // namespace unitTests diff --git a/catalogue/tests/modules/DriveStateCatalogueTest.hpp b/catalogue/tests/modules/DriveStateCatalogueTest.hpp new file mode 100644 index 0000000000..1d9f1aa16e --- /dev/null +++ b/catalogue/tests/modules/DriveStateCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_DriveStateTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_DriveStateTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/FileRecycleLogCatalogueTest.cpp b/catalogue/tests/modules/FileRecycleLogCatalogueTest.cpp new file mode 100644 index 0000000000..2beffac555 --- /dev/null +++ b/catalogue/tests/modules/FileRecycleLogCatalogueTest.cpp @@ -0,0 +1,1122 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2021-2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/interfaces/FileRecycleLogCatalogue.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/rdbms/RdbmsCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/DummyLogger.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_FileRecycleLogTest::cta_catalogue_FileRecycleLogTest() + : m_dummyLog("dummy", "dummy"), + m_tape1(CatalogueTestUtils::getTape1()), + m_tape2(CatalogueTestUtils::getTape2()), + m_tape3(CatalogueTestUtils::getTape3()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_storageClassDualCopy(CatalogueTestUtils::getStorageClassDualCopy()), + m_storageClassTripleCopy(CatalogueTestUtils::getStorageClassTripleCopy()) { +} + +void cta_catalogue_FileRecycleLogTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_FileRecycleLogTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_FileRecycleLogTest, reclaimTapeRemovesFilesFromRecycleLog) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapeDrive = "tape_drive"; + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + auto tape2 = m_tape2; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t nbArchiveFiles = 10; // Must be a multiple of 2 for this test + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + std::ostringstream diskFilePath; + diskFilePath << "/test/file"<<i; + + // Tape copy 1 written to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassSingleCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + { + ASSERT_TRUE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + } + log::LogContext dummyLc(m_dummyLog); + for (auto & tapeItemWritten: tapeFilesWrittenCopy1){ + auto tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get()); + cta::common::dataStructures::DeleteArchiveRequest req; + req.archiveFileID = tapeItem->archiveFileId; + req.diskFileId = tapeItem->diskFileId; + req.diskFilePath = tapeItem->diskFilePath; + req.diskInstance = tapeItem->diskInstance; + req.archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(tapeItem->archiveFileId); + ASSERT_NO_THROW(m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(req,dummyLc)); + } + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + std::vector<common::dataStructures::FileRecycleLog> deletedArchiveFiles; + { + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + while(itor.hasMore()){ + deletedArchiveFiles.push_back(itor.next()); + } + } + + //And test that these files are in the recycle log + ASSERT_EQ(nbArchiveFiles,deletedArchiveFiles.size()); + + ASSERT_TRUE(m_catalogue->FileRecycleLog()->getFileRecycleLogItor().hasMore()); + //Reclaim the tape + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, true); + m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc); + { + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_FALSE(itor.hasMore()); + } +} + +TEST_P(cta_catalogue_FileRecycleLogTest, emptyFileRecycleLogItorTest) { + using namespace cta; + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_FALSE(itor.hasMore()); + ASSERT_THROW(itor.next(),cta::exception::Exception); +} + +TEST_P(cta_catalogue_FileRecycleLogTest, getFileRecycleLogItorVidNotExists) { + using namespace cta; + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_FALSE(m_catalogue->FileRecycleLog()->getFileRecycleLogItor().hasMore()); + + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.vid = "NOT_EXISTS"; + + ASSERT_THROW(m_catalogue->FileRecycleLog()->getFileRecycleLogItor(criteria),exception::UserError); +} + +TEST_P(cta_catalogue_FileRecycleLogTest, filesArePutInTheFileRecycleLogInsteadOfBeingSuperseded) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + auto tape2 = m_tape2; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t nbArchiveFiles = 10; // Must be a multiple of 2 for this test + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + std::ostringstream diskFilePath; + diskFilePath << "/test/file"<<i; + + // Tape copy 1 written to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassSingleCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + { + ASSERT_TRUE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_FALSE(m_catalogue->FileRecycleLog()->getFileRecycleLogItor().hasMore()); + } + log::LogContext dummyLc(m_dummyLog); + //Archive the same files but in a new tape + for(auto & tapeItemWritten: tapeFilesWrittenCopy1){ + auto tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get()); + tapeItem->vid = tape2.vid; + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + //Change the vid back to the first one to test the content of the file recycle log afterwards + for(auto & tapeItemWritten: tapeFilesWrittenCopy1){ + auto tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get()); + tapeItem->vid = tape1.vid; + } + //Check that the new files written exist on the catalogue + { + auto archiveFilesItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + bool hasArchiveFilesItor = false; + while(archiveFilesItor.hasMore()){ + hasArchiveFilesItor = true; + //The vid is the destination one + ASSERT_EQ(tape2.vid, archiveFilesItor.next().tapeFiles.at(1).vid); + } + ASSERT_TRUE(hasArchiveFilesItor); + } + //Check that the old files are in the file recycle logs + std::list<common::dataStructures::FileRecycleLog> fileRecycleLogs; + { + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + while(fileRecycleLogItor.hasMore()){ + fileRecycleLogs.push_back(fileRecycleLogItor.next()); + } + ASSERT_FALSE(fileRecycleLogs.empty()); + //Now we check the consistency of what is returned by the file recycle log + for(const auto& fileRecycleLog: fileRecycleLogs){ + //First, get the correct file written to tape associated to the current fileRecycleLog + auto tapeFilesWrittenCopy1Itor = std::find_if(tapeFilesWrittenCopy1.begin(), tapeFilesWrittenCopy1.end(), + [&fileRecycleLog](const cta::catalogue::TapeItemWrittenPointer & item) { + auto fileWrittenPtr = static_cast<cta::catalogue::TapeFileWritten *>(item.get()); + return fileWrittenPtr->archiveFileId == fileRecycleLog.archiveFileId; + }); + + ASSERT_NE(tapeFilesWrittenCopy1.end(), tapeFilesWrittenCopy1Itor); + auto fileWrittenPtr = static_cast<cta::catalogue::TapeFileWritten *>(tapeFilesWrittenCopy1Itor->get()); + ASSERT_EQ(fileRecycleLog.vid,tape1.vid); + ASSERT_EQ(fileRecycleLog.fSeq,fileWrittenPtr->fSeq); + ASSERT_EQ(fileRecycleLog.blockId,fileWrittenPtr->blockId); + ASSERT_EQ(fileRecycleLog.copyNb,fileWrittenPtr->copyNb); + ASSERT_EQ(fileRecycleLog.archiveFileId,fileWrittenPtr->archiveFileId); + ASSERT_EQ(fileRecycleLog.diskInstanceName,fileWrittenPtr->diskInstance); + ASSERT_EQ(fileRecycleLog.diskFileId,fileWrittenPtr->diskFileId); + ASSERT_EQ(fileRecycleLog.diskFileIdWhenDeleted,fileWrittenPtr->diskFileId); + ASSERT_EQ(fileRecycleLog.diskFileUid,fileWrittenPtr->diskFileOwnerUid); + ASSERT_EQ(fileRecycleLog.diskFileGid,fileWrittenPtr->diskFileGid); + ASSERT_EQ(fileRecycleLog.sizeInBytes,fileWrittenPtr->size); + ASSERT_EQ(fileRecycleLog.checksumBlob,fileWrittenPtr->checksumBlob); + ASSERT_EQ(fileRecycleLog.storageClassName,fileWrittenPtr->storageClassName); + ASSERT_EQ(fileRecycleLog.reconciliationTime,fileRecycleLog.archiveFileCreationTime); + ASSERT_EQ(std::nullopt, fileRecycleLog.collocationHint); + ASSERT_EQ(std::nullopt, fileRecycleLog.diskFilePath); + ASSERT_EQ(cta::catalogue::InsertFileRecycleLog::getRepackReasonLog(),fileRecycleLog.reasonLog); + } + } + { + //Check the vid search criteria + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(criteria); + int nbFileRecycleLogs = 0; + while(fileRecycleLogItor.hasMore()){ + nbFileRecycleLogs++; + fileRecycleLogItor.next(); + } + ASSERT_EQ(nbArchiveFiles,nbFileRecycleLogs); + } + { + //Check the diskFileId search criteria + std::string diskFileId = "12345678"; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.diskFileIds = std::vector<std::string>(); + criteria.diskFileIds->push_back(diskFileId); + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(criteria); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + auto fileRecycleLog = fileRecycleLogItor.next(); + ASSERT_EQ(diskFileId,fileRecycleLog.diskFileId); + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + } + { + //Check the non existing diskFileId search criteria + std::string diskFileId = "DOES_NOT_EXIST"; + catalogue::RecycleTapeFileSearchCriteria criteria; + criteria.diskFileIds = std::vector<std::string>(); + criteria.diskFileIds->push_back(diskFileId); + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->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->FileRecycleLog()->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->FileRecycleLog()->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->FileRecycleLog()->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->FileRecycleLog()->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->FileRecycleLog()->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_FileRecycleLogTest, sameFileWrittenToSameTapePutThePreviousCopyOnTheFileRecycleLog) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + + m_catalogue->Tape()->createTape(m_admin, tape1); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + // Two files same archiveFileId and CopyNb on the same tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassSingleCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + + auto & tapeItemWritten = *(tapeFilesWrittenCopy1.begin()); + auto tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get()); + tapeItem->fSeq = 2; + tapeItem->blockId = 2 *100 + 1; + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + { + auto archiveFilesItor = m_catalogue->ArchiveFile()->getArchiveFilesItor(); + ASSERT_TRUE(archiveFilesItor.hasMore()); + //The file with fseq 2 is on the active archive files of CTA + ASSERT_EQ(2,archiveFilesItor.next().tapeFiles.at(1).fSeq); + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + //The previous file (fSeq = 1) is on the recycle log + ASSERT_EQ(1,fileRecycleLogItor.next().fSeq); + } +} + +TEST_P(cta_catalogue_FileRecycleLogTest, RestoreTapeFileCopy) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert both copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape1 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + } + + + { + // restore copy of file on tape1 + catalogue::RecycleTapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + searchCriteria.vid = tape1.vid; + + // new FID does not matter because archive file still exists in catalogue + m_catalogue->FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, "0"); + + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + //assert both copies present + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + //assert recycle log is empty + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + + } +} + +TEST_P(cta_catalogue_FileRecycleLogTest, RestoreRewrittenTapeFileCopyFails) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert both copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape1 + + //delete copy of file on tape1 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + } + + // Rewrite deleted copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 2; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + { + //restore copy of file on tape1 + catalogue::RecycleTapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + searchCriteria.vid = tape1.vid; + + ASSERT_THROW(m_catalogue->FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, "0"), + catalogue::UserSpecifiedExistingDeletedFileCopy); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + //assert only two copies present + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + //assert recycle log still contains deleted copy + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + } +} + +TEST_P(cta_catalogue_FileRecycleLogTest, RestoreVariousDeletedTapeFileCopies) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const std::string tapePoolName3 = "tape_pool_name_3"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName3, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassTripleCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + auto tape3 = m_tape3; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + tape3.tapePoolName = tapePoolName3; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + m_catalogue->Tape()->createTape(m_admin, tape3); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassTripleCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassTripleCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a third copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassTripleCopy.name; + fileWritten.vid = tape3.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 3; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert all copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(3, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape1 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape2 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape2.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + } + + + { + //try to restore all deleted copies should give an error + catalogue::RecycleTapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + + ASSERT_THROW(m_catalogue->FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, "0"), + cta::exception::UserError); + } +} + +TEST_P(cta_catalogue_FileRecycleLogTest, RestoreArchiveFileAndCopy) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert both copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete archive file + common::dataStructures::DeleteArchiveRequest deleteRequest; + deleteRequest.archiveFileID = 1; + deleteRequest.archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + deleteRequest.diskInstance = diskInstance; + deleteRequest.diskFileId = std::to_string(12345677); + deleteRequest.diskFilePath = "/test/file1"; + + log::LogContext dummyLc(m_dummyLog); + m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(deleteRequest, dummyLc); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(1), cta::exception::Exception); + } + + + { + //restore copy of file on tape1 + catalogue::RecycleTapeFileSearchCriteria searchCriteria; + searchCriteria.archiveFileId = 1; + searchCriteria.vid = tape1.vid; + + m_catalogue->FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, std::to_string(12345678)); //previous fid + 1 + + //assert archive file has been restored in the catalogue + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + ASSERT_EQ(archiveFile.diskFileId, std::to_string(12345678)); + ASSERT_EQ(archiveFile.diskInstance, diskInstance); + ASSERT_EQ(archiveFile.storageClass, m_storageClassDualCopy.name); + + //assert recycle log has the other tape file copy + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + auto fileRecycleLog = fileRecycleLogItor.next(); + ASSERT_FALSE(fileRecycleLogItor.hasMore()); + } +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp b/catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp new file mode 100644 index 0000000000..461daafe47 --- /dev/null +++ b/catalogue/tests/modules/FileRecycleLogCatalogueTest.hpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/log/DummyLogger.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/dataStructures/StorageClass.hpp" + +namespace unitTests { + +class cta_catalogue_FileRecycleLogTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_FileRecycleLogTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + const cta::catalogue::CreateTapeAttributes m_tape1; + const cta::catalogue::CreateTapeAttributes m_tape2; + const cta::catalogue::CreateTapeAttributes m_tape3; + const cta::catalogue::MediaType m_mediaType; + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::StorageClass m_storageClassDualCopy; + const cta::common::dataStructures::StorageClass m_storageClassTripleCopy; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/LogicalLibraryCatalogueTest.cpp b/catalogue/tests/modules/LogicalLibraryCatalogueTest.cpp new file mode 100644 index 0000000000..d2db960d3c --- /dev/null +++ b/catalogue/tests/modules/LogicalLibraryCatalogueTest.cpp @@ -0,0 +1,751 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/TapePool.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/EntryLog.hpp" +#include "common/dataStructures/LogicalLibrary.hpp" +#include "common/dataStructures/Tape.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_LogicalLibraryTest::cta_catalogue_LogicalLibraryTest() + : m_dummyLog("dummy", "dummy"), + m_admin("admin", "admin", "admin"), + m_vo(CatalogueTestUtils::getVo()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_tape1(CatalogueTestUtils::getTape1()) { +} + +void cta_catalogue_LogicalLibraryTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_LogicalLibraryTest::TearDown() { + m_catalogue.reset(); +} + +std::map<std::string, cta::common::dataStructures::LogicalLibrary> + cta_catalogue_LogicalLibraryTest::logicalLibraryListToMap( + const std::list<cta::common::dataStructures::LogicalLibrary> &listOfLibs) const { + try { + std::map<std::string, cta::common::dataStructures::LogicalLibrary> nameToLib; + + for (auto &lib: listOfLibs) { + if(nameToLib.end() != nameToLib.find(lib.name)) { + throw cta::exception::Exception(std::string("Duplicate logical library: value=") + lib.name); + } + nameToLib[lib.name] = lib; + } + + return nameToLib; + } catch(cta::exception::Exception &ex) { + throw cta::exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, createLogicalLibrary) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, createLogicalLibrary_disabled_true) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled(true); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_TRUE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, createLogicalLibrary_disabled_false) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled(false); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, createLogicalLibrary_same_twice) { + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + ASSERT_THROW(m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, + logicalLibraryIsDisabled, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, setLogicalLibraryDisabled_true) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + + { + const std::list<cta::common::dataStructures::LogicalLibrary> libs = + m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const bool modifiedLogicalLibraryIsDisabled= true; + m_catalogue->LogicalLibrary()->setLogicalLibraryDisabled(m_admin, logicalLibraryName, + modifiedLogicalLibraryIsDisabled); + + { + const std::list<cta::common::dataStructures::LogicalLibrary> libs = + m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(modifiedLogicalLibraryIsDisabled, lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, setLogicalLibraryDisabled_false) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + + { + const std::list<cta::common::dataStructures::LogicalLibrary> libs = + m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_FALSE(lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const bool modifiedLogicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->setLogicalLibraryDisabled(m_admin, logicalLibraryName, + modifiedLogicalLibraryIsDisabled); + + { + const std::list<cta::common::dataStructures::LogicalLibrary> libs = + m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(modifiedLogicalLibraryIsDisabled, lib.isDisabled); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, deleteLogicalLibrary) { + const bool libNotToDeleteIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string libNotToDeleteComment = "Create logical library to NOT be deleted"; + + // Create a tape and a logical library that are not the ones to be deleted + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, libNotToDeleteIsDisabled, + libNotToDeleteComment); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + ASSERT_EQ(1, libs.size()); + const auto lib = libs.front(); + ASSERT_EQ(m_tape1.logicalLibraryName, lib.name); + ASSERT_EQ(libNotToDeleteIsDisabled, lib.isDisabled); + ASSERT_EQ(libNotToDeleteComment, lib.comment); + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + m_catalogue->Tape()->createTape(m_admin, m_tape1); + ASSERT_TRUE(m_catalogue->Tape()->tapeExists(m_tape1.vid)); + { + const auto tapes = m_catalogue->Tape()->getTapes(); + ASSERT_EQ(1, tapes.size()); + + const auto tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + // Create the logical library to be deleted + const std::string libToDeleteName = "lib_to_delete"; + const bool libToDeleteIsDisabled = false; + const std::string libToDeleteComment = "Create logical library to be deleted"; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, libToDeleteName, libToDeleteIsDisabled, + libToDeleteComment); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + ASSERT_EQ(2, libs.size()); + const auto nameToLib = logicalLibraryListToMap(libs); + ASSERT_EQ(2, nameToLib.size()); + + { + const auto nameToLibItor = nameToLib.find(m_tape1.logicalLibraryName); + ASSERT_NE(nameToLib.end(), nameToLibItor); + const auto &lib = nameToLibItor->second; + ASSERT_EQ(m_tape1.logicalLibraryName, lib.name); + ASSERT_EQ(libNotToDeleteIsDisabled, lib.isDisabled); + ASSERT_EQ(libNotToDeleteComment, lib.comment); + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto nameToLibItor = nameToLib.find(libToDeleteName); + ASSERT_NE(nameToLib.end(), nameToLibItor); + const auto &lib = nameToLibItor->second; + ASSERT_EQ(libToDeleteName, lib.name); + ASSERT_EQ(libToDeleteIsDisabled, lib.isDisabled); + ASSERT_EQ(libToDeleteComment, lib.comment); + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + m_catalogue->LogicalLibrary()->deleteLogicalLibrary(libToDeleteName); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + ASSERT_EQ(1, libs.size()); + const auto lib = libs.front(); + ASSERT_EQ(m_tape1.logicalLibraryName, lib.name); + ASSERT_EQ(libNotToDeleteIsDisabled, lib.isDisabled); + ASSERT_EQ(libNotToDeleteComment, lib.comment); + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, deleteLogicalLibrary_non_existent) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + ASSERT_THROW(m_catalogue->LogicalLibrary()->deleteLogicalLibrary("non_existent_logical_library"), + cta::catalogue::UserSpecifiedANonExistentLogicalLibrary); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, deleteLogicalLibrary_non_empty) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + ASSERT_THROW(m_catalogue->LogicalLibrary()->deleteLogicalLibrary(m_tape1.logicalLibraryName), + cta::catalogue::UserSpecifiedANonEmptyLogicalLibrary); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryName) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string libraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool libraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, libraryName, libraryIsDisabled, comment); + + { + const auto libraries = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libraries.size()); + + const auto &library = libraries.front(); + ASSERT_EQ(libraryName, library.name); + ASSERT_FALSE(library.isDisabled); + ASSERT_EQ(comment, library.comment); + + const cta::common::dataStructures::EntryLog creationLog = library.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = library.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newLibraryName = "new_logical_library"; + m_catalogue->LogicalLibrary()->modifyLogicalLibraryName(m_admin, libraryName, newLibraryName); + + { + const auto libraries = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libraries.size()); + + const auto &library = libraries.front(); + ASSERT_EQ(newLibraryName, library.name); + ASSERT_FALSE(library.isDisabled); + ASSERT_EQ(comment, library.comment); + + const cta::common::dataStructures::EntryLog creationLog = library.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryName_emptyStringCurrentLogicalLibraryName) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string libraryName = "logical_library"; + const bool libraryIsDisabled = false; + const std::string comment = "Create logical library"; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, libraryName, libraryIsDisabled, comment); + + const std::string newLibraryName = "new_logical_library"; + ASSERT_THROW(m_catalogue->LogicalLibrary()->modifyLogicalLibraryName(m_admin, "", newLibraryName), + cta::catalogue::UserSpecifiedAnEmptyStringLogicalLibraryName); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryName_emptyStringNewLogicalLibraryName) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string libraryName = "logical_library"; + const bool libraryIsDisabled = false; + const std::string comment = "Create logical library"; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, libraryName, libraryIsDisabled, comment); + + { + const auto libraries = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libraries.size()); + + const auto library = libraries.front(); + ASSERT_EQ(libraryName, library.name); + ASSERT_FALSE(library.isDisabled); + ASSERT_EQ(comment, library.comment); + + const cta::common::dataStructures::EntryLog creationLog = library.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = library.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newLibraryName = ""; + ASSERT_THROW(m_catalogue->LogicalLibrary()->modifyLogicalLibraryName(m_admin, libraryName, newLibraryName), + cta::catalogue::UserSpecifiedAnEmptyStringLogicalLibraryName); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryComment) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(comment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->LogicalLibrary()->modifyLogicalLibraryComment(m_admin, logicalLibraryName, modifiedComment); + + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(modifiedComment, lib.comment); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryComment_nonExisentLogicalLibrary) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + ASSERT_THROW(m_catalogue->LogicalLibrary()->modifyLogicalLibraryComment(m_admin, logicalLibraryName, comment), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryDisabledReason) { + using namespace cta; + + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string comment = "Create logical library"; + const bool logicalLibraryIsDisabled= false; + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + comment); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(comment, lib.comment); + ASSERT_FALSE(lib.disabledReason); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedDisabledReason = "Modified disabled reason"; + m_catalogue->LogicalLibrary()->modifyLogicalLibraryDisabledReason(m_admin, logicalLibraryName, + modifiedDisabledReason); + + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(comment, lib.comment); + ASSERT_EQ(modifiedDisabledReason, lib.disabledReason.value()); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + } + + //setting empty reason should delete it from the DB + m_catalogue->LogicalLibrary()->modifyLogicalLibraryDisabledReason(m_admin, logicalLibraryName, ""); + { + const auto libs = m_catalogue->LogicalLibrary()->getLogicalLibraries(); + + ASSERT_EQ(1, libs.size()); + + const cta::common::dataStructures::LogicalLibrary lib = libs.front(); + ASSERT_EQ(logicalLibraryName, lib.name); + ASSERT_EQ(comment, lib.comment); + ASSERT_FALSE(lib.disabledReason); + + const cta::common::dataStructures::EntryLog creationLog = lib.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = lib.lastModificationLog; + } +} + +TEST_P(cta_catalogue_LogicalLibraryTest, modifyLogicalLibraryDisabledReason_nonExisentLogicalLibrary) { + ASSERT_TRUE(m_catalogue->LogicalLibrary()->getLogicalLibraries().empty()); + + const std::string logicalLibraryName = "logical_library"; + const std::string disabledReason = "Create logical library"; + ASSERT_THROW(m_catalogue->LogicalLibrary()->modifyLogicalLibraryDisabledReason(m_admin, logicalLibraryName, + disabledReason), cta::exception::UserError); +} + + +TEST_P(cta_catalogue_LogicalLibraryTest, tapeExists_emptyString) { + const std::string vid = ""; + ASSERT_THROW(m_catalogue->Tape()->tapeExists(vid), cta::exception::Exception); +} + +TEST_P(cta_catalogue_LogicalLibraryTest, createTape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + ASSERT_TRUE(m_catalogue->Tape()->tapeExists(m_tape1.vid)); + + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + { + const auto tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } +} + + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp b/catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp new file mode 100644 index 0000000000..ff23e3fb3a --- /dev/null +++ b/catalogue/tests/modules/LogicalLibraryCatalogueTest.hpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_LogicalLibraryTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_LogicalLibraryTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::catalogue::MediaType m_mediaType; + const cta::catalogue::CreateTapeAttributes m_tape1; + + std::map<std::string, cta::common::dataStructures::LogicalLibrary> logicalLibraryListToMap( + const std::list<cta::common::dataStructures::LogicalLibrary> &listOfLibs) const; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/MediaTypeCatalogueTest.cpp b/catalogue/tests/modules/MediaTypeCatalogueTest.cpp new file mode 100644 index 0000000000..10f17d1269 --- /dev/null +++ b/catalogue/tests/modules/MediaTypeCatalogueTest.cpp @@ -0,0 +1,788 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <optional> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/MediaTypeCatalogueTest.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_MediaTypeTest::cta_catalogue_MediaTypeTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_tape1(CatalogueTestUtils::getTape1()) { +} + +void cta_catalogue_MediaTypeTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_MediaTypeTest::TearDown() { + m_catalogue.reset(); +} + +std::map<std::string, cta::catalogue::MediaTypeWithLogs> cta_catalogue_MediaTypeTest::mediaTypeWithLogsListToMap( + const std::list<cta::catalogue::MediaTypeWithLogs> &listOfMediaTypes) { + try { + std::map<std::string, cta::catalogue::MediaTypeWithLogs> m; + + for(auto &mediaType: listOfMediaTypes) { + if(m.end() != m.find(mediaType.name)) { + cta::exception::Exception ex; + ex.getMessage() << "Media type " << mediaType.name << " is a duplicate"; + throw ex; + } + m[mediaType.name] = mediaType; + } + return m; + } catch(cta::exception::Exception &ex) { + throw cta::exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType_same_twice) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + ASSERT_THROW(m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType_emptyStringMediaTypeName) { + auto mediaType = m_mediaType; + mediaType.name = ""; + ASSERT_THROW(m_catalogue->MediaType()->createMediaType(m_admin, mediaType), + cta::catalogue::UserSpecifiedAnEmptyStringMediaTypeName); +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType_emptyStringComment) { + auto mediaType = m_mediaType; + mediaType.comment = ""; + ASSERT_THROW(m_catalogue->MediaType()->createMediaType(m_admin, mediaType), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType_emptyStringCartridge) { + auto mediaType = m_mediaType; + mediaType.cartridge = ""; + ASSERT_THROW(m_catalogue->MediaType()->createMediaType(m_admin, mediaType), + cta::catalogue::UserSpecifiedAnEmptyStringCartridge); +} + +TEST_P(cta_catalogue_MediaTypeTest, createMediaType_zeroCapacity) { + auto mediaType = m_mediaType; + mediaType.capacityInBytes = 0; + ASSERT_THROW(m_catalogue->MediaType()->createMediaType(m_admin, mediaType), + cta::catalogue::UserSpecifiedAZeroCapacity); +} + +TEST_P(cta_catalogue_MediaTypeTest, deleteMediaType) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->MediaType()->deleteMediaType(m_mediaType.name); + + ASSERT_TRUE(m_catalogue->MediaType()->getMediaTypes().empty()); +} + +TEST_P(cta_catalogue_MediaTypeTest, deleteMediaType_nonExistentMediaType) { + ASSERT_THROW(m_catalogue->MediaType()->deleteMediaType("media_type"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, deleteMediaType_usedByTapes) { + cta::log::LogContext dummyLc(m_dummyLog); + const bool logicalLibraryIsDisabled = false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + //Media type is used by at least one tape, deleting it should throw an exception + ASSERT_THROW(m_catalogue->MediaType()->deleteMediaType(m_tape1.mediaType), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeName) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newMediaTypeName = "new_media_type"; + m_catalogue->MediaType()->modifyMediaTypeName(m_admin, m_mediaType.name, newMediaTypeName); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(newMediaTypeName, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeName_nonExistentMediaType) { + const std::string currentName = "media_type"; + const std::string newName = "new_media_type"; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeName(m_admin, currentName, newName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeName_newNameAlreadyExists) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + auto mediaType2 = m_mediaType; + mediaType2.name = "media_type_2"; + + m_catalogue->MediaType()->createMediaType(m_admin, mediaType2); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(2, mediaTypes.size()); + + const auto mediaTypeMap = mediaTypeWithLogsListToMap(mediaTypes); + + ASSERT_EQ(2, mediaTypeMap.size()); + + auto mediaType1Itor = mediaTypeMap.find(m_mediaType.name); + ASSERT_TRUE(mediaType1Itor != mediaTypeMap.end()); + + ASSERT_EQ(m_mediaType.name, mediaType1Itor->second.name); + ASSERT_EQ(m_mediaType.cartridge, mediaType1Itor->second.cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaType1Itor->second.capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaType1Itor->second.primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaType1Itor->second.secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaType1Itor->second.nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaType1Itor->second.minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaType1Itor->second.maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaType1Itor->second.comment); + + const cta::common::dataStructures::EntryLog creationLog1 = mediaType1Itor->second.creationLog; + ASSERT_EQ(m_admin.username, creationLog1.username); + ASSERT_EQ(m_admin.host, creationLog1.host); + + const cta::common::dataStructures::EntryLog lastModificationLog1 = mediaType1Itor->second.lastModificationLog; + ASSERT_EQ(creationLog1, lastModificationLog1); + + auto mediaType2Itor = mediaTypeMap.find(mediaType2.name); + ASSERT_TRUE(mediaType2Itor != mediaTypeMap.end()); + + ASSERT_EQ(mediaType2.name, mediaType2Itor->second.name); + ASSERT_EQ(mediaType2.cartridge, mediaType2Itor->second.cartridge); + ASSERT_EQ(mediaType2.capacityInBytes, mediaType2Itor->second.capacityInBytes); + ASSERT_EQ(mediaType2.primaryDensityCode, mediaType2Itor->second.primaryDensityCode); + ASSERT_EQ(mediaType2.secondaryDensityCode, mediaType2Itor->second.secondaryDensityCode); + ASSERT_EQ(mediaType2.nbWraps, mediaType2Itor->second.nbWraps); + ASSERT_EQ(mediaType2.minLPos, mediaType2Itor->second.minLPos); + ASSERT_EQ(mediaType2.maxLPos, mediaType2Itor->second.maxLPos); + ASSERT_EQ(mediaType2.comment, mediaType2Itor->second.comment); + + const cta::common::dataStructures::EntryLog creationLog2 = mediaType2Itor->second.creationLog; + ASSERT_EQ(m_admin.username, creationLog2.username); + ASSERT_EQ(m_admin.host, creationLog2.host); + + const cta::common::dataStructures::EntryLog lastModificationLog2 = mediaType2Itor->second.lastModificationLog; + ASSERT_EQ(creationLog2, lastModificationLog2); + } + + // Try to rename the first media type with the name of the second one + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeName(m_admin, m_mediaType.name, mediaType2.name), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeCartridge) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedCartridge = "new_cartridge"; + m_catalogue->MediaType()->modifyMediaTypeCartridge(m_admin, m_mediaType.name, modifiedCartridge); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(modifiedCartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeCartridge_nonExistentMediaType) { + const std::string name = "media_type"; + const std::string cartridge = "cartride"; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeCartridge(m_admin, name, cartridge), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeCapacityInBytes) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedCapacityInBytes = m_mediaType.capacityInBytes + 7; + m_catalogue->MediaType()->modifyMediaTypeCapacityInBytes(m_admin, m_mediaType.name, modifiedCapacityInBytes); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(modifiedCapacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeCapacityInBytes_nonExistentMediaType) { + const std::string name = "media_type"; + const uint64_t capacityInBytes = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeCapacityInBytes(m_admin, name, capacityInBytes), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypePrimaryDensityCode) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint8_t modifiedPrimaryDensityCode = 7; + m_catalogue->MediaType()->modifyMediaTypePrimaryDensityCode(m_admin, m_mediaType.name, modifiedPrimaryDensityCode); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(modifiedPrimaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypePrimaryDensityCode_nonExistentMediaType) { + const std::string name = "media_type"; + const uint8_t primaryDensityCode = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypePrimaryDensityCode(m_admin, name, primaryDensityCode), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeSecondaryDensityCode) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint8_t modifiedSecondaryDensityCode = 7; + m_catalogue->MediaType()->modifyMediaTypeSecondaryDensityCode(m_admin, m_mediaType.name, modifiedSecondaryDensityCode); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(modifiedSecondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeSecondaryDensityCode_nonExistentMediaType) { + const std::string name = "media_type"; + const uint8_t secondaryDensityCode = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeSecondaryDensityCode(m_admin, name, secondaryDensityCode), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeNbWraps) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint32_t modifiedNbWraps = 7; + m_catalogue->MediaType()->modifyMediaTypeNbWraps(m_admin, m_mediaType.name, modifiedNbWraps); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(modifiedNbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeNbWraps_nonExistentMediaType) { + const std::string name = "media_type"; + const uint32_t nbWraps = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeNbWraps(m_admin, name, nbWraps), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeMinLPos) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedMinLPos = 7; + m_catalogue->MediaType()->modifyMediaTypeMinLPos(m_admin, m_mediaType.name, modifiedMinLPos); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(modifiedMinLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeMinLPos_nonExistentMediaType) { + const std::string name = "media_type"; + const uint64_t minLPos = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeMinLPos(m_admin, name, minLPos), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeMaxLPos) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedMaxLPos = 7; + m_catalogue->MediaType()->modifyMediaTypeMaxLPos(m_admin, m_mediaType.name, modifiedMaxLPos); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(modifiedMaxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeMaxLPos_nonExistentMediaType) { + const std::string name = "media_type"; + const uint64_t maxLPos = 1; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeMaxLPos(m_admin, name, maxLPos), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeComment) { + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(m_mediaType.comment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = mediaTypes.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->MediaType()->modifyMediaTypeComment(m_admin, m_mediaType.name, modifiedComment); + + { + const auto mediaTypes = m_catalogue->MediaType()->getMediaTypes(); + + ASSERT_EQ(1, mediaTypes.size()); + + ASSERT_EQ(m_mediaType.name, mediaTypes.front().name); + ASSERT_EQ(m_mediaType.cartridge, mediaTypes.front().cartridge); + ASSERT_EQ(m_mediaType.capacityInBytes, mediaTypes.front().capacityInBytes); + ASSERT_EQ(m_mediaType.primaryDensityCode, mediaTypes.front().primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, mediaTypes.front().secondaryDensityCode); + ASSERT_EQ(m_mediaType.nbWraps, mediaTypes.front().nbWraps); + ASSERT_EQ(m_mediaType.minLPos, mediaTypes.front().minLPos); + ASSERT_EQ(m_mediaType.maxLPos, mediaTypes.front().maxLPos); + ASSERT_EQ(modifiedComment, mediaTypes.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = mediaTypes.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_MediaTypeTest, modifyMediaTypeComment_nonExistentMediaType) { + const std::string name = "media_type"; + const std::string comment = "Comment"; + ASSERT_THROW(m_catalogue->MediaType()->modifyMediaTypeComment(m_admin, name, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MediaTypeTest, getMediaTypeByVid_nonExistentTape) { + ASSERT_THROW(m_catalogue->MediaType()->getMediaTypeByVid("DOES_NOT_EXIST"), cta::exception::Exception); +} + +TEST_P(cta_catalogue_MediaTypeTest, getMediaTypeByVid) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + auto tapeMediaType = m_catalogue->MediaType()->getMediaTypeByVid(m_tape1.vid); + ASSERT_EQ(m_mediaType.name, tapeMediaType.name); + ASSERT_EQ(m_mediaType.capacityInBytes, tapeMediaType.capacityInBytes); + ASSERT_EQ(m_mediaType.cartridge, tapeMediaType.cartridge); + ASSERT_EQ(m_mediaType.comment, tapeMediaType.comment); + ASSERT_EQ(m_mediaType.maxLPos, tapeMediaType.maxLPos); + ASSERT_EQ(m_mediaType.minLPos, tapeMediaType.minLPos); + ASSERT_EQ(m_mediaType.nbWraps, tapeMediaType.nbWraps); + ASSERT_EQ(m_mediaType.primaryDensityCode, tapeMediaType.primaryDensityCode); + ASSERT_EQ(m_mediaType.secondaryDensityCode, tapeMediaType.secondaryDensityCode); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/MediaTypeCatalogueTest.hpp b/catalogue/tests/modules/MediaTypeCatalogueTest.hpp new file mode 100644 index 0000000000..a56c414a57 --- /dev/null +++ b/catalogue/tests/modules/MediaTypeCatalogueTest.hpp @@ -0,0 +1,65 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <list> +#include <map> +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_MediaTypeTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_MediaTypeTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::catalogue::MediaType m_mediaType; + const cta::catalogue::CreateTapeAttributes m_tape1; + + /** + * Creates a map from tape meida type name to tape media type from the + * specified list of tape media types. + * + * @param listOfMediaTypes The list of tape media types. + * @return Map from tape media type name to tape media type. + */ + std::map<std::string, cta::catalogue::MediaTypeWithLogs> mediaTypeWithLogsListToMap( + const std::list<cta::catalogue::MediaTypeWithLogs> &listOfMediaTypes); +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/MountPolicyCatalogueTest.cpp b/catalogue/tests/modules/MountPolicyCatalogueTest.cpp new file mode 100644 index 0000000000..06fd8f3182 --- /dev/null +++ b/catalogue/tests/modules/MountPolicyCatalogueTest.cpp @@ -0,0 +1,318 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/MountPolicyCatalogueTest.hpp" +#include "common/dataStructures/MountPolicy.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_MountPolicyTest::cta_catalogue_MountPolicyTest() + : m_dummyLog("dummy", "dummy"), + m_admin("admin", "host") { +} + +void cta_catalogue_MountPolicyTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_MountPolicyTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_MountPolicyTest, createMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + cta::catalogue::CreateMountPolicyAttributes mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin, mountPolicyToAdd); + + const std::list<cta::common::dataStructures::MountPolicy> mountPolicies = + m_catalogue->MountPolicy()->getMountPolicies(); + + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(mountPolicyName, mountPolicy.name); + + ASSERT_EQ(mountPolicyToAdd.archivePriority, mountPolicy.archivePriority); + ASSERT_EQ(mountPolicyToAdd.minArchiveRequestAge, mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(mountPolicyToAdd.retrievePriority, mountPolicy.retrievePriority); + ASSERT_EQ(mountPolicyToAdd.minRetrieveRequestAge, mountPolicy.retrieveMinRequestAge); + + ASSERT_EQ(mountPolicyToAdd.comment, mountPolicy.comment); + + const cta::common::dataStructures::EntryLog creationLog = mountPolicy.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + mountPolicy.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_MountPolicyTest, createMountPolicy_same_twice) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicy =CatalogueTestUtils::getMountPolicy1(); + + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicy); + + ASSERT_THROW(m_catalogue->MountPolicy()->createMountPolicy(m_admin, mountPolicy),cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, deleteMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + + ASSERT_EQ(1, mountPolicies.size()); + + m_catalogue->MountPolicy()->deleteMountPolicy(mountPolicyName); + + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); +} + +TEST_P(cta_catalogue_MountPolicyTest, deleteMountPolicy_non_existent) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + ASSERT_THROW(m_catalogue->MountPolicy()->deleteMountPolicy("non_existent_mount_policy"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, getMountPolicyByName) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + cta::catalogue::CreateMountPolicyAttributes mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin, mountPolicyToAdd); + { + const std::optional<cta::common::dataStructures::MountPolicy> mountPolicyOpt = + m_catalogue->MountPolicy()->getMountPolicy(mountPolicyName); + + ASSERT_TRUE(static_cast<bool>(mountPolicyOpt)); + + const cta::common::dataStructures::MountPolicy mountPolicy = *mountPolicyOpt; + + ASSERT_EQ(mountPolicyName, mountPolicy.name); + + ASSERT_EQ(mountPolicyToAdd.archivePriority, mountPolicy.archivePriority); + ASSERT_EQ(mountPolicyToAdd.minArchiveRequestAge, mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(mountPolicyToAdd.retrievePriority, mountPolicy.retrievePriority); + ASSERT_EQ(mountPolicyToAdd.minRetrieveRequestAge, mountPolicy.retrieveMinRequestAge); + + ASSERT_EQ(mountPolicyToAdd.comment, mountPolicy.comment); + + const cta::common::dataStructures::EntryLog creationLog = mountPolicy.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + mountPolicy.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + //non existant name + const std::optional<cta::common::dataStructures::MountPolicy> mountPolicyOpt = + m_catalogue->MountPolicy()->getMountPolicy("non existant mount policy"); + ASSERT_FALSE(static_cast<bool>(mountPolicyOpt)); + } +} + + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyArchivePriority) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const uint64_t modifiedArchivePriority = mountPolicyToAdd.archivePriority + 10; + m_catalogue->MountPolicy()->modifyMountPolicyArchivePriority(m_admin, mountPolicyToAdd.name, modifiedArchivePriority); + + { + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(modifiedArchivePriority, mountPolicy.archivePriority); + + const cta::common::dataStructures::EntryLog modificationLog = mountPolicy.lastModificationLog; + ASSERT_EQ(m_admin.username, modificationLog.username); + ASSERT_EQ(m_admin.host, modificationLog.host); + } +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyArchivePriority_nonExistentMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + const std::string name = "mount_policy"; + const uint64_t archivePriority = 1; + + ASSERT_THROW(m_catalogue->MountPolicy()->modifyMountPolicyArchivePriority(m_admin, name, archivePriority), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyArchiveMinRequestAge) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const uint64_t modifiedMinArchiveRequestAge = mountPolicyToAdd.minArchiveRequestAge + 10; + m_catalogue->MountPolicy()->modifyMountPolicyArchiveMinRequestAge(m_admin, mountPolicyToAdd.name, + modifiedMinArchiveRequestAge); + + { + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(modifiedMinArchiveRequestAge, mountPolicy.archiveMinRequestAge); + + const cta::common::dataStructures::EntryLog modificationLog = mountPolicy.lastModificationLog; + ASSERT_EQ(m_admin.username, modificationLog.username); + ASSERT_EQ(m_admin.host, modificationLog.host); + } +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyArchiveMinRequestAge_nonExistentMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + const std::string name = "mount_policy"; + const uint64_t minArchiveRequestAge = 2; + + ASSERT_THROW(m_catalogue->MountPolicy()->modifyMountPolicyArchiveMinRequestAge(m_admin, name, minArchiveRequestAge), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyRetrievePriority) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const uint64_t modifiedRetrievePriority = mountPolicyToAdd.retrievePriority + 10; + m_catalogue->MountPolicy()->modifyMountPolicyRetrievePriority(m_admin, mountPolicyToAdd.name, + modifiedRetrievePriority); + + { + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(modifiedRetrievePriority, mountPolicy.retrievePriority); + + const cta::common::dataStructures::EntryLog modificationLog = mountPolicy.lastModificationLog; + ASSERT_EQ(m_admin.username, modificationLog.username); + ASSERT_EQ(m_admin.host, modificationLog.host); + } +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyRetrievePriority_nonExistentMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + const std::string name = "mount_policy"; + const uint64_t retrievePriority = 1; + + ASSERT_THROW(m_catalogue->MountPolicy()->modifyMountPolicyRetrievePriority(m_admin, name, retrievePriority), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyRetrieveMinRequestAge) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const uint64_t modifiedMinRetrieveRequestAge = mountPolicyToAdd.minRetrieveRequestAge + 10; + m_catalogue->MountPolicy()->modifyMountPolicyRetrieveMinRequestAge(m_admin, mountPolicyToAdd.name, + modifiedMinRetrieveRequestAge); + + { + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(modifiedMinRetrieveRequestAge, mountPolicy.retrieveMinRequestAge); + + const cta::common::dataStructures::EntryLog modificationLog = mountPolicy.lastModificationLog; + ASSERT_EQ(m_admin.username, modificationLog.username); + ASSERT_EQ(m_admin.host, modificationLog.host); + } +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyRetrieveMinRequestAge_nonExistentMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + const std::string name = "mount_policy"; + const uint64_t minRetrieveRequestAge = 2; + + ASSERT_THROW(m_catalogue->MountPolicy()->modifyMountPolicyRetrieveMinRequestAge(m_admin, name, minRetrieveRequestAge), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyComment) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string modifiedComment = "Modified comment"; + m_catalogue->MountPolicy()->modifyMountPolicyComment(m_admin, mountPolicyToAdd.name, modifiedComment); + + { + const auto mountPolicies = m_catalogue->MountPolicy()->getMountPolicies(); + ASSERT_EQ(1, mountPolicies.size()); + + const cta::common::dataStructures::MountPolicy mountPolicy = mountPolicies.front(); + + ASSERT_EQ(modifiedComment, mountPolicy.comment); + + const cta::common::dataStructures::EntryLog modificationLog = mountPolicy.lastModificationLog; + ASSERT_EQ(m_admin.username, modificationLog.username); + ASSERT_EQ(m_admin.host, modificationLog.host); + } +} + +TEST_P(cta_catalogue_MountPolicyTest, modifyMountPolicyComment_nonExistentMountPolicy) { + ASSERT_TRUE(m_catalogue->MountPolicy()->getMountPolicies().empty()); + + const std::string name = "mount_policy"; + const std::string comment = "Comment"; + + ASSERT_THROW(m_catalogue->MountPolicy()->modifyMountPolicyComment(m_admin, name, comment), cta::exception::UserError); +} + +} // namespace unitTests diff --git a/catalogue/tests/modules/MountPolicyCatalogueTest.hpp b/catalogue/tests/modules/MountPolicyCatalogueTest.hpp new file mode 100644 index 0000000000..3e3d9af4ab --- /dev/null +++ b/catalogue/tests/modules/MountPolicyCatalogueTest.hpp @@ -0,0 +1,45 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_MountPolicyTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_MountPolicyTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterActivityMountRuleTest.cpp b/catalogue/tests/modules/RequesterActivityMountRuleTest.cpp new file mode 100644 index 0000000000..87eae6cf8c --- /dev/null +++ b/catalogue/tests/modules/RequesterActivityMountRuleTest.cpp @@ -0,0 +1,282 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/RequesterActivityMountRuleTest.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_RequesterActivityMountRuleTest::cta_catalogue_RequesterActivityMountRuleTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()) { +} + +void cta_catalogue_RequesterActivityMountRuleTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_RequesterActivityMountRuleTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, createRequesterActivityMountRule) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity_regex"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment); + + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterActivityMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(activityRegex, rule.activityRegex); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, createRequesterActivityMountRule_same_twice) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity_regex"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment); + + ASSERT_THROW(m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, createRequesterActivityMountRule_non_existent_mount_policy) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + const std::string comment = "Create mount rule for requester"; + const std::string mountPolicyName = "non_existent_mount_policy"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity_regex"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + ASSERT_THROW( m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, createRequesterActivityMountRule_non_existent_disk_instance) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity_regex"; + ASSERT_THROW( m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment), cta::exception::UserError); +} + + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, deleteRequesterActivityMountRule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity_regex"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment); + + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + m_catalogue->RequesterActivityMountRule()->deleteRequesterActivityMountRule(m_diskInstance.name, requesterName, + activityRegex); + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, deleteRequesterActivityMountRule_non_existent) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + ASSERT_THROW(m_catalogue->RequesterActivityMountRule()->deleteRequesterActivityMountRule("non_existent_disk_instance", + "non_existent_requester", "non_existrnt_activity"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, modifyRequesterActivityMountRulePolicy) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string anotherMountPolicyName = "another_mount_policy"; + + auto anotherMountPolicy = CatalogueTestUtils::getMountPolicy1(); + anotherMountPolicy.name = anotherMountPolicyName; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,anotherMountPolicy); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment); + + { + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterActivityMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(activityRegex, rule.activityRegex); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } + + m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRulePolicy(m_admin, m_diskInstance.name, + requesterName, activityRegex, anotherMountPolicyName); + + { + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterActivityMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(anotherMountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(activityRegex, rule.activityRegex); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, modifyRequesterActivityMountRulePolicy_nonExistentRequesterActivity) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity"; + + ASSERT_THROW(m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRulePolicy(m_admin, + m_diskInstance.name, requesterName, activityRegex, mountPolicyName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, modifyRequesterActivityMountRuleComment) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "activity"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, activityRegex, comment); + + { + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterActivityMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(activityRegex, rule.activityRegex); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRuleComment(m_admin, m_diskInstance.name, + requesterName, activityRegex, modifiedComment); + + { + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterActivityMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(modifiedComment, rule.comment); + ASSERT_EQ(activityRegex, rule.activityRegex); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterActivityMountRuleTest, modifyRequesterMountRuleComment_nonExistentRequesterActivity) { + ASSERT_TRUE(m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules().empty()); + + const std::string diskInstanceName = "disk_instance"; + const std::string requesterName = "requester_name"; + const std::string comment = "Comment"; + const std::string activityRegex = "activity"; + ASSERT_THROW(m_catalogue->RequesterActivityMountRule()->modifyRequesterActivityMountRuleComment(m_admin, + diskInstanceName, requesterName, activityRegex, comment), cta::exception::UserError); +} + + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterActivityMountRuleTest.hpp b/catalogue/tests/modules/RequesterActivityMountRuleTest.hpp new file mode 100644 index 0000000000..6416242223 --- /dev/null +++ b/catalogue/tests/modules/RequesterActivityMountRuleTest.hpp @@ -0,0 +1,47 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_RequesterActivityMountRuleTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_RequesterActivityMountRuleTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.cpp b/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.cpp new file mode 100644 index 0000000000..288c0c9a2b --- /dev/null +++ b/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.cpp @@ -0,0 +1,288 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp" +#include "common/dataStructures/RequesterGroupMountRule.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_RequesterGroupMountRuleTest::cta_catalogue_RequesterGroupMountRuleTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()) { +} + +void cta_catalogue_RequesterGroupMountRuleTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_RequesterGroupMountRuleTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, modifyRequesterGroupMountRulePolicy) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + std::string mountPolicyName = mountPolicyToAdd.name; + + const std::string anotherMountPolicyName = "another_mount_policy"; + + auto anotherMountPolicy = CatalogueTestUtils::getMountPolicy1(); + anotherMountPolicy.name = anotherMountPolicyName; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,anotherMountPolicy); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group_name"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + { + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(diskInstanceName, rule.diskInstance); + } + + m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRulePolicy(m_admin, diskInstanceName, + requesterGroupName, anotherMountPolicyName); + + { + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(anotherMountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(diskInstanceName, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, modifyRequesterGroupMountRulePolicy_nonExistentRequester) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group_name"; + + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRulePolicy(m_admin, diskInstanceName, + requesterGroupName, mountPolicyName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, modifyRequesterGroupMountRuleComment) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group_name"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + { + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(diskInstanceName, rule.diskInstance); + } + + const std::string modifiedComment = "ModifiedComment"; + m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRuleComment(m_admin, diskInstanceName, + requesterGroupName, modifiedComment); + + { + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(modifiedComment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(diskInstanceName, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, modifyRequesterGroupMountRuleComment_nonExistentRequester) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + const std::string diskInstanceName = "disk_instance"; + const std::string requesterGroupName = "requester_group_name"; + const std::string comment = "Comment"; + + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->modifyRequesterGroupMountRuleComment(m_admin, diskInstanceName, + requesterGroupName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, createRequesterGroupMountRule) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + const auto rules = + m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(diskInstanceName, rule.diskInstance); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, createRequesterGroupMountRule_same_twice) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, + diskInstanceName, requesterGroupName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, createRequesterGroupMountRule_non_existent_mount_policy) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester group"; + const std::string mountPolicyName = "non_existent_mount_policy"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, + diskInstanceName, requesterGroupName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, createRequesterGroupMountRule_non_existent_disk_instance) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, + diskInstanceName, requesterGroupName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, deleteRequesterGroupMountRule) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester group"; + const std::string diskInstanceName = m_diskInstance.name; + const std::string requesterGroupName = "requester_group"; + m_catalogue->RequesterGroupMountRule()->createRequesterGroupMountRule(m_admin, mountPolicyName, diskInstanceName, + requesterGroupName, comment); + + const auto rules = m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterGroupMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName, rule.diskInstance); + ASSERT_EQ(requesterGroupName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(diskInstanceName, rule.diskInstance); + + m_catalogue->RequesterGroupMountRule()->deleteRequesterGroupMountRule(diskInstanceName, requesterGroupName); + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); +} + +TEST_P(cta_catalogue_RequesterGroupMountRuleTest, deleteRequesterGroupMountRule_non_existent) { + ASSERT_TRUE(m_catalogue->RequesterGroupMountRule()->getRequesterGroupMountRules().empty()); + ASSERT_THROW(m_catalogue->RequesterGroupMountRule()->deleteRequesterGroupMountRule("non_existent_disk_isntance", + "non_existent_requester_group"), cta::exception::UserError); +} + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp b/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp new file mode 100644 index 0000000000..dd38240cb2 --- /dev/null +++ b/catalogue/tests/modules/RequesterGroupMountRuleCatalogueTest.hpp @@ -0,0 +1,47 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_RequesterGroupMountRuleTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_RequesterGroupMountRuleTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterMountRuleTest.cpp b/catalogue/tests/modules/RequesterMountRuleTest.cpp new file mode 100644 index 0000000000..93621f13a9 --- /dev/null +++ b/catalogue/tests/modules/RequesterMountRuleTest.cpp @@ -0,0 +1,267 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/RequesterMountRuleTest.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_RequesterMountRuleTest::cta_catalogue_RequesterMountRuleTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()) { +} + +void cta_catalogue_RequesterMountRuleTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_RequesterMountRuleTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, createRequesterMountRule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, m_diskInstance.name, + requesterName, comment); + + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, createRequesterMountRule_same_twice) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, m_diskInstance.name, + requesterName, comment); + ASSERT_THROW(m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyToAdd.name, + m_diskInstance.name, requesterName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, createRequesterMountRule_non_existent_mount_policy) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string mountPolicyName = "non_existent_mount_policy"; + const std::string requesterName = "requester_name"; + ASSERT_THROW(m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, createRequesterMountRule_non_existent_disk_instance) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + ASSERT_THROW(m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, + m_diskInstance.name, requesterName, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, deleteRequesterMountRule) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, m_diskInstance.name, + requesterName, comment); + + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + m_catalogue->RequesterMountRule()->deleteRequesterMountRule(m_diskInstance.name, requesterName); + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, deleteRequesterMountRule_non_existent) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + ASSERT_THROW(m_catalogue->RequesterMountRule()->deleteRequesterMountRule("non_existent_disk_instance", + "non_existent_requester"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, modifyRequesterMountRulePolicy) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string anotherMountPolicyName = "another_mount_policy"; + + auto anotherMountPolicy =CatalogueTestUtils::getMountPolicy1(); + anotherMountPolicy.name = anotherMountPolicyName; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,anotherMountPolicy); + + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, m_diskInstance.name, + requesterName, comment); + + { + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } + + m_catalogue->RequesterMountRule()->modifyRequesterMountRulePolicy(m_admin, m_diskInstance.name, requesterName, + anotherMountPolicyName); + + { + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(anotherMountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, modifyRequesterMountRulePolicy_nonExistentRequester) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string requesterName = "requester_name"; + + ASSERT_THROW(m_catalogue->RequesterMountRule()->modifyRequesterMountRulePolicy(m_admin, m_diskInstance.name, + requesterName, mountPolicyName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, modifyRequesteMountRuleComment) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + auto mountPolicyToAdd =CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, m_diskInstance.name, + requesterName, comment); + + { + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->RequesterMountRule()->modifyRequesteMountRuleComment(m_admin, m_diskInstance.name, requesterName, + modifiedComment); + + { + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(modifiedComment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(m_diskInstance.name, rule.diskInstance); + } +} + +TEST_P(cta_catalogue_RequesterMountRuleTest, modifyRequesteMountRuleComment_nonExistentRequester) { + ASSERT_TRUE(m_catalogue->RequesterMountRule()->getRequesterMountRules().empty()); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + const std::string requesterName = "requester_name"; + const std::string comment = "Comment"; + + ASSERT_THROW(m_catalogue->RequesterMountRule()->modifyRequesteMountRuleComment(m_admin, m_diskInstance.name, + requesterName, comment), cta::exception::UserError); +} + +} // namespace unitTests diff --git a/catalogue/tests/modules/RequesterMountRuleTest.hpp b/catalogue/tests/modules/RequesterMountRuleTest.hpp new file mode 100644 index 0000000000..eaced6e452 --- /dev/null +++ b/catalogue/tests/modules/RequesterMountRuleTest.hpp @@ -0,0 +1,47 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2023 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_RequesterMountRuleTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_RequesterMountRuleTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::DiskInstance m_diskInstance; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/SchemaCatalogueTest.cpp b/catalogue/tests/modules/SchemaCatalogueTest.cpp new file mode 100644 index 0000000000..58e5cf9468 --- /dev/null +++ b/catalogue/tests/modules/SchemaCatalogueTest.cpp @@ -0,0 +1,55 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/SchemaVersion.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/SchemaCatalogueTest.hpp" +#include "common/Constants.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_SchemaTest::cta_catalogue_SchemaTest() + : m_dummyLog("dummy", "dummy") { +} + +void cta_catalogue_SchemaTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_SchemaTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_SchemaTest, getSchemaVersion) { + const auto schemaDbVersion = m_catalogue->Schema()->getSchemaVersion(); + ASSERT_EQ(static_cast<uint64_t>(CTA_CATALOGUE_SCHEMA_VERSION_MAJOR), + schemaDbVersion.getSchemaVersion<cta::catalogue::SchemaVersion::MajorMinor>().first); + ASSERT_EQ(static_cast<uint64_t>(CTA_CATALOGUE_SCHEMA_VERSION_MINOR), + schemaDbVersion.getSchemaVersion<cta::catalogue::SchemaVersion::MajorMinor>().second); +} + +TEST_P(cta_catalogue_SchemaTest, ping) { + m_catalogue->Schema()->ping(); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/SchemaCatalogueTest.hpp b/catalogue/tests/modules/SchemaCatalogueTest.hpp new file mode 100644 index 0000000000..3f005f30f7 --- /dev/null +++ b/catalogue/tests/modules/SchemaCatalogueTest.hpp @@ -0,0 +1,41 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_SchemaTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_SchemaTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/StorageClassCatalogueTest.cpp b/catalogue/tests/modules/StorageClassCatalogueTest.cpp new file mode 100644 index 0000000000..48a1e35267 --- /dev/null +++ b/catalogue/tests/modules/StorageClassCatalogueTest.cpp @@ -0,0 +1,337 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/SchemaVersion.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/StorageClassCatalogueTest.hpp" +#include "common/Constants.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_StorageClassTest::cta_catalogue_StorageClassTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()) { +} + +void cta_catalogue_StorageClassTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_StorageClassTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + ASSERT_EQ(m_storageClassSingleCopy.vo.name, storageClasses.front().vo.name); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = storageClasses.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass_same_twice) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + ASSERT_THROW(m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass_emptyStringStorageClassName) { + auto storageClass = m_storageClassSingleCopy; + storageClass.name = ""; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + ASSERT_THROW(m_catalogue->StorageClass()->createStorageClass(m_admin, storageClass), + cta::catalogue::UserSpecifiedAnEmptyStringStorageClassName); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass_emptyStringComment) { + auto storageClass = m_storageClassSingleCopy; + storageClass.comment = ""; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + ASSERT_THROW(m_catalogue->StorageClass()->createStorageClass(m_admin, storageClass), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass_emptyStringVo) { + auto storageClass = m_storageClassSingleCopy; + storageClass.vo.name = ""; + ASSERT_THROW(m_catalogue->StorageClass()->createStorageClass(m_admin, storageClass), + cta::catalogue::UserSpecifiedAnEmptyStringVo); +} + +TEST_P(cta_catalogue_StorageClassTest, createStorageClass_nonExistingVo) { + auto storageClass = m_storageClassSingleCopy; + storageClass.vo.name = "NonExistingVO"; + ASSERT_THROW(m_catalogue->StorageClass()->createStorageClass(m_admin, storageClass), cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, deleteStorageClass) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = storageClasses.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->StorageClass()->deleteStorageClass(m_storageClassSingleCopy.name); + ASSERT_TRUE(m_catalogue->StorageClass()->getStorageClasses().empty()); +} + +TEST_P(cta_catalogue_StorageClassTest, deleteStorageClass_non_existent) { + ASSERT_THROW(m_catalogue->StorageClass()->deleteStorageClass("non_existent_storage_class"), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassNbCopies) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = storageClasses.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedNbCopies = 5; + m_catalogue->StorageClass()->modifyStorageClassNbCopies(m_admin, m_storageClassSingleCopy.name, modifiedNbCopies); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(modifiedNbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassNbCopies_nonExistentStorageClass) { + const std::string storageClassName = "storage_class"; + const uint64_t nbCopies = 5; + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassNbCopies(m_admin, storageClassName, nbCopies), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassComment) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = storageClasses.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->StorageClass()->modifyStorageClassComment(m_admin, m_storageClassSingleCopy.name, modifiedComment); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(modifiedComment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassComment_nonExistentStorageClass) { + const std::string storageClassName = "storage_class"; + const std::string comment = "Comment"; + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassComment(m_admin, storageClassName, comment), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassName) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(m_storageClassSingleCopy.name, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = storageClasses.front().lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newStorageClassName = "new_storage_class_name"; + m_catalogue->StorageClass()->modifyStorageClassName(m_admin, m_storageClassSingleCopy.name, newStorageClassName); + + { + const auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + + ASSERT_EQ(1, storageClasses.size()); + + + ASSERT_EQ(newStorageClassName, storageClasses.front().name); + ASSERT_EQ(m_storageClassSingleCopy.nbCopies, storageClasses.front().nbCopies); + ASSERT_EQ(m_storageClassSingleCopy.comment, storageClasses.front().comment); + + const cta::common::dataStructures::EntryLog creationLog = storageClasses.front().creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassName_nonExistentStorageClass) { + const std::string currentStorageClassName = "storage_class"; + const std::string newStorageClassName = "new_storage_class"; + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassName( + m_admin, currentStorageClassName, newStorageClassName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassName_newNameAlreadyExists) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto storageClass2 = m_storageClassSingleCopy; + storageClass2.name = "storage_class2"; + + m_catalogue->StorageClass()->createStorageClass(m_admin, storageClass2); + + //Try to rename the first storage class with the name of the second one + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassName( + m_admin, m_storageClassSingleCopy.name, storageClass2.name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassVo) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto newVo = m_vo; + newVo.name = "newVo"; + m_catalogue->VO()->createVirtualOrganization(m_admin, newVo); + + m_catalogue->StorageClass()->modifyStorageClassVo(m_admin, m_storageClassSingleCopy.name, newVo.name); + + auto storageClasses = m_catalogue->StorageClass()->getStorageClasses(); + ASSERT_EQ(newVo.name, storageClasses.front().vo.name); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassEmptyStringVo) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassVo(m_admin, m_storageClassSingleCopy.name, ""), + cta::catalogue::UserSpecifiedAnEmptyStringVo); +} + +TEST_P(cta_catalogue_StorageClassTest, modifyStorageClassVoDoesNotExist) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + ASSERT_THROW(m_catalogue->StorageClass()->modifyStorageClassVo( + m_admin, m_storageClassSingleCopy.name, "DOES_NOT_EXISTS"), cta::exception::UserError); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/StorageClassCatalogueTest.hpp b/catalogue/tests/modules/StorageClassCatalogueTest.hpp new file mode 100644 index 0000000000..e397fca119 --- /dev/null +++ b/catalogue/tests/modules/StorageClassCatalogueTest.hpp @@ -0,0 +1,50 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_StorageClassTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_StorageClassTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::DiskInstance m_diskInstance; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/TapeCatalogueTest.cpp b/catalogue/tests/modules/TapeCatalogueTest.cpp new file mode 100644 index 0000000000..d635c4da2d --- /dev/null +++ b/catalogue/tests/modules/TapeCatalogueTest.cpp @@ -0,0 +1,4185 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <memory> +#include <optional> +#include <set> +#include <string> +#include <vector> + +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/rdbms/RdbmsCatalogueUtils.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeForWriting.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/TapeCatalogueTest.hpp" +#include "common/dataStructures/ArchiveFile.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/RequesterIdentity.hpp" +#include "common/log/DummyLogger.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_TapeTest::cta_catalogue_TapeTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_tape1(CatalogueTestUtils::getTape1()), + m_tape2(CatalogueTestUtils::getTape2()), + m_tape3(CatalogueTestUtils::getTape3()) { +} + +void cta_catalogue_TapeTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_TapeTest::TearDown() { + m_catalogue.reset(); +} + +std::map<std::string, cta::common::dataStructures::Tape> cta_catalogue_TapeTest::tapeListToMap( + const std::list<cta::common::dataStructures::Tape> &listOfTapes) { + try { + std::map<std::string, cta::common::dataStructures::Tape> vidToTape; + + for (auto &tape: listOfTapes) { + if(vidToTape.end() != vidToTape.find(tape.vid)) { + throw cta::exception::Exception(std::string("Duplicate VID: value=") + tape.vid); + } + vidToTape[tape.vid] = tape; + } + + return vidToTape; + } catch(cta::exception::Exception &ex) { + throw cta::exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} + +TEST_P(cta_catalogue_TapeTest, createTape_1_tape_with_write_log_1_tape_without) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string diskInstance = m_diskInstance.name; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const auto tapes = tapeListToMap(m_catalogue->Tape()->getTapes()); + ASSERT_EQ(1, tapes.size()); + + const auto tapeItor = tapes.find(m_tape1.vid); + ASSERT_NE(tapes.end(), tapeItor); + + const cta::common::dataStructures::Tape tape = tapeItor->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + const uint64_t fileSize = 1234 * 1000000000UL; + const uint64_t archiveFileId = 1234; + const std::string diskFileId = "5678"; + { + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = diskFileId; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = fileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, 0x1000); // tests checksum with embedded zeros + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = "tape_drive"; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + } + + { + // Check that a lookup of diskFileId 5678 returns 1 tape + cta::catalogue::TapeSearchCriteria searchCriteria; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("5678"); + searchCriteria.diskFileIds = diskFileIds; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + ASSERT_EQ(m_tape1.vid, vidToTape.begin()->first); + ASSERT_EQ(m_tape1.vid, vidToTape.begin()->second.vid); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(fileSize, pool.dataBytes); + ASSERT_EQ(1, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + { + const auto tapes = tapeListToMap(m_catalogue->Tape()->getTapes()); + ASSERT_EQ(2, tapes.size()); + + const auto tapeItor = tapes.find(m_tape2.vid); + ASSERT_NE(tapes.end(), tapeItor); + + const cta::common::dataStructures::Tape tape = tapeItor->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.state, tape.state); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(2, pool.nbTapes); + ASSERT_EQ(2*m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(fileSize, pool.dataBytes); + ASSERT_EQ(1, pool.nbPhysicalFiles); + } +} + +TEST_P(cta_catalogue_TapeTest, deleteTape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + + m_catalogue->Tape()->deleteTape(tape.vid); + ASSERT_TRUE(m_catalogue->Tape()->getTapes().empty()); +} + +TEST_P(cta_catalogue_TapeTest, writeToTapeAndCheckMasterBytesAndFiles) { + cta::log::LogContext dummyLc(m_dummyLog); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.nbMasterFiles); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + std::set<cta::catalogue::TapeItemWrittenPointer> fileWrittenSet; + { + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + fileWrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = 1234; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = 1234 * 1000000000UL; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 2; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = "tape_drive"; + } + { + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + fileWrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = 1235; + file2Written.diskInstance = diskInstance; + file2Written.diskFileId = "5679"; + file2Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file2Written.diskFileGid = PUBLIC_DISK_GROUP; + file2Written.size = 1234 * 1000000000UL; + file2Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape1.vid; + file2Written.fSeq = 1; + file2Written.blockId = 8642; + file2Written.copyNb = 1; + file2Written.tapeDrive = "tape_drive"; + } + + m_catalogue->TapeFile()->filesWrittenToTape(fileWrittenSet); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(2 * 1234 * 1000000000UL, tape.dataOnTapeInBytes); + ASSERT_EQ(2 * 1234 * 1000000000UL, tape.masterDataInBytes); + ASSERT_EQ(2, tape.nbMasterFiles); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(static_cast<bool>(tape.labelLog)); + ASSERT_FALSE(static_cast<bool>(tape.lastReadLog)); + ASSERT_TRUE(static_cast<bool>(tape.lastWriteLog)); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + + +TEST_P(cta_catalogue_TapeTest, deleteNonEmptyTape) { + cta::log::LogContext dummyLc(m_dummyLog); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t fileSize = 1234 * 1000000000UL; + const uint64_t archiveFileId = 1234; + const std::string diskFileId = "5678"; + { + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstance; + file1Written.diskFileId = diskFileId; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = fileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = "tape_drive"; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(fileSize, tape.dataOnTapeInBytes); + ASSERT_EQ(fileSize, tape.masterDataInBytes); + ASSERT_EQ(1, tape.nbMasterFiles); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_THROW(m_catalogue->Tape()->deleteTape(m_tape1.vid), cta::catalogue::UserSpecifiedANonEmptyTape); + ASSERT_FALSE(m_catalogue->Tape()->getTapes().empty()); + + //Put the files on the tape on the recycle log + cta::common::dataStructures::DeleteArchiveRequest deletedArchiveReq; + deletedArchiveReq.archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + deletedArchiveReq.diskInstance = diskInstance; + deletedArchiveReq.archiveFileID = archiveFileId; + deletedArchiveReq.diskFileId = diskFileId; + deletedArchiveReq.recycleTime = time(nullptr); + deletedArchiveReq.requester = cta::common::dataStructures::RequesterIdentity(m_admin.username,"group"); + deletedArchiveReq.diskFilePath = "/path/"; + m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(deletedArchiveReq,dummyLc); + + //The ArchiveFilesItor should not have any file in it + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + //The tape should not be deleted + ASSERT_THROW(m_catalogue->Tape()->deleteTape(m_tape1.vid), cta::catalogue::UserSpecifiedANonEmptyTape); + ASSERT_FALSE(m_catalogue->Tape()->getTapes().empty()); + m_catalogue->Tape()->setTapeFull(m_admin,m_tape1.vid,true); + //Reclaim it to delete the files from the recycle log + m_catalogue->Tape()->reclaimTape(m_admin,m_tape1.vid,dummyLc); + //Deletion should be successful + ASSERT_NO_THROW(m_catalogue->Tape()->deleteTape(m_tape1.vid)); + ASSERT_TRUE(m_catalogue->Tape()->getTapes().empty()); +} + +TEST_P(cta_catalogue_TapeTest, deleteTape_non_existent) { + ASSERT_THROW(m_catalogue->Tape()->deleteTape("non_existent_tape"), cta::catalogue::UserSpecifiedANonExistentTape); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeMediaType) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + auto anotherMediaType = m_mediaType; + anotherMediaType.name = "another_media_type"; + + m_catalogue->MediaType()->createMediaType(m_admin, anotherMediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->modifyTapeMediaType(m_admin, m_tape1.vid, anotherMediaType.name); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(anotherMediaType.name, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + ASSERT_THROW(m_catalogue->Tape()->modifyTapeMediaType(m_admin, m_tape1.vid, "DOES NOT EXIST"), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeVendor) { + const std::string anotherVendor = "another_vendor"; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->modifyTapeVendor(m_admin, m_tape1.vid, anotherVendor); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(anotherVendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeLogicalLibraryName) { + const bool logicalLibraryIsDisabled= false; + const std::string anotherLogicalLibraryName = "another_logical_library_name"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, anotherLogicalLibraryName, logicalLibraryIsDisabled, + "Create another logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->modifyTapeLogicalLibraryName(m_admin, m_tape1.vid, anotherLogicalLibraryName); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(anotherLogicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeLogicalLibraryName_nonExistentTape) { + const bool logicalLibraryIsDisabled= false; + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + ASSERT_THROW(m_catalogue->Tape()->modifyTapeLogicalLibraryName(m_admin, m_tape1.vid, m_tape1.logicalLibraryName), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeTapePoolName) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string anotherTapePoolName = "another_tape_pool_name"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, anotherTapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create another tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->modifyTapeTapePoolName(m_admin, m_tape1.vid, anotherTapePoolName); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(anotherTapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeTapePoolName_nonExistentTape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + ASSERT_THROW(m_catalogue->Tape()->modifyTapeTapePoolName(m_admin, m_tape1.vid, m_tape1.tapePoolName), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeEncryptionKeyName) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedEncryptionKeyName = "modified_encryption_key_name"; + m_catalogue->Tape()->modifyTapeEncryptionKeyName(m_admin, m_tape1.vid, modifiedEncryptionKeyName); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(modifiedEncryptionKeyName, tape.encryptionKeyName); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeEncryptionKeyName_emptyStringEncryptionKey) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedEncryptionKeyName; + m_catalogue->Tape()->modifyTapeEncryptionKeyName(m_admin, m_tape1.vid, modifiedEncryptionKeyName); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_FALSE((bool)tape.encryptionKeyName); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeVerificationStatus) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + ASSERT_FALSE(tape.verificationStatus); + } + + const std::string modifiedVerificationStatus = "verification_status"; + m_catalogue->Tape()->modifyTapeVerificationStatus(m_admin, m_tape1.vid, modifiedVerificationStatus); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + ASSERT_EQ(tape.verificationStatus.value(), modifiedVerificationStatus); + } + + // Clear verification status + m_catalogue->Tape()->modifyTapeVerificationStatus(m_admin, m_tape1.vid, ""); + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_FALSE(tape.verificationStatus); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeEncryptionKeyName_nonExistentTape) { + const std::string encryptionKeyName = "encryption_key_name"; + + ASSERT_THROW(m_catalogue->Tape()->modifyTapeEncryptionKeyName(m_admin, m_tape1.vid, encryptionKeyName), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeState_nonExistentTape) { + cta::common::dataStructures::Tape::State state = cta::common::dataStructures::Tape::State::ACTIVE; + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, "DOES_NOT_EXIST", state, std::nullopt, std::nullopt), + cta::catalogue::UserSpecifiedANonExistentTape); +} + +TEST_P(cta_catalogue_TapeTest, setTapeDisabled_nonExistentTape) { + ASSERT_THROW(m_catalogue->Tape()->setTapeDisabled(m_admin, m_tape1.vid, "Test"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeState_nonExistentState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + cta::common::dataStructures::Tape::State state = (cta::common::dataStructures::Tape::State)42; + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, state, std::nullopt, std::nullopt), + cta::catalogue::UserSpecifiedANonExistentTapeState); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeState_nonExistentPrevState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + cta::common::dataStructures::Tape::State state = cta::common::dataStructures::Tape::State::ACTIVE; + cta::common::dataStructures::Tape::State prevState = (cta::common::dataStructures::Tape::State)42; + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, state, prevState, std::nullopt), + cta::catalogue::UserSpecifiedANonExistentTapeState); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeState_wrongPrevState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + cta::common::dataStructures::Tape::State prevState = cta::common::dataStructures::Tape::State::ACTIVE; + cta::common::dataStructures::Tape::State prevStateGuess = cta::common::dataStructures::Tape::State::REPACKING; + cta::common::dataStructures::Tape::State nextState = cta::common::dataStructures::Tape::State::DISABLED; + std::string reason = "modify for testing"; + m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, prevState, std::nullopt, std::nullopt); + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid,nextState,prevStateGuess,reason), + cta::catalogue::UserSpecifiedANonExistentTape); +} + + +TEST_P(cta_catalogue_TapeTest, modifyTapeState_noReasonWhenNotActive) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + std::string reason = ""; + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, + cta::common::dataStructures::Tape::State::BROKEN, std::nullopt, reason), + cta::catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); + + ASSERT_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, + cta::common::dataStructures::Tape::State::DISABLED,std::nullopt,std::nullopt), + cta::catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + std::string reason = "tape broken"; + + std::string vid = m_tape1.vid; + ASSERT_NO_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, vid, cta::common::dataStructures::Tape::State::BROKEN, + std::nullopt,reason)); + + { + //catalogue getTapesByVid test (single VID) + auto vidToTapeMap = m_catalogue->Tape()->getTapesByVid(vid); + auto tape = vidToTapeMap.at(vid); + ASSERT_EQ(vid,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::BROKEN,tape.state); + ASSERT_EQ(reason,tape.stateReason); + ASSERT_EQ(cta::catalogue::RdbmsCatalogueUtils::generateTapeStateModifiedBy(m_admin),tape.stateModifiedBy); + ASSERT_NE(0,tape.stateUpdateTime); + } + + { + //Get tape by search criteria test + cta::catalogue::TapeSearchCriteria criteria; + criteria.vid = vid; + auto tapes = m_catalogue->Tape()->getTapes(criteria); + auto tape = tapes.front(); + ASSERT_EQ(vid,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::BROKEN,tape.state); + ASSERT_EQ(reason,tape.stateReason); + ASSERT_EQ(cta::catalogue::RdbmsCatalogueUtils::generateTapeStateModifiedBy(m_admin),tape.stateModifiedBy); + ASSERT_NE(0,tape.stateUpdateTime); + } + + { + //catalogue getTapesByVid test (set of VIDs) + std::set<std::string> vids = {vid}; + auto vidToTapeMap = m_catalogue->Tape()->getTapesByVid(vids); + auto tape = vidToTapeMap.at(vid); + ASSERT_EQ(vid,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::BROKEN,tape.state); + ASSERT_EQ(reason,tape.stateReason); + ASSERT_EQ(cta::catalogue::RdbmsCatalogueUtils::generateTapeStateModifiedBy(m_admin),tape.stateModifiedBy); + ASSERT_NE(0,tape.stateUpdateTime); + } +} + +TEST_P(cta_catalogue_TapeTest, modifyTapeStateResetReasonWhenBackToActiveState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + std::string vid = m_tape1.vid; + + std::string reason = "Broken tape"; + ASSERT_NO_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, vid, cta::common::dataStructures::Tape::State::BROKEN, + std::nullopt,reason)); + + ASSERT_NO_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, vid, cta::common::dataStructures::Tape::State::ACTIVE, + std::nullopt, std::nullopt)); + + { + auto vidToTapeMap = m_catalogue->Tape()->getTapesByVid(vid); + auto tape = vidToTapeMap.at(vid); + ASSERT_EQ(vid,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::ACTIVE,tape.state); + ASSERT_FALSE(tape.stateReason); + ASSERT_EQ(cta::catalogue::RdbmsCatalogueUtils::generateTapeStateModifiedBy(m_admin),tape.stateModifiedBy); + ASSERT_NE(0,tape.stateUpdateTime); + } +} + +TEST_P(cta_catalogue_TapeTest, getTapesSearchCriteriaByState) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + std::string vidTape1 = m_tape1.vid; + std::string vidTape2 = m_tape2.vid; + + { + cta::catalogue::TapeSearchCriteria criteria; + criteria.state = cta::common::dataStructures::Tape::ACTIVE; + auto tapes = m_catalogue->Tape()->getTapes(criteria); + ASSERT_EQ(2,tapes.size()); + auto tape = tapes.front(); + ASSERT_EQ(vidTape1,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::ACTIVE,tape.state); + ASSERT_FALSE(tape.stateReason); + ASSERT_EQ(m_admin.username + "@" + m_admin.host,tape.stateModifiedBy); + ASSERT_NE(0,tape.stateUpdateTime); + } + + std::string reason = "Broken tape"; + ASSERT_NO_THROW(m_catalogue->Tape()->modifyTapeState(m_admin, vidTape1, + cta::common::dataStructures::Tape::State::BROKEN, std::nullopt, reason)); + + { + cta::catalogue::TapeSearchCriteria criteria; + criteria.state = cta::common::dataStructures::Tape::ACTIVE; + auto tapes = m_catalogue->Tape()->getTapes(criteria); + ASSERT_EQ(1,tapes.size()); + auto tape = tapes.front(); + //The tape 2 is ACTIVE so this is the one we expect + ASSERT_EQ(vidTape2,tape.vid); + } + { + cta::catalogue::TapeSearchCriteria criteria; + criteria.state = cta::common::dataStructures::Tape::BROKEN; + auto tapes = m_catalogue->Tape()->getTapes(criteria); + ASSERT_EQ(1,tapes.size()); + auto tape = tapes.front(); + //The tape 2 is ACTIVE so this is the one we expect + ASSERT_EQ(vidTape1,tape.vid); + ASSERT_EQ(cta::common::dataStructures::Tape::BROKEN,tape.state); + } +} + +TEST_P(cta_catalogue_TapeTest, tapeLabelled) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string labelDrive = "labelling_drive"; + m_catalogue->Tape()->tapeLabelled(m_tape1.vid, labelDrive); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_TRUE((bool)tape.labelLog); + ASSERT_EQ(labelDrive, tape.labelLog.value().drive); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, tapeLabelled_nonExistentTape) { + const std::string labelDrive = "drive"; + + ASSERT_THROW(m_catalogue->Tape()->tapeLabelled(m_tape1.vid, labelDrive), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, tapeMountedForArchive) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedDrive = "modified_drive"; + m_catalogue->Tape()->tapeMountedForArchive(m_tape1.vid, modifiedDrive); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(1, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(modifiedDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + for(int i=1; i<1024; i++) { + m_catalogue->Tape()->tapeMountedForArchive(m_tape1.vid, modifiedDrive); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(1024, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(modifiedDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, tapeMountedForArchive_nonExistentTape) { + const std::string drive = "drive"; + + ASSERT_THROW(m_catalogue->Tape()->tapeMountedForArchive(m_tape1.vid, drive), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, tapeMountedForRetrieve) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(0, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedDrive = "modified_drive"; + m_catalogue->Tape()->tapeMountedForRetrieve(m_tape1.vid, modifiedDrive); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(1, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_TRUE((bool)tape.lastReadLog); + ASSERT_EQ(modifiedDrive, tape.lastReadLog.value().drive); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + for(int i=1; i<1024; i++) { + m_catalogue->Tape()->tapeMountedForRetrieve(m_tape1.vid, modifiedDrive); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(1024, tape.readMountCount); + ASSERT_EQ(0, tape.writeMountCount); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_TRUE((bool)tape.lastReadLog); + ASSERT_EQ(modifiedDrive, tape.lastReadLog.value().drive); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, tapeMountedForRetrieve_nonExistentTape) { + const std::string drive = "drive"; + + ASSERT_THROW(m_catalogue->Tape()->tapeMountedForRetrieve(m_tape1.vid, drive), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, setTapeFull) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_TRUE(tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, setTapeFull_nonExistentTape) { + ASSERT_THROW(m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, setTapeDirty) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + ASSERT_TRUE(tape.dirty); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeDirty(m_admin, m_tape1.vid, false); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + ASSERT_FALSE(tape.dirty); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, setTapeDirty_nonExistentTape) { + ASSERT_THROW(m_catalogue->Tape()->setTapeDirty(m_admin, m_tape1.vid, true), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, noSpaceLeftOnTape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->noSpaceLeftOnTape(m_tape1.vid); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_TRUE(tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, noSpaceLeftOnTape_nonExistentTape) { + ASSERT_THROW(m_catalogue->Tape()->noSpaceLeftOnTape(m_tape1.vid), cta::exception::Exception); +} + +TEST_P(cta_catalogue_TapeTest, setTapeIsFromCastorInUnitTests) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeIsFromCastorInUnitTests(m_tape1.vid); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_TRUE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + // do it twice + m_catalogue->Tape()->setTapeIsFromCastorInUnitTests(m_tape1.vid); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_TRUE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, setTapeIsFromCastor_nonExistentTape) { + ASSERT_THROW(m_catalogue->Tape()->setTapeIsFromCastorInUnitTests(m_tape1.vid), cta::exception::Exception); +} + +TEST_P(cta_catalogue_TapeTest, getTapesForWriting) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + m_catalogue->Tape()->tapeLabelled(m_tape1.vid, "tape_drive"); + + const auto tapes = m_catalogue->Tape()->getTapesForWriting(m_tape1.logicalLibraryName); + + ASSERT_EQ(1, tapes.size()); + + const cta::catalogue::TapeForWriting tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePool); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(0, tape.dataOnTapeInBytes); +} + +TEST_P(cta_catalogue_TapeTest, getTapeLabelFormat) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + // Get Tape + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + ASSERT_EQ(1, tapes.size()); + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + + // Get label format and compare + const auto labelFormat = m_catalogue->Tape()->getTapeLabelFormat(m_tape1.vid); + ASSERT_EQ(tape.labelFormat, labelFormat); +} + +TEST_P(cta_catalogue_TapeTest, getTapesForWritingOrderedByDataInBytesDesc) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + + m_catalogue->Tape()->tapeLabelled(m_tape1.vid, "tape_drive"); + + const auto tapes = m_catalogue->Tape()->getTapesForWriting(m_tape1.logicalLibraryName); + + ASSERT_EQ(1, tapes.size()); + + const cta::catalogue::TapeForWriting tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePool); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + + //Create a tape and insert a file in it + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + m_catalogue->Tape()->tapeLabelled(m_tape2.vid, "tape_drive"); + + const uint64_t fileSize = 1234 * 1000000000UL; + { + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = 1234; + file1Written.diskInstance = m_diskInstance.name; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = fileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, 0x1000); // tests checksum with embedded zeros + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape2.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = "tape_drive"; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + } + + //The tape m_tape2 should be returned by the Catalogue::Tape()->getTapesForWriting() method + ASSERT_EQ(m_tape2.vid,m_catalogue->Tape()->getTapesForWriting(m_tape2.logicalLibraryName).front().vid); +} + +TEST_P(cta_catalogue_TapeTest, getTapesForWriting_disabled_tape) { + const bool logicalLibraryIsDisabled = false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + auto tape = m_tape1; + tape.state = cta::common::dataStructures::Tape::DISABLED; + tape.stateReason = "test"; + m_catalogue->Tape()->createTape(m_admin, tape); + + m_catalogue->Tape()->tapeLabelled(m_tape1.vid, "tape_drive"); + + const auto tapes = m_catalogue->Tape()->getTapesForWriting(m_tape1.logicalLibraryName); + + ASSERT_EQ(0, tapes.size()); +} + +TEST_P(cta_catalogue_TapeTest, getTapesForWriting_full_tape) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + auto tape1 = m_tape1; + tape1.full = true; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, tape1); + + m_catalogue->Tape()->tapeLabelled(tape1.vid, "tape_drive"); + + const auto tapes = m_catalogue->Tape()->getTapesForWriting(tape1.logicalLibraryName); + + ASSERT_EQ(0, tapes.size()); +} + +TEST_P(cta_catalogue_TapeTest, DISABLED_getTapesForWriting_no_labelled_tapes) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + const auto tapes = m_catalogue->Tape()->getTapesForWriting(m_tape1.logicalLibraryName); + + ASSERT_TRUE(tapes.empty()); +} + +TEST_P(cta_catalogue_TapeTest, reclaimTapeActiveState) { + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + cta::log::LogContext dummyLc(m_dummyLog); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, true); + + // ACTIVE - Reclaim allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::ACTIVE, std::nullopt, + "Testing"); + ASSERT_NO_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc)); +} + +TEST_P(cta_catalogue_TapeTest, reclaimTapeDisabledState) { + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + cta::log::LogContext dummyLc(m_dummyLog); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, true); + + // ACTIVE - Reclaim allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::DISABLED, std::nullopt, + "Testing"); + ASSERT_NO_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc)); +} + +TEST_P(cta_catalogue_TapeTest, reclaimTapeNotAllowedStates) { + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + + cta::log::LogContext dummyLc(m_dummyLog); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->setTapeFull(m_admin, tape1.vid, true); + + // REPACKING - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::REPACKING, std::nullopt, + "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // REPACKING_DISABLED - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::REPACKING_DISABLED, + std::nullopt, "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // REPACKING_PENDING - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::REPACKING_PENDING, + std::nullopt, "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // BROKEN - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::BROKEN, std::nullopt, + "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // BROKEN_PENDING - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::BROKEN_PENDING, + std::nullopt, "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // EXPORTED - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::EXPORTED, std::nullopt, + "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); + + // EXPORTED_PENDING - Reclaim not allowed + m_catalogue->Tape()->modifyTapeState(m_admin, tape1.vid, cta::common::dataStructures::Tape::EXPORTED_PENDING, + std::nullopt, "Testing"); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, tape1.vid, dummyLc), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, getTapes_non_existent_tape_pool) { + cta::log::LogContext dummyLc(m_dummyLog); + const bool logicalLibraryIsDisabled = false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + cta::catalogue::TapeSearchCriteria criteria; + criteria.tapePool = "non_existent"; + ASSERT_THROW(m_catalogue->Tape()->getTapes(criteria), cta::catalogue::UserSpecifiedANonExistentTapePool); + } +} + +TEST_P(cta_catalogue_TapeTest, createTape_deleteStorageClass) { + // TO BE DONE +} + + + +TEST_P(cta_catalogue_TapeTest, createTape_emptyStringVid) { + const std::string vid = ""; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + { + auto tape = m_tape1; + tape.vid = ""; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape), cta::catalogue::UserSpecifiedAnEmptyStringVid); + } +} + +TEST_P(cta_catalogue_TapeTest, createTape_emptyStringMediaType) { + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape = m_tape1; + tape.mediaType = ""; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape), cta::catalogue::UserSpecifiedAnEmptyStringMediaType); +} + +TEST_P(cta_catalogue_TapeTest, createTape_emptyStringVendor) { + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape = m_tape1; + tape.vendor = ""; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape), cta::catalogue::UserSpecifiedAnEmptyStringVendor); +} + +TEST_P(cta_catalogue_TapeTest, createTape_emptyStringLogicalLibraryName) { + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + auto tape = m_tape1; + tape.logicalLibraryName = ""; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape), cta::catalogue::UserSpecifiedAnEmptyStringLogicalLibraryName); +} + +TEST_P(cta_catalogue_TapeTest, createTape_emptyStringTapePoolName) { + const bool logicalLibraryIsDisabled= false; + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + auto tape = m_tape1; + tape.tapePoolName = ""; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape), cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapeTest, createTape_non_existent_logical_library) { + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, m_tape1), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, createTape_non_existent_tape_pool) { + const bool logicalLibraryIsDisabled= false; + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, m_tape1), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, createTape_9_exabytes_capacity) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + // The maximum size of an SQLite integer is a signed 64-bit integer + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + { + const auto &tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } +} + +TEST_P(cta_catalogue_TapeTest, createTape_same_twice) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, m_tape1), cta::exception::UserError); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } +} + +TEST_P(cta_catalogue_TapeTest, createTape_StateDoesNotExist) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + auto tape = m_tape1; + tape.state = (cta::common::dataStructures::Tape::State)42; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape),cta::catalogue::UserSpecifiedANonExistentTapeState); +} + +TEST_P(cta_catalogue_TapeTest, createTape_StateNotActiveWithoutReasonShouldThrow) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + auto tape1 = m_tape1; + tape1.state = cta::common::dataStructures::Tape::DISABLED; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape1), + cta::catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); + + auto tape2 = m_tape2; + tape2.state = cta::common::dataStructures::Tape::BROKEN; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape2), + cta::catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); + + tape2.stateReason = "Tape broken"; + ASSERT_NO_THROW(m_catalogue->Tape()->createTape(m_admin, tape2)); + + auto tape3 = m_tape3; + tape3.state = cta::common::dataStructures::Tape::EXPORTED; + ASSERT_THROW(m_catalogue->Tape()->createTape(m_admin, tape3), + cta::catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive); + + tape3.stateReason = "Tape exported"; + ASSERT_NO_THROW(m_catalogue->Tape()->createTape(m_admin, tape3)); +} + +TEST_P(cta_catalogue_TapeTest, createTape_many_tapes) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + const uint64_t nbTapes = 10; + + // Effectively clone the tapes from m_tape1 but give each one its own VID + for(uint64_t i = 1; i <= nbTapes; i++) { + std::ostringstream vid; + vid << "vid" << i; + + auto tape = m_tape1; + tape.vid = vid.str(); + m_catalogue->Tape()->createTape(m_admin, tape); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(i, pool.nbTapes); + ASSERT_EQ(i * m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + + for(uint64_t i = 1; i <= nbTapes; i++) { + std::ostringstream vid; + vid << "vid" << i; + + auto vidAndTapeItor = vidToTape.find(vid.str()); + ASSERT_NE(vidToTape.end(), vidAndTapeItor); + + const cta::common::dataStructures::Tape tape = vidAndTapeItor->second; + ASSERT_EQ(vid.str(), tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.mediaType = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vendor = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.logicalLibrary = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.tapePool = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vo = ""; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.diskFileIds = std::vector<std::string>(); + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.state = (cta::common::dataStructures::Tape::State)42; + ASSERT_THROW(m_catalogue->Tape()->getTapes(searchCriteria), cta::exception::UserError); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = "vid1"; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(1, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + ASSERT_EQ("vid1", vidToTape.begin()->first); + ASSERT_EQ("vid1", vidToTape.begin()->second.vid); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.mediaType = m_tape1.mediaType; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.mediaType, vidToTape.begin()->second.mediaType); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vendor = m_tape1.vendor; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.vendor, vidToTape.begin()->second.vendor); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.logicalLibrary = m_tape1.logicalLibraryName; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.logicalLibraryName, vidToTape.begin()->second.logicalLibraryName); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.tapePool = m_tape1.tapePoolName; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.tapePoolName, vidToTape.begin()->second.tapePoolName); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vo = m_vo.name; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_vo.name, vidToTape.begin()->second.vo); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.capacityInBytes = m_mediaType.capacityInBytes; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_mediaType.capacityInBytes, vidToTape.begin()->second.capacityInBytes); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.state = m_tape1.state; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.state, vidToTape.begin()->second.state); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.full = m_tape1.full; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_EQ(nbTapes, tapes.size()); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(nbTapes, vidToTape.size()); + ASSERT_EQ(m_tape1.full, vidToTape.begin()->second.full); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = "non_existent_vid"; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_TRUE(tapes.empty()); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + std::vector<std::string> diskFileIds; + diskFileIds.push_back("non_existent_fid"); + searchCriteria.diskFileIds = diskFileIds; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + ASSERT_TRUE(tapes.empty()); + } + + { + cta::catalogue::TapeSearchCriteria searchCriteria; + searchCriteria.vid = "vid1"; + searchCriteria.logicalLibrary = m_tape1.logicalLibraryName; + searchCriteria.tapePool = m_tape1.tapePoolName; + searchCriteria.capacityInBytes = m_mediaType.capacityInBytes; + searchCriteria.state = m_tape1.state; + searchCriteria.full = m_tape1.full; + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(searchCriteria); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + ASSERT_EQ("vid1", vidToTape.begin()->first); + ASSERT_EQ("vid1", vidToTape.begin()->second.vid); + ASSERT_EQ(m_tape1.logicalLibraryName, vidToTape.begin()->second.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, vidToTape.begin()->second.tapePoolName); + ASSERT_EQ(m_mediaType.capacityInBytes, vidToTape.begin()->second.capacityInBytes); + ASSERT_EQ(m_tape1.state, vidToTape.begin()->second.state); + ASSERT_EQ(m_tape1.full, vidToTape.begin()->second.full); + } + + { + std::set<std::string> vids; + for(uint64_t i = 1; i <= nbTapes; i++) { + std::ostringstream vid; + vid << "vid" << i; + vids.insert(vid.str()); + } + + const cta::common::dataStructures::VidToTapeMap vidToTape = m_catalogue->Tape()->getTapesByVid(vids); + ASSERT_EQ(nbTapes, vidToTape.size()); + + for(uint64_t i = 1; i <= nbTapes; i++) { + std::ostringstream vid; + vid << "vid" << i; + + auto vidAndTapeItor = vidToTape.find(vid.str()); + ASSERT_NE(vidToTape.end(), vidAndTapeItor); + + const cta::common::dataStructures::Tape tape = vidAndTapeItor->second; + ASSERT_EQ(vid.str(), tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } +} + + +TEST_P(cta_catalogue_TapeTest, getTapesByVid_non_existent_tape) { + + std::set<std::string> vids = {{"non_existent_tape"}}; + ASSERT_THROW(m_catalogue->Tape()->getTapesByVid(vids), cta::exception::Exception); +} + +TEST_P(cta_catalogue_TapeTest, getTapesByVid_no_vids) { + + std::set<std::string> vids; + ASSERT_TRUE(m_catalogue->Tape()->getTapesByVid(vids).empty()); +} + +TEST_P(cta_catalogue_TapeTest, getTapesByVid_1_tape) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t nbTapes = 1; + std::set<std::string> allVids; + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + auto tape = m_tape1; + tape.vid = vid.str(); + m_catalogue->Tape()->createTape(m_admin, tape); + allVids.insert(vid.str()); + } + + const auto vidToTapeMap = m_catalogue->Tape()->getTapesByVid(allVids); + ASSERT_EQ(nbTapes, vidToTapeMap.size()); + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + const auto tapeItor = vidToTapeMap.find(vid.str()); + ASSERT_NE(vidToTapeMap.end(), tapeItor); + + ASSERT_EQ(vid.str(), tapeItor->second.vid); + ASSERT_EQ(m_tape1.mediaType, tapeItor->second.mediaType); + ASSERT_EQ(m_tape1.vendor, tapeItor->second.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tapeItor->second.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tapeItor->second.tapePoolName); + ASSERT_EQ(m_vo.name, tapeItor->second.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tapeItor->second.capacityInBytes); + ASSERT_EQ(m_tape1.state, tapeItor->second.state); + ASSERT_EQ(m_tape1.full, tapeItor->second.full); + + ASSERT_FALSE(tapeItor->second.isFromCastor); + ASSERT_EQ(0, tapeItor->second.readMountCount); + ASSERT_EQ(0, tapeItor->second.writeMountCount); + ASSERT_EQ(m_tape1.comment, tapeItor->second.comment); + } +} + +TEST_P(cta_catalogue_TapeTest, getTapesByVid_350_tapes) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t nbTapes = 310; + std::set<std::string> allVids; + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + auto tape = m_tape1; + tape.vid = vid.str(); + m_catalogue->Tape()->createTape(m_admin, tape); + allVids.insert(vid.str()); + } + + const auto vidToTapeMap = m_catalogue->Tape()->getTapesByVid(allVids); + ASSERT_EQ(nbTapes, vidToTapeMap.size()); + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + const auto tapeItor = vidToTapeMap.find(vid.str()); + ASSERT_NE(vidToTapeMap.end(), tapeItor); + + ASSERT_EQ(vid.str(), tapeItor->second.vid); + ASSERT_EQ(m_tape1.mediaType, tapeItor->second.mediaType); + ASSERT_EQ(m_tape1.vendor, tapeItor->second.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tapeItor->second.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tapeItor->second.tapePoolName); + ASSERT_EQ(m_vo.name, tapeItor->second.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tapeItor->second.capacityInBytes); + ASSERT_EQ(m_tape1.state, tapeItor->second.state); + ASSERT_EQ(m_tape1.full, tapeItor->second.full); + + ASSERT_FALSE(tapeItor->second.isFromCastor); + ASSERT_EQ(0, tapeItor->second.readMountCount); + ASSERT_EQ(0, tapeItor->second.writeMountCount); + ASSERT_EQ(m_tape1.comment, tapeItor->second.comment); + } +} + +TEST_P(cta_catalogue_TapeTest, getVidToLogicalLibrary_no_vids) { + + std::set<std::string> vids; + ASSERT_TRUE(m_catalogue->Tape()->getVidToLogicalLibrary(vids).empty()); +} + +TEST_P(cta_catalogue_TapeTest, getVidToLogicalLibrary_1_tape) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t nbTapes = 1; + std::set<std::string> allVids; + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + auto tape = m_tape1; + tape.vid = vid.str(); + m_catalogue->Tape()->createTape(m_admin, tape); + allVids.insert(vid.str()); + } + + const auto vidToLogicalLibrary = m_catalogue->Tape()->getVidToLogicalLibrary(allVids); + ASSERT_EQ(nbTapes, vidToLogicalLibrary.size()); + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + const auto itor = vidToLogicalLibrary.find(vid.str()); + ASSERT_NE(vidToLogicalLibrary.end(), itor); + + ASSERT_EQ(m_tape1.logicalLibraryName, itor->second); + } +} + +TEST_P(cta_catalogue_TapeTest, getVidToLogicalLibrary_310_tapes) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + const uint32_t nbTapes = 310; + std::set<std::string> allVids; + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + auto tape = m_tape1; + tape.vid = vid.str(); + m_catalogue->Tape()->createTape(m_admin, tape); + allVids.insert(vid.str()); + } + + const auto vidToLogicalLibrary = m_catalogue->Tape()->getVidToLogicalLibrary(allVids); + ASSERT_EQ(nbTapes, vidToLogicalLibrary.size()); + + for(uint32_t i = 0; i < nbTapes; i++) { + std::ostringstream vid; + vid << "V" << std::setfill('0') << std::setw(5) << i; + const std::string tapeComment = "Create tape " + vid.str(); + + const auto itor = vidToLogicalLibrary.find(vid.str()); + ASSERT_NE(vidToLogicalLibrary.end(), itor); + + ASSERT_EQ(m_tape1.logicalLibraryName, itor->second); + } +} + +TEST_P(cta_catalogue_TapeTest, getNbFilesOnTape_no_tape_files) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_EQ(0, m_catalogue->Tape()->getNbFilesOnTape(m_tape1.vid)); +} + +TEST_P(cta_catalogue_TapeTest, getNbFilesOnTape_one_tape_file) { + + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + ASSERT_EQ(1, m_catalogue->Tape()->getNbFilesOnTape(m_tape1.vid)); +} + +TEST_P(cta_catalogue_TapeTest, checkTapeForLabel_no_tape_files) { + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_NO_THROW(m_catalogue->Tape()->checkTapeForLabel(m_tape1.vid)); +} + +TEST_P(cta_catalogue_TapeTest, checkTapeForLabel_one_tape_file) { + + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + ASSERT_THROW(m_catalogue->Tape()->checkTapeForLabel(m_tape1.vid), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, checkTapeForLabel_one_tape_file_reclaimed_tape) { + + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + ASSERT_THROW(m_catalogue->Tape()->checkTapeForLabel(m_tape1.vid), cta::exception::UserError); + + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(diskInstanceName1, archiveFileId, dummyLc); + + m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true); + m_catalogue->Tape()->reclaimTape(m_admin, m_tape1.vid,dummyLc); + + ASSERT_NO_THROW(m_catalogue->Tape()->checkTapeForLabel(m_tape1.vid)); +} + +TEST_P(cta_catalogue_TapeTest, checkTapeForLabel_not_in_the_catalogue) { + + ASSERT_THROW(m_catalogue->Tape()->checkTapeForLabel(m_tape1.vid), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, checkTapeForLabel_empty_vid) { + + const std::string vid = ""; + ASSERT_THROW(m_catalogue->Tape()->checkTapeForLabel(vid), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, reclaimTape_full_lastFSeq_0_no_tape_files) { + + cta::log::LogContext dummyLc(m_dummyLog); + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true); + m_catalogue->Tape()->reclaimTape(m_admin, m_tape1.vid, dummyLc); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_FALSE(tape.full); + ASSERT_FALSE(tape.verificationStatus); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, reclaimTape_not_full_lastFSeq_0_no_tape_files) { + + cta::log::LogContext dummyLc(m_dummyLog); + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, m_tape1.vid, dummyLc), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeTest, reclaimTape_full_lastFSeq_1_no_tape_files) { + + cta::log::LogContext dummyLc(m_dummyLog); + + const std::string diskInstanceName1 = m_diskInstance.name; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP = std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(1, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(tapeDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + m_catalogue->ArchiveFile()->DO_NOT_USE_deleteArchiveFile_DO_NOT_USE(diskInstanceName1, file1Written.archiveFileId, dummyLc); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(1, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(tapeDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true); + m_catalogue->Tape()->reclaimTape(m_admin, m_tape1.vid, dummyLc); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + const cta::common::dataStructures::Tape tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(tapeDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapeTest, reclaimTape_full_lastFSeq_1_one_tape_file) { + cta::log::LogContext dummyLc(m_dummyLog); + + const std::string diskInstanceName1 = m_diskInstance.name; + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(0, tape.dataOnTapeInBytes); + ASSERT_EQ(0, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + { + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + ASSERT_EQ(1, vidToTape.size()); + + auto it = vidToTape.find(m_tape1.vid); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(file1Written.size, tape.dataOnTapeInBytes); + ASSERT_EQ(file1Written.size, tape.masterDataInBytes); + ASSERT_EQ(1, tape.nbMasterFiles); + ASSERT_EQ(1, tape.lastFSeq); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_TRUE((bool)tape.lastWriteLog); + ASSERT_EQ(tapeDrive, tape.lastWriteLog.value().drive); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + m_catalogue->Tape()->setTapeFull(m_admin, m_tape1.vid, true); + ASSERT_THROW(m_catalogue->Tape()->reclaimTape(m_admin, m_tape1.vid, dummyLc), cta::exception::UserError); +} + + + + + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/TapeCatalogueTest.hpp b/catalogue/tests/modules/TapeCatalogueTest.hpp new file mode 100644 index 0000000000..66496f8e5d --- /dev/null +++ b/catalogue/tests/modules/TapeCatalogueTest.hpp @@ -0,0 +1,62 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <list> +#include <map> +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueFactory.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_TapeTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_TapeTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::catalogue::MediaType m_mediaType; + const cta::catalogue::CreateTapeAttributes m_tape1; + const cta::catalogue::CreateTapeAttributes m_tape2; + const cta::catalogue::CreateTapeAttributes m_tape3; + + std::map<std::string, cta::common::dataStructures::Tape> tapeListToMap( + const std::list<cta::common::dataStructures::Tape> &listOfTapes); +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/TapeFileCatalogueTest.cpp b/catalogue/tests/modules/TapeFileCatalogueTest.cpp new file mode 100644 index 0000000000..4f6ea1f503 --- /dev/null +++ b/catalogue/tests/modules/TapeFileCatalogueTest.cpp @@ -0,0 +1,1614 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CatalogueItor.hpp" +#include "catalogue/CreateMountPolicyAttributes.hpp" +#include "catalogue/InsertFileRecycleLog.hpp" +#include "catalogue/TapeFileWritten.hpp" +#include "catalogue/TapeItemWrittenPointer.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/TapeFileCatalogueTest.hpp" +#include "common/dataStructures/DeleteArchiveRequest.hpp" +#include "common/dataStructures/FileRecycleLog.hpp" +#include "common/dataStructures/RequesterActivityMountRule.hpp" +#include "common/dataStructures/RequesterMountRule.hpp" +#include "common/dataStructures/RetrieveFileQueueCriteria.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_TapeFileTest::cta_catalogue_TapeFileTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_tape1(CatalogueTestUtils::getTape1()), + m_tape2(CatalogueTestUtils::getTape2()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_storageClassDualCopy(CatalogueTestUtils::getStorageClassDualCopy()) { +} + +void cta_catalogue_TapeFileTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_TapeFileTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_TapeFileTest, moveFilesToRecycleLog) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + auto tape1 = m_tape1; + tape1.tapePoolName = tapePoolName1; + auto tape2 = m_tape2; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t nbArchiveFiles = 10; // Must be a multiple of 2 for this test + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + std::ostringstream diskFilePath; + diskFilePath << "/test/file"<<i; + + // Tape copy 1 written to tape + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = i; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassSingleCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = i; + fileWritten.blockId = i * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + } + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + { + ASSERT_TRUE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + } + log::LogContext dummyLc(m_dummyLog); + for(auto & tapeItemWritten: tapeFilesWrittenCopy1){ + cta::catalogue::TapeFileWritten * tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get()); + cta::common::dataStructures::DeleteArchiveRequest req; + req.requester.name = m_admin.username; + req.archiveFileID = tapeItem->archiveFileId; + req.diskFileId = tapeItem->diskFileId; + req.diskFilePath = tapeItem->diskFilePath; + req.diskInstance = tapeItem->diskInstance; + req.archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(tapeItem->archiveFileId); + ASSERT_NO_THROW(m_catalogue->ArchiveFile()->moveArchiveFileToRecycleLog(req,dummyLc)); + } + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + + std::vector<common::dataStructures::FileRecycleLog> deletedArchiveFiles; + { + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + while(itor.hasMore()){ + deletedArchiveFiles.push_back(itor.next()); + } + } + + //And test that these files are there. + //Run the unit test for all the databases + ASSERT_EQ(nbArchiveFiles,deletedArchiveFiles.size()); + + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + + auto deletedArchiveFile = deletedArchiveFiles[i-1]; + + std::ostringstream diskFileId; + diskFileId << (12345677 + i); + + std::ostringstream diskFilePath; + diskFilePath << "/test/file"<<i; + + ASSERT_EQ(i,deletedArchiveFile.archiveFileId); + ASSERT_EQ(diskInstance,deletedArchiveFile.diskInstanceName); + ASSERT_EQ(diskFileId.str(),deletedArchiveFile.diskFileId); + ASSERT_EQ(diskFilePath.str(),deletedArchiveFile.diskFilePath); + ASSERT_EQ(PUBLIC_DISK_USER,deletedArchiveFile.diskFileUid); + ASSERT_EQ(PUBLIC_DISK_GROUP,deletedArchiveFile.diskFileGid); + ASSERT_EQ(archiveFileSize,deletedArchiveFile.sizeInBytes); + ASSERT_EQ(cta::checksum::ChecksumBlob(checksum::ADLER32, "1357"),deletedArchiveFile.checksumBlob); + ASSERT_EQ(m_storageClassSingleCopy.name, deletedArchiveFile.storageClassName); + ASSERT_EQ(diskFileId.str(),deletedArchiveFile.diskFileIdWhenDeleted); + ASSERT_EQ(cta::catalogue::InsertFileRecycleLog::getDeletionReasonLog(m_admin.username,diskInstance),deletedArchiveFile.reasonLog); + ASSERT_EQ(tape1.vid, deletedArchiveFile.vid); + ASSERT_EQ(i,deletedArchiveFile.fSeq); + ASSERT_EQ(i * 100,deletedArchiveFile.blockId); + ASSERT_EQ(1, deletedArchiveFile.copyNb); + } + + //Let's try the deletion of the files from the recycle-bin. + for(uint64_t i = 1; i <= nbArchiveFiles; i++) { + m_catalogue->FileRecycleLog()->deleteFilesFromRecycleLog(tape1.vid,dummyLc); + } + + { + auto itor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_FALSE(itor.hasMore()); + } +} + +TEST_P(cta_catalogue_TapeFileTest, DeleteTapeFileCopyUsingArchiveID) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert both copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape1 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + criteria.archiveFileId = 1; + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + //The deleted file (fSeq = 1) is on the recycle log + auto recycleFileLog = fileRecycleLogItor.next(); + ASSERT_EQ(1, recycleFileLog.fSeq); + ASSERT_EQ(tape1.vid, recycleFileLog.vid); + ASSERT_EQ(1, recycleFileLog.archiveFileId); + ASSERT_EQ(1, recycleFileLog.copyNb); + ASSERT_EQ(1 * 100, recycleFileLog.blockId); + ASSERT_EQ("(Deleted using cta-admin tf rm) " + reason, recycleFileLog.reasonLog); + ASSERT_EQ(std::string("/test/file1"), recycleFileLog.diskFilePath.value()); + } + + { + //get last archive file copy for deletions should fail + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape2.vid; + criteria.archiveFileId = 1; + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria), exception::UserError); + } +} + +TEST_P(cta_catalogue_TapeFileTest, DeleteTapeFileCopyDoesNotExist) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + { + //delete copy of file that does not exist should fail + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape2.vid; + criteria.archiveFileId = 1; + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria), exception::UserError); + } +} + + + +TEST_P(cta_catalogue_TapeFileTest, DeleteTapeFileCopyUsingFXID) { + using namespace cta; + + const bool logicalLibraryIsDisabled= false; + const std::string tapePoolName1 = "tape_pool_name_1"; + const std::string tapePoolName2 = "tape_pool_name_2"; + const uint64_t nbPartialTapes = 1; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string diskInstance = m_diskInstance.name; + const std::string tapeDrive = "tape_drive"; + const std::string reason = "reason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName1, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName2, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassDualCopy); + + auto tape1 = m_tape1; + auto tape2 = m_tape2; + tape1.tapePoolName = tapePoolName1; + tape2.tapePoolName = tapePoolName2; + + m_catalogue->Tape()->createTape(m_admin, tape1); + m_catalogue->Tape()->createTape(m_admin, tape2); + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + const uint64_t archiveFileSize = 2 * 1000 * 1000 * 1000; + + + // Write a file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape1.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 1; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + + // Write a second copy of file on tape + { + std::set<catalogue::TapeItemWrittenPointer> tapeFilesWrittenCopy1; + + std::ostringstream diskFileId; + diskFileId << 12345677; + + std::ostringstream diskFilePath; + diskFilePath << "/test/file1"; + + auto fileWrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & fileWritten = *fileWrittenUP; + fileWritten.archiveFileId = 1; + fileWritten.diskInstance = diskInstance; + fileWritten.diskFileId = diskFileId.str(); + fileWritten.diskFilePath = diskFilePath.str(); + fileWritten.diskFileOwnerUid = PUBLIC_DISK_USER; + fileWritten.diskFileGid = PUBLIC_DISK_GROUP; + fileWritten.size = archiveFileSize; + fileWritten.checksumBlob.insert(checksum::ADLER32, "1357"); + fileWritten.storageClassName = m_storageClassDualCopy.name; + fileWritten.vid = tape2.vid; + fileWritten.fSeq = 1; + fileWritten.blockId = 1 * 100; + fileWritten.copyNb = 2; + fileWritten.tapeDrive = tapeDrive; + tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); + + m_catalogue->TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); + } + { + //Assert both copies written + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + } + + { + //delete copy of file on tape1 + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape1.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + auto archiveFileForDeletion = m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria); + archiveFileForDeletion.diskFileInfo.path = "/test/file1"; + m_catalogue->TapeFile()->deleteTapeFileCopy(archiveFileForDeletion, reason); + auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(1); + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto fileRecycleLogItor = m_catalogue->FileRecycleLog()->getFileRecycleLogItor(); + ASSERT_TRUE(fileRecycleLogItor.hasMore()); + //The previous file (fSeq = 1) is on the recycle log + auto recycleFileLog = fileRecycleLogItor.next(); + ASSERT_EQ(1, recycleFileLog.fSeq); + ASSERT_EQ(tape1.vid, recycleFileLog.vid); + ASSERT_EQ(1, recycleFileLog.archiveFileId); + ASSERT_EQ(1, recycleFileLog.copyNb); + ASSERT_EQ(1 * 100, recycleFileLog.blockId); + ASSERT_EQ("(Deleted using cta-admin tf rm) " + reason, recycleFileLog.reasonLog); + ASSERT_EQ(std::string("/test/file1"), recycleFileLog.diskFilePath.value()); + } + + { + //delete last copy of file should fail + cta::catalogue::TapeFileSearchCriteria criteria; + criteria.vid = tape2.vid; + criteria.diskInstance = diskInstance; + criteria.diskFileIds = std::vector<std::string>(); + auto fid = std::to_string(strtol("BC614D", nullptr, 16)); + criteria.diskFileIds.value().push_back(fid); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileForDeletion(criteria), exception::UserError); + } +} + +TEST_P(cta_catalogue_TapeFileTest, prepareToRetrieveFileUsingArchiveFileId_repackingTapes) { + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + std::string repackingReason = "repackingReason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + const auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + + const auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + uint64_t minArchiveRequestAge = mountPolicyToAdd.minArchiveRequestAge; + uint64_t archivePriority = mountPolicyToAdd.archivePriority; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName1, + requesterName, comment); + + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName1, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + cta::log::LogContext dummyLc(m_dummyLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = queueCriteria.archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + const auto copyNbToTapeFile2Itor = queueCriteria.archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + m_catalogue->Tape()->modifyTapeState(m_admin, m_tape1.vid, cta::common::dataStructures::Tape::State::REPACKING, + std::nullopt, repackingReason); + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(1, queueCriteria.archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile2Itor = queueCriteria.archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + m_catalogue->Tape()->modifyTapeState(m_admin, m_tape2.vid, cta::common::dataStructures::Tape::State::REPACKING, + std::nullopt, repackingReason); + + ASSERT_THROW(m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, + dummyLc), cta::exception::UserError); +} + + +TEST_P(cta_catalogue_TapeFileTest, prepareToRetrieveFileUsingArchiveFileId) { + const std::string diskInstanceName1 = m_diskInstance.name; + const std::string diskInstanceName2 = "disk_instance_2"; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstanceName1, "comment"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstanceName2, "comment"); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP = std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const auto archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + uint64_t minArchiveRequestAge = mountPolicyToAdd.minArchiveRequestAge; + uint64_t archivePriority = mountPolicyToAdd.archivePriority; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName1, requesterName, comment); + + const std::list<cta::common::dataStructures::RequesterMountRule> rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName1, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + cta::log::LogContext dummyLc(m_dummyLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + // Check that the diskInstanceName mismatch detection works + ASSERT_THROW(m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName2, archiveFileId, requesterIdentity, std::nullopt, dummyLc), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeFileTest, prepareToRetrieveFileUsingArchiveFileId_disabledTapes) { + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + std::string disabledReason = "disabledReason"; + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + + const auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + uint64_t minArchiveRequestAge = mountPolicyToAdd.minArchiveRequestAge; + uint64_t archivePriority = mountPolicyToAdd.archivePriority; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName1, + requesterName, comment); + + const auto rules = m_catalogue->RequesterMountRule()->getRequesterMountRules(); + ASSERT_EQ(1, rules.size()); + + const cta::common::dataStructures::RequesterMountRule rule = rules.front(); + + ASSERT_EQ(diskInstanceName1, rule.diskInstance); + ASSERT_EQ(requesterName, rule.name); + ASSERT_EQ(mountPolicyName, rule.mountPolicy); + ASSERT_EQ(comment, rule.comment); + ASSERT_EQ(m_admin.username, rule.creationLog.username); + ASSERT_EQ(m_admin.host, rule.creationLog.host); + ASSERT_EQ(rule.creationLog, rule.lastModificationLog); + + cta::log::LogContext dummyLc(m_dummyLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = queueCriteria.archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + const auto copyNbToTapeFile2Itor = queueCriteria.archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } + + m_catalogue->Tape()->setTapeDisabled(m_admin, m_tape1.vid, disabledReason); + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = queueCriteria.archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + + const auto copyNbToTapeFile2Itor = queueCriteria.archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile2.copyNb); + } +} + +TEST_P(cta_catalogue_TapeFileTest, prepareToRetrieveFileUsingArchiveFileId_returnNonSupersededFiles) { + const std::string diskInstanceName1 = m_diskInstance.name; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + + const uint64_t archiveFileId = 1234; + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + //Create a superseder file + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 1; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + ASSERT_TRUE(m_catalogue->FileRecycleLog()->getFileRecycleLogItor().hasMore()); + + auto mountPolicyToAdd = CatalogueTestUtils::getMountPolicy1(); + std::string mountPolicyName = mountPolicyToAdd.name; + uint64_t minArchiveRequestAge = mountPolicyToAdd.minArchiveRequestAge; + uint64_t archivePriority = mountPolicyToAdd.archivePriority; + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd); + + const std::string comment = "Create mount rule for requester"; + const std::string requesterName = "requester_name"; + m_catalogue->RequesterMountRule()->createRequesterMountRule(m_admin, mountPolicyName, diskInstanceName1, requesterName, comment); + + cta::log::LogContext dummyLc(m_dummyLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc); + + ASSERT_EQ(archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + + ASSERT_EQ(1, queueCriteria.archiveFile.tapeFiles.size()); + + const auto copyNbToTapeFile1Itor = queueCriteria.archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, queueCriteria.archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file2Written.vid, tapeFile1.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file2Written.copyNb, tapeFile1.copyNb); + } + + std::string repackingReason = "repackingReason"; + m_catalogue->Tape()->modifyTapeState(m_admin, m_tape2.vid, cta::common::dataStructures::Tape::State::REPACKING, + std::nullopt, repackingReason); + + ASSERT_THROW(m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, std::nullopt, dummyLc), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapeFileTest, prepareToRetrieveFileUsingArchiveFileId_ActivityMountPolicy) { + const std::string diskInstanceName1 = m_diskInstance.name; + const std::string diskInstanceName2 = "disk_instance_2"; + + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + m_catalogue->Tape()->createTape(m_admin, m_tape2); + + const std::list<cta::common::dataStructures::Tape> tapes = m_catalogue->Tape()->getTapes(); + const std::map<std::string, cta::common::dataStructures::Tape> vidToTape = CatalogueTestUtils::tapeListToMap(tapes); + { + auto it = vidToTape.find(m_tape1.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + auto it = vidToTape.find(m_tape2.vid); + ASSERT_TRUE(it != vidToTape.end()); + const cta::common::dataStructures::Tape &tape = it->second; + ASSERT_EQ(m_tape2.vid, tape.vid); + ASSERT_EQ(m_tape2.mediaType, tape.mediaType); + ASSERT_EQ(m_tape2.vendor, tape.vendor); + ASSERT_EQ(m_tape2.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape2.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape2.full, tape.full); + + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape2.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const cta::common::dataStructures::EntryLog creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t archiveFileId = 1234; + + + ASSERT_FALSE(m_catalogue->ArchiveFile()->getArchiveFilesItor().hasMore()); + ASSERT_THROW(m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId), cta::exception::Exception); + + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const uint64_t archiveFileSize = 1; + const std::string tapeDrive = "tape_drive"; + + auto file1WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file1Written = *file1WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file1WrittenSet; + file1WrittenSet.insert(file1WrittenUP.release()); + file1Written.archiveFileId = archiveFileId; + file1Written.diskInstance = diskInstanceName1; + file1Written.diskFileId = "5678"; + file1Written.diskFileOwnerUid = PUBLIC_DISK_USER; + file1Written.diskFileGid = PUBLIC_DISK_GROUP; + file1Written.size = archiveFileSize; + file1Written.checksumBlob.insert(cta::checksum::ADLER32, "1234"); + file1Written.storageClassName = m_storageClassSingleCopy.name; + file1Written.vid = m_tape1.vid; + file1Written.fSeq = 1; + file1Written.blockId = 4321; + file1Written.copyNb = 1; + file1Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file1WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file1Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file1Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file1Written.size, archiveFile.fileSize); + ASSERT_EQ(file1Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file1Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file1Written.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(file1Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file1Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(1, archiveFile.tapeFiles.size()); + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + ASSERT_EQ(file1Written.copyNb, tapeFile1.copyNb); + } + + auto file2WrittenUP=std::make_unique<cta::catalogue::TapeFileWritten>(); + auto & file2Written = *file2WrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> file2WrittenSet; + file2WrittenSet.insert(file2WrittenUP.release()); + file2Written.archiveFileId = file1Written.archiveFileId; + file2Written.diskInstance = file1Written.diskInstance; + file2Written.diskFileId = file1Written.diskFileId; + file2Written.diskFileOwnerUid = file1Written.diskFileOwnerUid; + file2Written.diskFileGid = file1Written.diskFileGid; + file2Written.size = archiveFileSize; + file2Written.checksumBlob = file1Written.checksumBlob; + file2Written.storageClassName = m_storageClassSingleCopy.name; + file2Written.vid = m_tape2.vid; + file2Written.fSeq = 1; + file2Written.blockId = 4331; + file2Written.copyNb = 2; + file2Written.tapeDrive = tapeDrive; + m_catalogue->TapeFile()->filesWrittenToTape(file2WrittenSet); + + { + const cta::common::dataStructures::ArchiveFile archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(archiveFileId); + + ASSERT_EQ(file2Written.archiveFileId, archiveFile.archiveFileID); + ASSERT_EQ(file2Written.diskFileId, archiveFile.diskFileId); + ASSERT_EQ(file2Written.size, archiveFile.fileSize); + ASSERT_EQ(file2Written.checksumBlob, archiveFile.checksumBlob); + ASSERT_EQ(file2Written.storageClassName, archiveFile.storageClass); + + ASSERT_EQ(file2Written.diskInstance, archiveFile.diskInstance); + ASSERT_EQ(file2Written.diskFileOwnerUid, archiveFile.diskFileInfo.owner_uid); + ASSERT_EQ(file2Written.diskFileGid, archiveFile.diskFileInfo.gid); + + ASSERT_EQ(2, archiveFile.tapeFiles.size()); + + auto copyNbToTapeFile1Itor = archiveFile.tapeFiles.find(1); + ASSERT_NE(copyNbToTapeFile1Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile1 = *copyNbToTapeFile1Itor; + ASSERT_EQ(file1Written.vid, tapeFile1.vid); + ASSERT_EQ(file1Written.fSeq, tapeFile1.fSeq); + ASSERT_EQ(file1Written.blockId, tapeFile1.blockId); + ASSERT_EQ(file1Written.checksumBlob, tapeFile1.checksumBlob); + + auto copyNbToTapeFile2Itor = archiveFile.tapeFiles.find(2); + ASSERT_NE(copyNbToTapeFile2Itor, archiveFile.tapeFiles.end()); + const cta::common::dataStructures::TapeFile &tapeFile2 = *copyNbToTapeFile2Itor; + ASSERT_EQ(file2Written.vid, tapeFile2.vid); + ASSERT_EQ(file2Written.fSeq, tapeFile2.fSeq); + ASSERT_EQ(file2Written.blockId, tapeFile2.blockId); + ASSERT_EQ(file2Written.checksumBlob, tapeFile2.checksumBlob); + } + + auto mountPolicyToAdd1 = CatalogueTestUtils::getMountPolicy1(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd1); + auto mountPolicyToAdd2 = CatalogueTestUtils::getMountPolicy2(); + m_catalogue->MountPolicy()->createMountPolicy(m_admin,mountPolicyToAdd2); + + const std::string comment = "Create mount rule for requester+activity"; + const std::string requesterName = "requester_name"; + const std::string activityRegex = "^activity_[a-zA-Z0-9-]+$"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyToAdd1.name, + diskInstanceName1, requesterName, activityRegex, comment); + + const std::string secondActivityRegex = "^activity_specific$"; + m_catalogue->RequesterActivityMountRule()->createRequesterActivityMountRule(m_admin, mountPolicyToAdd2.name, + diskInstanceName1, requesterName, secondActivityRegex, comment); + { + const auto rules = m_catalogue->RequesterActivityMountRule()->getRequesterActivityMountRules(); + ASSERT_EQ(2, rules.size()); + } + + cta::log::LogContext dummyLc(m_dummyLog); + + cta::common::dataStructures::RequesterIdentity requesterIdentity; + requesterIdentity.name = requesterName; + requesterIdentity.group = "group"; + std::optional<std::string> requestActivity = std::string("activity_retrieve"); + + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, + requestActivity, dummyLc); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + ASSERT_EQ(mountPolicyToAdd1.archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(mountPolicyToAdd1.minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + } + + // Check that multiple matching policies returns the highest priority one for retrieve + requestActivity = std::string("activity_specific"); + { + const cta::common::dataStructures::RetrieveFileQueueCriteria queueCriteria = + m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName1, archiveFileId, requesterIdentity, requestActivity, + dummyLc); + + ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); + ASSERT_EQ(mountPolicyToAdd2.archivePriority, queueCriteria.mountPolicy.archivePriority); + ASSERT_EQ(mountPolicyToAdd2.minArchiveRequestAge, queueCriteria.mountPolicy.archiveMinRequestAge); + } + + + // Check that no matching activity detection works + requestActivity = std::string("no_matching_activity"); + ASSERT_THROW(m_catalogue->TapeFile()->prepareToRetrieveFile(diskInstanceName2, archiveFileId, requesterIdentity, + requestActivity, dummyLc), cta::exception::UserError); +} + + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/TapeFileCatalogueTest.hpp b/catalogue/tests/modules/TapeFileCatalogueTest.hpp new file mode 100644 index 0000000000..042f4742ee --- /dev/null +++ b/catalogue/tests/modules/TapeFileCatalogueTest.hpp @@ -0,0 +1,57 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/MediaTypeWithLogs.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_TapeFileTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_TapeFileTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::catalogue::MediaType m_mediaType; + const cta::catalogue::CreateTapeAttributes m_tape1; + const cta::catalogue::CreateTapeAttributes m_tape2; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::StorageClass m_storageClassDualCopy; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/TapePoolCatalogueTest.cpp b/catalogue/tests/modules/TapePoolCatalogueTest.cpp new file mode 100644 index 0000000000..3f07954606 --- /dev/null +++ b/catalogue/tests/modules/TapePoolCatalogueTest.cpp @@ -0,0 +1,1526 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <list> +#include <memory> +#include <string> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/MediaType.hpp" +#include "catalogue/rdbms/CommonExceptions.hpp" +#include "catalogue/TapePool.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/TapePoolCatalogueTest.hpp" +#include "common/Constants.hpp" +#include "common/dataStructures/ArchiveRoute.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/Tape.hpp" +#include "common/exception/Exception.hpp" +#include "common/log/LogContext.hpp" + +namespace unitTests { + +cta_catalogue_TapePoolTest::cta_catalogue_TapePoolTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_anotherVo(CatalogueTestUtils::getAnotherVo()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_anotherStorageClass(CatalogueTestUtils::getAnotherStorageClass()), + m_mediaType(CatalogueTestUtils::getMediaType()), + m_tape1(CatalogueTestUtils::getTape1()) { +} + +void cta_catalogue_TapePoolTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_TapePoolTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_TapePoolTest, getTapePool_non_existent) { + const std::string tapePoolName = "non_existent_tape_pool"; + + ASSERT_FALSE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + const auto pool = m_catalogue->TapePool()->getTapePool(tapePoolName); + + ASSERT_FALSE((bool)pool); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool) { + const std::string tapePoolName = "tape_pool"; + + ASSERT_FALSE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + + ASSERT_TRUE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + { + const auto pool = m_catalogue->TapePool()->getTapePool(tapePoolName); + + ASSERT_TRUE((bool)pool); + + ASSERT_EQ(tapePoolName, pool->name); + ASSERT_EQ(m_vo.name, pool->vo.name); + ASSERT_EQ(nbPartialTapes, pool->nbPartialTapes); + ASSERT_EQ(isEncrypted, pool->encryption); + ASSERT_TRUE((bool)pool->supply); + ASSERT_EQ(supply.value(), pool->supply.value()); + ASSERT_EQ(supply, pool->supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool->creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool->lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_null_supply) { + const std::string tapePoolName = "tape_pool"; + + ASSERT_FALSE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply; + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + + ASSERT_TRUE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_FALSE((bool)pool.supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = + pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_same_twice) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + ASSERT_THROW(m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, + isEncrypted, supply, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_vo_does_not_exist) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + ASSERT_THROW(m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, + isEncrypted, supply, comment), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_tapes_of_mixed_state) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + cta::catalogue::TapeSearchCriteria criteria; + criteria.vid = m_tape1.vid; + ASSERT_EQ(0,m_catalogue->Tape()->getTapes(criteria).size()); + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + auto tape_disabled_01 = m_tape1; + tape_disabled_01.vid = "D000001"; + tape_disabled_01.state = cta::common::dataStructures::Tape::DISABLED; + tape_disabled_01.stateReason = "unit Test"; + m_catalogue->Tape()->createTape(m_admin, tape_disabled_01); + + auto tape_disabled_02 = m_tape1; + tape_disabled_02.vid = "D000002"; + tape_disabled_02.state = cta::common::dataStructures::Tape::DISABLED; + tape_disabled_02.stateReason = "unit Test"; + m_catalogue->Tape()->createTape(m_admin, tape_disabled_02); + + auto tape_broken_01 = m_tape1; + tape_broken_01.vid = "B000002"; + tape_broken_01.state = cta::common::dataStructures::Tape::BROKEN; + tape_broken_01.stateReason = "unit Test"; + m_catalogue->Tape()->createTape(m_admin, tape_broken_01); + + auto tape_exported_01 = m_tape1; + tape_exported_01.vid = "E000001"; + tape_exported_01.state = cta::common::dataStructures::Tape::EXPORTED; + tape_exported_01.stateReason = "unit Test"; + m_catalogue->Tape()->createTape(m_admin, tape_exported_01); + + auto tape_full_01 = m_tape1; + tape_full_01.vid = "F000001"; + tape_full_01.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_full_01); + + auto tape_full_02 = m_tape1; + tape_full_02.vid = "F000002"; + tape_full_02.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_full_02); + + auto tape_full_03 = m_tape1; + tape_full_03.vid = "F000003"; + tape_full_03.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_full_03); + + auto tape_broken_full_01 = m_tape1; + tape_broken_full_01.vid = "BFO001"; + tape_broken_full_01.state = cta::common::dataStructures::Tape::BROKEN; + tape_broken_full_01.stateReason = "unit Test"; + tape_broken_full_01.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_broken_full_01); + + auto tape_exported_full_01 = m_tape1; + tape_exported_full_01.vid = "EFO001"; + tape_exported_full_01.state = cta::common::dataStructures::Tape::EXPORTED; + tape_exported_full_01.stateReason = "unit Test"; + tape_exported_full_01.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_exported_full_01); + + auto tape_disabled_full_01 = m_tape1; + tape_disabled_full_01.vid = "DFO001"; + tape_disabled_full_01.state = cta::common::dataStructures::Tape::DISABLED; + tape_disabled_full_01.stateReason = "unit Test"; + tape_disabled_full_01.full = true; + m_catalogue->Tape()->createTape(m_admin, tape_disabled_full_01); + + auto tape_disabled_full_02 = m_tape1; + tape_disabled_full_02.vid = "DFO002"; + tape_disabled_full_02.full = true; + tape_disabled_full_02.state = cta::common::dataStructures::Tape::DISABLED; + tape_disabled_full_02.stateReason = "unit Test"; + m_catalogue->Tape()->createTape(m_admin, tape_disabled_full_02); + + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(12, tapes.size()); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(12, pool.nbTapes); + ASSERT_EQ(12, pool.nbEmptyTapes); + ASSERT_EQ(4, pool.nbDisabledTapes); + ASSERT_EQ(7, pool.nbFullTapes); + ASSERT_EQ(1, pool.nbWritableTapes); + ASSERT_EQ(12 * m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + { + const auto pool = m_catalogue->TapePool()->getTapePool(m_tape1.tapePoolName); + ASSERT_TRUE((bool)pool); + + ASSERT_EQ(m_tape1.tapePoolName, pool->name); + ASSERT_EQ(m_vo.name, pool->vo.name); + ASSERT_EQ(12, pool->nbTapes); + ASSERT_EQ(12, pool->nbEmptyTapes); + ASSERT_EQ(4, pool->nbDisabledTapes); + ASSERT_EQ(7, pool->nbFullTapes); + ASSERT_EQ(1, pool->nbWritableTapes); + ASSERT_EQ(12 * m_mediaType.capacityInBytes, pool->capacityBytes); + ASSERT_EQ(0, pool->dataBytes); + ASSERT_EQ(0, pool->nbPhysicalFiles); + } +} + +TEST_P(cta_catalogue_TapePoolTest, deleteTapePool) { + const uint64_t tapePoolNbPartialTapes = 2; + const bool tapePoolIsEncrypted = true; + const std::string tapePoolComment = "Create tape pool"; + { + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, tapePoolNbPartialTapes, + tapePoolIsEncrypted, supply, tapePoolComment); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(tapePoolNbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(tapePoolIsEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(tapePoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + // Create a separate archive route with another tape pool that has nothing to + // do with the tape pool being tested in order to test + // RdbmsCatalogue::tapePoolUsedInAnArchiveRoute() + const std::string anotherTapePoolName = "another_tape_pool"; + const uint64_t anotherNbPartialTapes = 4; + const std::string anotherTapePoolComment = "Create another tape pool"; + const bool anotherTapePoolIsEncrypted = false; + { + m_catalogue->StorageClass()->createStorageClass(m_admin, m_anotherStorageClass); + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_anotherVo); + m_catalogue->TapePool()->createTapePool(m_admin, anotherTapePoolName, m_anotherVo.name, anotherNbPartialTapes, + anotherTapePoolIsEncrypted, supply, anotherTapePoolComment); + const uint32_t copyNb = 1; + const std::string comment = "Create a separate archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_anotherStorageClass.name, copyNb, anotherTapePoolName, comment); + } + + { + const auto pools = CatalogueTestUtils::tapePoolListToMap(m_catalogue->TapePool()->getTapePools()); + + ASSERT_EQ(2, pools.size()); + + { + const auto poolMaplet = pools.find(m_tape1.tapePoolName); + ASSERT_NE(pools.end(), poolMaplet); + + const auto &pool = poolMaplet->second; + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(tapePoolNbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(tapePoolIsEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(tapePoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto poolMaplet = pools.find(anotherTapePoolName); + ASSERT_NE(pools.end(), poolMaplet); + + const auto &pool = poolMaplet->second; + ASSERT_EQ(anotherTapePoolName, pool.name); + ASSERT_EQ(m_anotherVo.name, pool.vo.name); + ASSERT_EQ(anotherNbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(anotherTapePoolIsEncrypted, pool.encryption); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(anotherTapePoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + } + + m_catalogue->TapePool()->deleteTapePool(m_tape1.tapePoolName); + + ASSERT_EQ(1, m_catalogue->TapePool()->getTapePools().size()); +} + +TEST_P(cta_catalogue_TapePoolTest, deleteTapePool_notEmpty) { + const bool logicalLibraryIsDisabled= false; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + m_catalogue->MediaType()->createMediaType(m_admin, m_mediaType); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(m_admin, m_tape1.logicalLibraryName, logicalLibraryIsDisabled, + "Create logical library"); + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + m_catalogue->Tape()->createTape(m_admin, m_tape1); + + ASSERT_TRUE(m_catalogue->Tape()->tapeExists(m_tape1.vid)); + + const auto tapes = m_catalogue->Tape()->getTapes(); + + ASSERT_EQ(1, tapes.size()); + + { + const auto tape = tapes.front(); + ASSERT_EQ(m_tape1.vid, tape.vid); + ASSERT_EQ(m_tape1.mediaType, tape.mediaType); + ASSERT_EQ(m_tape1.vendor, tape.vendor); + ASSERT_EQ(m_tape1.logicalLibraryName, tape.logicalLibraryName); + ASSERT_EQ(m_tape1.tapePoolName, tape.tapePoolName); + ASSERT_EQ(m_vo.name, tape.vo); + ASSERT_EQ(m_mediaType.capacityInBytes, tape.capacityInBytes); + ASSERT_EQ(m_tape1.state,tape.state); + ASSERT_EQ(m_tape1.full, tape.full); + ASSERT_FALSE(tape.isFromCastor); + ASSERT_EQ(m_tape1.comment, tape.comment); + ASSERT_FALSE(tape.labelLog); + ASSERT_FALSE(tape.lastReadLog); + ASSERT_FALSE(tape.lastWriteLog); + + const auto creationLog = tape.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const auto lastModificationLog = tape.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(m_tape1.tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(1, pool.nbTapes); + ASSERT_EQ(m_mediaType.capacityInBytes, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + } + + ASSERT_THROW(m_catalogue->TapePool()->deleteTapePool(m_tape1.tapePoolName), + cta::catalogue::UserSpecifiedAnEmptyTapePool); + ASSERT_THROW(m_catalogue->TapePool()->deleteTapePool(m_tape1.tapePoolName), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_emptyStringTapePoolName) { + const std::string tapePoolName = ""; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + ASSERT_THROW(m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, + supply, comment), cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_emptyStringVO) { + const std::string vo = ""; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + ASSERT_THROW(m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, "", nbPartialTapes, isEncrypted, + supply, comment), cta::catalogue::UserSpecifiedAnEmptyStringVo); +} + +TEST_P(cta_catalogue_TapePoolTest, createTapePool_emptyStringComment) { + const std::string tapePoolName = "tape_pool"; + + ASSERT_FALSE(m_catalogue->TapePool()->tapePoolExists(tapePoolName)); + + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = ""; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + ASSERT_THROW(m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, + isEncrypted, supply, comment), cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_TapePoolTest, deleteTapePool_non_existent) { + ASSERT_THROW(m_catalogue->TapePool()->deleteTapePool("non_existent_tape_pool"), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, deleteTapePool_used_in_an_archive_route) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + const uint32_t copyNb = 1; + const std::string comment = "Create archive route"; + m_catalogue->ArchiveRoute()->createArchiveRoute(m_admin, m_storageClassSingleCopy.name, copyNb, tapePoolName, comment); + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes = m_catalogue->ArchiveRoute()->getArchiveRoutes(); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + { + const std::list<cta::common::dataStructures::ArchiveRoute> routes + = m_catalogue->ArchiveRoute()->getArchiveRoutes(m_storageClassSingleCopy.name, tapePoolName); + + ASSERT_EQ(1, routes.size()); + + const cta::common::dataStructures::ArchiveRoute route = routes.front(); + ASSERT_EQ(m_storageClassSingleCopy.name, route.storageClassName); + ASSERT_EQ(copyNb, route.copyNb); + ASSERT_EQ(tapePoolName, route.tapePoolName); + ASSERT_EQ(comment, route.comment); + + const cta::common::dataStructures::EntryLog creationLog = route.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = route.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + ASSERT_THROW(m_catalogue->TapePool()->deleteTapePool(tapePoolName), + cta::catalogue::UserSpecifiedTapePoolUsedInAnArchiveRoute); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolVo) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + auto modifiedVo = m_vo; + modifiedVo.name = "modified_vo"; + m_catalogue->VO()->createVirtualOrganization(m_admin, modifiedVo); + m_catalogue->TapePool()->modifyTapePoolVo(m_admin, tapePoolName, modifiedVo.name); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(modifiedVo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolVo_emptyStringTapePool) { + const std::string tapePoolName = ""; + const std::string modifiedVo = "modified_vo"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolVo(m_admin, tapePoolName, modifiedVo), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolVo_emptyStringVo) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedVo = ""; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolVo(m_admin, tapePoolName, modifiedVo), + cta::catalogue::UserSpecifiedAnEmptyStringVo); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolVo_VoDoesNotExist) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedVo = "DoesNotExists"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolVo(m_admin, tapePoolName, modifiedVo), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolNbPartialTapes) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const uint64_t modifiedNbPartialTapes = 5; + m_catalogue->TapePool()->modifyTapePoolNbPartialTapes(m_admin, tapePoolName, modifiedNbPartialTapes); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(modifiedNbPartialTapes, 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolNbPartialTapes_emptyStringTapePoolName) { + const std::string tapePoolName = ""; + const uint64_t modifiedNbPartialTapes = 5; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolNbPartialTapes(m_admin, tapePoolName, modifiedNbPartialTapes), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolNbPartialTapes_nonExistentTapePool) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 5; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolNbPartialTapes(m_admin, tapePoolName, nbPartialTapes), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolComment) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = "Modified comment"; + m_catalogue->TapePool()->modifyTapePoolComment(m_admin, tapePoolName, modifiedComment); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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(modifiedComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolComment_emptyStringTapePoolName) { + const std::string tapePoolName = ""; + const std::string modifiedComment = "Modified comment"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolComment(m_admin, tapePoolName, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolComment_emptyStringComment) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedComment = ""; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolComment(m_admin, tapePoolName, modifiedComment), + cta::catalogue::UserSpecifiedAnEmptyStringComment); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolComment_nonExistentTapePool) { + const std::string tapePoolName = "tape_pool"; + const std::string comment = "Comment"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolComment(m_admin, tapePoolName, comment), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, setTapePoolEncryption) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const bool modifiedIsEncrypted = !isEncrypted; + m_catalogue->TapePool()->setTapePoolEncryption(m_admin, tapePoolName, modifiedIsEncrypted); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(modifiedIsEncrypted, 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, setTapePoolEncryption_nonExistentTapePool) { + const std::string tapePoolName = "tape_pool"; + const bool isEncrypted = false; + ASSERT_THROW(m_catalogue->TapePool()->setTapePoolEncryption(m_admin, tapePoolName, isEncrypted), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolSupply) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedSupply("Modified supply"); + m_catalogue->TapePool()->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(modifiedSupply, pool.supply.value()); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolSupply_emptyStringTapePoolName) { + const std::string tapePoolName = ""; + const std::string modifiedSupply = "Modified supply"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolSupply_emptyStringSupply) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_TRUE((bool)supply); + ASSERT_EQ(supply.value(), pool.supply.value()); + ASSERT_EQ(supply, pool.supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string modifiedSupply; + m_catalogue->TapePool()->modifyTapePoolSupply(m_admin, tapePoolName, modifiedSupply); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(isEncrypted, pool.encryption); + ASSERT_FALSE((bool)pool.supply); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolSupply_nonExistentTapePool) { + const std::string tapePoolName = "tape_pool"; + const std::string supply = "value for the supply pool mechanism"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolSupply(m_admin, tapePoolName, supply), cta::exception::UserError); +} + +TEST_P(cta_catalogue_TapePoolTest, getTapePools_filterName) { + const std::string tapePoolName = "tape_pool"; + const std::string secondTapePoolName = "tape_pool_2"; + + const uint64_t nbFirstPoolPartialTapes = 2; + const uint64_t nbSecondPoolPartialTapes = 3; + + const bool firstPoolIsEncrypted = true; + const bool secondPoolIsEncrypted = false; + + const std::optional<std::string> firstPoolSupply("value for the supply first pool mechanism"); + const std::optional<std::string> secondPoolSupply("value for the supply second pool mechanism"); + + const std::string firstPoolComment = "Create first tape pool"; + const std::string secondPoolComment = "Create second tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_anotherVo); + + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName, m_vo.name, nbFirstPoolPartialTapes, + firstPoolIsEncrypted, firstPoolSupply, firstPoolComment); + m_catalogue->TapePool()->createTapePool(m_admin, secondTapePoolName, m_anotherVo.name, nbSecondPoolPartialTapes, + secondPoolIsEncrypted, secondPoolSupply, secondPoolComment); + + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.name = tapePoolName; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbFirstPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(firstPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(firstPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.name = secondTapePoolName; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(secondTapePoolName, pool.name); + ASSERT_EQ(m_anotherVo.name, pool.vo.name); + ASSERT_EQ(nbSecondPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(secondPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(secondPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.name = "no pool with such name"; + + ASSERT_THROW(m_catalogue->TapePool()->getTapePools(criteria), cta::catalogue::UserSpecifiedANonExistentTapePool); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.name = ""; + + ASSERT_THROW(m_catalogue->TapePool()->getTapePools(criteria), cta::exception::UserError); + } +} + +TEST_P(cta_catalogue_TapePoolTest, getTapePools_filterVO) { + const std::string tapePoolName = "tape_pool"; + const std::string secondTapePoolName = "tape_pool_2"; + + const uint64_t nbFirstPoolPartialTapes = 2; + const uint64_t nbSecondPoolPartialTapes = 3; + + const bool firstPoolIsEncrypted = true; + const bool secondPoolIsEncrypted = false; + + const std::optional<std::string> firstPoolSupply("value for the supply first pool mechanism"); + const std::optional<std::string> secondPoolSupply("value for the supply second pool mechanism"); + + const std::string firstPoolComment = "Create first tape pool"; + const std::string secondPoolComment = "Create second tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_anotherVo); + + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName, m_vo.name, nbFirstPoolPartialTapes, + firstPoolIsEncrypted, firstPoolSupply, firstPoolComment); + m_catalogue->TapePool()->createTapePool(m_admin, secondTapePoolName, m_anotherVo.name, nbSecondPoolPartialTapes, + secondPoolIsEncrypted, secondPoolSupply, secondPoolComment); + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.vo = m_vo.name; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbFirstPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(firstPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(firstPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.vo = m_anotherVo.name; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(secondTapePoolName, pool.name); + ASSERT_EQ(m_anotherVo.name, pool.vo.name); + ASSERT_EQ(nbSecondPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(secondPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(secondPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.vo = "no vo with such name"; + + ASSERT_THROW(m_catalogue->TapePool()->getTapePools(criteria), + cta::catalogue::UserSpecifiedANonExistentVirtualOrganization); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.vo = ""; + + ASSERT_THROW(m_catalogue->TapePool()->getTapePools(criteria), cta::exception::UserError); + } +} + +TEST_P(cta_catalogue_TapePoolTest, getTapePools_filterEncrypted) { + const std::string tapePoolName = "tape_pool"; + const std::string secondTapePoolName = "tape_pool_2"; + + const uint64_t nbFirstPoolPartialTapes = 2; + const uint64_t nbSecondPoolPartialTapes = 3; + + const bool firstPoolIsEncrypted = true; + const bool secondPoolIsEncrypted = false; + + const std::optional<std::string> firstPoolSupply("value for the supply first pool mechanism"); + const std::optional<std::string> secondPoolSupply("value for the supply second pool mechanism"); + + const std::string firstPoolComment = "Create first tape pool"; + const std::string secondPoolComment = "Create second tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_anotherVo); + + m_catalogue->TapePool()->createTapePool(m_admin, tapePoolName, m_vo.name, nbFirstPoolPartialTapes, + firstPoolIsEncrypted, firstPoolSupply, firstPoolComment); + m_catalogue->TapePool()->createTapePool(m_admin, secondTapePoolName, m_anotherVo.name, nbSecondPoolPartialTapes, + secondPoolIsEncrypted, secondPoolSupply, secondPoolComment); + + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.encrypted = true; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + ASSERT_EQ(nbFirstPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(firstPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(firstPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } + + { + cta::catalogue::TapePoolSearchCriteria criteria; + criteria.encrypted = false; + const auto pools = m_catalogue->TapePool()->getTapePools(criteria); + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(secondTapePoolName, pool.name); + ASSERT_EQ(m_anotherVo.name, pool.vo.name); + ASSERT_EQ(nbSecondPoolPartialTapes, pool.nbPartialTapes); + ASSERT_EQ(secondPoolIsEncrypted, pool.encryption); + ASSERT_TRUE((bool)pool.supply); + ASSERT_EQ(0, pool.nbTapes); + ASSERT_EQ(0, pool.capacityBytes); + ASSERT_EQ(0, pool.dataBytes); + ASSERT_EQ(0, pool.nbPhysicalFiles); + ASSERT_EQ(secondPoolComment, pool.comment); + + const cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolName) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newTapePoolName = "new_tape_pool"; + m_catalogue->TapePool()->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName); + + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(newTapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + } +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolName_emptyStringCurrentTapePoolName) { + const std::string tapePoolName = ""; + const std::string newTapePoolName = "new_tape_pool"; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + +TEST_P(cta_catalogue_TapePoolTest, modifyTapePoolName_emptyStringNewTapePoolName) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + comment); + { + const auto pools = m_catalogue->TapePool()->getTapePools(); + + ASSERT_EQ(1, pools.size()); + + const auto &pool = pools.front(); + ASSERT_EQ(tapePoolName, pool.name); + ASSERT_EQ(m_vo.name, pool.vo.name); + 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 cta::common::dataStructures::EntryLog creationLog = pool.creationLog; + ASSERT_EQ(m_admin.username, creationLog.username); + ASSERT_EQ(m_admin.host, creationLog.host); + + const cta::common::dataStructures::EntryLog lastModificationLog = pool.lastModificationLog; + ASSERT_EQ(creationLog, lastModificationLog); + } + + const std::string newTapePoolName = ""; + ASSERT_THROW(m_catalogue->TapePool()->modifyTapePoolName(m_admin, tapePoolName, newTapePoolName), + cta::catalogue::UserSpecifiedAnEmptyStringTapePoolName); +} + + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/TapePoolCatalogueTest.hpp b/catalogue/tests/modules/TapePoolCatalogueTest.hpp new file mode 100644 index 0000000000..9701d7ee87 --- /dev/null +++ b/catalogue/tests/modules/TapePoolCatalogueTest.hpp @@ -0,0 +1,56 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_TapePoolTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_TapePoolTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::VirtualOrganization m_anotherVo; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::StorageClass m_anotherStorageClass; + const cta::catalogue::MediaType m_mediaType; + const cta::catalogue::CreateTapeAttributes m_tape1; +}; + +} // namespace unitTests diff --git a/catalogue/tests/modules/VirtualOrganizationCatalogueTest.cpp b/catalogue/tests/modules/VirtualOrganizationCatalogueTest.cpp new file mode 100644 index 0000000000..801ba27dae --- /dev/null +++ b/catalogue/tests/modules/VirtualOrganizationCatalogueTest.cpp @@ -0,0 +1,335 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "catalogue/tests/CatalogueTestUtils.hpp" +#include "catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/exception/Exception.hpp" +#include "common/exception/UserError.hpp" +#include "common/log/DummyLogger.hpp" +#include "common/log/LogContext.hpp" +#include "common/utils/utils.hpp" + +namespace unitTests { + +cta_catalogue_VirtualOrganizationTest::cta_catalogue_VirtualOrganizationTest() + : m_dummyLog("dummy", "dummy"), + m_admin(CatalogueTestUtils::getAdmin()), + m_vo(CatalogueTestUtils::getVo()), + m_storageClassSingleCopy(CatalogueTestUtils::getStorageClass()), + m_diskInstance(CatalogueTestUtils::getDiskInstance()), + m_tape1(CatalogueTestUtils::getTape1()) { +} + +void cta_catalogue_VirtualOrganizationTest::SetUp() { + cta::log::LogContext dummyLc(m_dummyLog); + m_catalogue = CatalogueTestUtils::createCatalogue(GetParam(), &dummyLc); +} + +void cta_catalogue_VirtualOrganizationTest::TearDown() { + m_catalogue.reset(); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganization) { + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganizationAlreadyExists) { + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + ASSERT_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganizationAlreadyExistsCaseSensitive) { + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + cta::utils::toUpper(vo.name); + ASSERT_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganizationEmptyComment) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + vo.comment = ""; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganizationEmptyName) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + vo.name = ""; + vo.comment = "comment"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, createVirtualOrganizationEmptyDiskInstanceName) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + vo.diskInstanceName = ""; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, deleteVirtualOrganization) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + ASSERT_NO_THROW(m_catalogue->VO()->deleteVirtualOrganization(vo.name)); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, deleteVirtualOrganizationUsedByTapePool) { + const std::string tapePoolName = "tape_pool"; + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + const std::string comment = "Create tape pool"; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, comment); + + ASSERT_THROW(m_catalogue->VO()->deleteVirtualOrganization(m_vo.name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, deleteVirtualOrganizationNameDoesNotExist) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + ASSERT_THROW(m_catalogue->VO()->deleteVirtualOrganization("DOES_NOT_EXIST"),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, deleteVirtualOrganizationUsedByStorageClass) { + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin, m_vo); + m_catalogue->StorageClass()->createStorageClass(m_admin, m_storageClassSingleCopy); + ASSERT_THROW(m_catalogue->VO()->deleteVirtualOrganization(m_vo.name), cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, getVirtualOrganizations) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + std::list<cta::common::dataStructures::VirtualOrganization> vos = m_catalogue->VO()->getVirtualOrganizations(); + ASSERT_EQ(1,vos.size()); + + auto &voRetrieved = vos.front(); + ASSERT_EQ(vo.name,voRetrieved.name); + ASSERT_EQ(vo.readMaxDrives,voRetrieved.readMaxDrives); + ASSERT_EQ(vo.writeMaxDrives,voRetrieved.writeMaxDrives); + ASSERT_EQ(vo.diskInstanceName,voRetrieved.diskInstanceName); + ASSERT_EQ(vo.comment,voRetrieved.comment); + + ASSERT_EQ(m_admin.host,voRetrieved.creationLog.host); + ASSERT_EQ(m_admin.username,voRetrieved.creationLog.username); + ASSERT_EQ(m_admin.host,voRetrieved.lastModificationLog.host); + ASSERT_EQ(m_admin.username,voRetrieved.lastModificationLog.username); + + + ASSERT_NO_THROW(m_catalogue->VO()->deleteVirtualOrganization(vo.name)); + vos = m_catalogue->VO()->getVirtualOrganizations(); + ASSERT_EQ(0,vos.size()); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationName) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + std::string newVoName = "NewVoName"; + + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationName(m_admin,vo.name,newVoName)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + + auto voFront = vos.front(); + ASSERT_EQ(newVoName,voFront.name); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationNameVoDoesNotExists) { + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationName(m_admin,"DOES_NOT_EXIST","NEW_NAME"), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationNameThatAlreadyExists) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + std::string vo2Name = "vo2"; + std::string vo1Name = vo.name; + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + vo.name = vo2Name; + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationName(m_admin,vo1Name,vo2Name),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationComment) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + std::string newComment = "newComment"; + + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationComment(m_admin,vo.name,newComment)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + auto &frontVo = vos.front(); + + ASSERT_EQ(newComment, frontVo.comment); + + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationComment(m_admin,"DOES not exists","COMMENT_DOES_NOT_EXIST"), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationReadMaxDrives) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + uint64_t readMaxDrives = 42; + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationReadMaxDrives(m_admin,vo.name,readMaxDrives)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + auto &frontVo = vos.front(); + + ASSERT_EQ(readMaxDrives,frontVo.readMaxDrives); + + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationReadMaxDrives(m_admin,"DOES not exists",readMaxDrives), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationWriteMaxDrives) { + cta::common::dataStructures::VirtualOrganization vo =CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + uint64_t writeMaxDrives = 42; + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationWriteMaxDrives(m_admin,vo.name,writeMaxDrives)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + auto &frontVo = vos.front(); + + ASSERT_EQ(writeMaxDrives,frontVo.writeMaxDrives); + + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationWriteMaxDrives(m_admin,"DOES not exists",writeMaxDrives), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationMaxFileSize) { + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + uint64_t maxFileSize = 1; + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationMaxFileSize(m_admin,vo.name,maxFileSize)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + auto &frontVo = vos.front(); + + ASSERT_EQ(maxFileSize,frontVo.maxFileSize); + + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationMaxFileSize(m_admin,"DOES not exists", maxFileSize), + cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationDiskInstanceName) { + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + std::string diskInstanceName = "diskInstanceName"; + m_catalogue->DiskInstance()->createDiskInstance(m_admin, diskInstanceName, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->modifyVirtualOrganizationDiskInstanceName(m_admin,vo.name,diskInstanceName)); + + auto vos = m_catalogue->VO()->getVirtualOrganizations(); + auto &frontVo = vos.front(); + + ASSERT_EQ(diskInstanceName,frontVo.diskInstanceName); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationDiskInstanceNameNonExistingVO) { + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationDiskInstanceName(m_admin,"DOES not exists", + "VO_DOES_NOT_EXIST"),cta::exception::UserError); +} + +TEST_P(cta_catalogue_VirtualOrganizationTest, modifyVirtualOrganizationDiskInstanceNameNonExistingDiskInstance) { + const cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + ASSERT_NO_THROW(m_catalogue->VO()->createVirtualOrganization(m_admin,vo)); + + const std::string diskInstanceName = "diskInstanceName"; + ASSERT_THROW(m_catalogue->VO()->modifyVirtualOrganizationDiskInstanceName(m_admin,vo.name,diskInstanceName), + cta::exception::Exception); +} + + +TEST_P(cta_catalogue_VirtualOrganizationTest, getVirtualOrganizationOfTapepool) { + const uint64_t nbPartialTapes = 2; + const bool isEncrypted = true; + const std::optional<std::string> supply("value for the supply pool mechanism"); + + cta::common::dataStructures::VirtualOrganization vo = CatalogueTestUtils::getVo(); + + m_catalogue->DiskInstance()->createDiskInstance(m_admin, m_diskInstance.name, m_diskInstance.comment); + m_catalogue->VO()->createVirtualOrganization(m_admin,vo); + m_catalogue->TapePool()->createTapePool(m_admin, m_tape1.tapePoolName, m_vo.name, nbPartialTapes, isEncrypted, supply, + "Create tape pool"); + + cta::common::dataStructures::VirtualOrganization voFromTapepool = + m_catalogue->VO()->getVirtualOrganizationOfTapepool(m_tape1.tapePoolName); + ASSERT_EQ(vo,voFromTapepool); + + ASSERT_THROW(m_catalogue->VO()->getVirtualOrganizationOfTapepool("DOES_NOT_EXIST"),cta::exception::Exception); +} + +} // namespace unitTests \ No newline at end of file diff --git a/catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp b/catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp new file mode 100644 index 0000000000..fa02451549 --- /dev/null +++ b/catalogue/tests/modules/VirtualOrganizationCatalogueTest.hpp @@ -0,0 +1,52 @@ +/* + * @project The CERN Tape Archive (CTA) + * @copyright Copyright © 2022 CERN + * @license This program is free software, distributed under the terms of the GNU General Public + * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". You can + * redistribute it and/or modify it under the terms of the GPL Version 3, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * In applying this licence, CERN does not waive the privileges and immunities + * granted to it by virtue of its status as an Intergovernmental Organization or + * submit itself to any jurisdiction. + */ + +#pragma once + +#include <gtest/gtest.h> + +#include <memory> + +#include "catalogue/Catalogue.hpp" +#include "catalogue/CreateTapeAttributes.hpp" +#include "common/dataStructures/DiskInstance.hpp" +#include "common/dataStructures/SecurityIdentity.hpp" +#include "common/dataStructures/StorageClass.hpp" +#include "common/dataStructures/VirtualOrganization.hpp" +#include "common/log/DummyLogger.hpp" + +namespace unitTests { + +class cta_catalogue_VirtualOrganizationTest : public ::testing::TestWithParam<cta::catalogue::CatalogueFactory **> { +public: + cta_catalogue_VirtualOrganizationTest(); + + void SetUp() override; + void TearDown() override; + +protected: + cta::log::DummyLogger m_dummyLog; + std::unique_ptr<cta::catalogue::Catalogue> m_catalogue; + + const cta::common::dataStructures::SecurityIdentity m_admin; + const cta::common::dataStructures::VirtualOrganization m_vo; + const cta::common::dataStructures::StorageClass m_storageClassSingleCopy; + const cta::common::dataStructures::DiskInstance m_diskInstance; + const cta::catalogue::CreateTapeAttributes m_tape1; +}; + +} // namespace unitTests diff --git a/disk/DiskSystem.cpp b/disk/DiskSystem.cpp index e4bf79b69c..a1158a4d3d 100644 --- a/disk/DiskSystem.cpp +++ b/disk/DiskSystem.cpp @@ -146,7 +146,8 @@ void DiskSystemFreeSpaceList::fetchDiskSystemFreeSpace(const std::set<std::strin entry.targetedFreeSpace = m_systemList.at(ds).targetedFreeSpace; if (updateCatalogue) { - catalogue.modifyDiskInstanceSpaceFreeSpace(diskInstanceSpace.name, diskInstanceSpace.diskInstance, freeSpace); + catalogue.DiskInstanceSpace()->modifyDiskInstanceSpaceFreeSpace(diskInstanceSpace.name, + diskInstanceSpace.diskInstance, freeSpace); } } if(failedToFetchDiskSystems.size()){ diff --git a/disk/DiskSystemTest.cpp b/disk/DiskSystemTest.cpp index fcdd16347b..e26fef1763 100644 --- a/disk/DiskSystemTest.cpp +++ b/disk/DiskSystemTest.cpp @@ -74,13 +74,13 @@ namespace unitTests { // create disk instance std::string diskInstanceName = "DiskInstanceNameSpinner"; std::string diskInstanceComment = "Comment"; - catalogue.createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); + catalogue.DiskInstance()->createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); // create disk instance space std::string diskInstanceSpaceName = "DiskInstanceSpaceSpinner"; std::string freeSpaceQueryURL = "eos:ctaeos:spinners"; uint64_t refrestInterval = 1; std::string diskInstanceSpaceComment = "Comment"; - catalogue.createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); m_diskSystemSpinner.name = "DiskSystemNameSpinner"; m_diskSystemSpinner.fileRegexp = "root://ctaeos.archiveretrieve-1215709git0e38ccd0-xi98.svc.cluster.local//eos/ctaeos/cta(.*)eos.space=spinners"; @@ -88,7 +88,7 @@ namespace unitTests { m_diskSystemSpinner.sleepTime = 1; m_diskSystemSpinner.comment = "Comment"; - catalogue.createDiskSystem(m_cliId,m_diskSystemSpinner.name, diskInstanceName, diskInstanceSpaceName, m_diskSystemSpinner.fileRegexp, + catalogue.DiskSystem()->createDiskSystem(m_cliId,m_diskSystemSpinner.name, diskInstanceName, diskInstanceSpaceName, m_diskSystemSpinner.fileRegexp, m_diskSystemSpinner.targetedFreeSpace, m_diskSystemSpinner.sleepTime,m_diskSystemSpinner.comment); } @@ -98,13 +98,13 @@ namespace unitTests { // create disk instance std::string diskInstanceName = "ctaeos"; std::string diskInstanceComment = "Comment"; - catalogue.createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); + catalogue.DiskInstance()->createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); // create disk instance space std::string diskInstanceSpaceName = "DiskInstanceSpaceDefault"; std::string freeSpaceQueryURL = "eosSpace:default"; uint64_t refrestInterval = 1; std::string diskInstanceSpaceComment = "Comment"; - catalogue.createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); // create disk system m_diskSystemDefault.name = "DiskSystemNameDefault"; m_diskSystemDefault.fileRegexp = "root://ctaeos.archiveretrieve-1215709git0e38ccd0-xi98.svc.cluster.local//eos/ctaeos/cta(.*)eos.space=default"; @@ -112,7 +112,7 @@ namespace unitTests { m_diskSystemDefault.sleepTime = 1; m_diskSystemDefault.comment = "Comment"; - catalogue.createDiskSystem(m_cliId,m_diskSystemDefault.name, diskInstanceName, diskInstanceSpaceName, m_diskSystemDefault.fileRegexp, + catalogue.DiskSystem()->createDiskSystem(m_cliId,m_diskSystemDefault.name, diskInstanceName, diskInstanceSpaceName, m_diskSystemDefault.fileRegexp, m_diskSystemDefault.targetedFreeSpace, m_diskSystemDefault.sleepTime,m_diskSystemDefault.comment); } @@ -122,7 +122,7 @@ namespace unitTests { auto & catalogue = getCatalogue(); - auto allDiskSystem = catalogue.getAllDiskSystems(); + auto allDiskSystem = catalogue.DiskSystem()->getAllDiskSystems(); std::string dstURL = "root://ctaeos.archiveretrieve-1215709git0e38ccd0-xi98.svc.cluster.local//eos/ctaeos/cta/54065a67-a3ea-4a44-b213-6f6a6f4e2cf4?eos.lfn=fxid:7&eos.ruid=0&eos.rgid=0&eos.injection=1&eos.workflow=retrieve_written&eos.space=spinners&toto=5"; @@ -144,13 +144,13 @@ namespace unitTests { // create disk instance std::string diskInstanceName = "DiskInstanceNameConstantFreeSpace"; std::string diskInstanceComment = "Comment"; - catalogue.createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); + catalogue.DiskInstance()->createDiskInstance(m_cliId, diskInstanceName, diskInstanceComment); // create disk instance space std::string diskInstanceSpaceName = "DiskInstanceSpaceConstantFreeSpace"; std::string freeSpaceQueryURL = "constantFreeSpace:200"; uint64_t refrestInterval = 1; std::string diskInstanceSpaceComment = "Comment"; - catalogue.createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(m_cliId, diskInstanceSpaceName, diskInstanceName, freeSpaceQueryURL, refrestInterval, diskInstanceSpaceComment); // create disk system cta::disk::DiskSystem constantFreeSpaceDiskSystem; @@ -160,10 +160,10 @@ namespace unitTests { constantFreeSpaceDiskSystem.sleepTime = 1; constantFreeSpaceDiskSystem.comment = "Comment"; - catalogue.createDiskSystem(m_cliId,constantFreeSpaceDiskSystem.name, diskInstanceName, diskInstanceSpaceName, constantFreeSpaceDiskSystem.fileRegexp, + catalogue.DiskSystem()->createDiskSystem(m_cliId,constantFreeSpaceDiskSystem.name, diskInstanceName, diskInstanceSpaceName, constantFreeSpaceDiskSystem.fileRegexp, constantFreeSpaceDiskSystem.targetedFreeSpace, constantFreeSpaceDiskSystem.sleepTime,constantFreeSpaceDiskSystem.comment); - auto allDiskSystem = catalogue.getAllDiskSystems(); + auto allDiskSystem = catalogue.DiskSystem()->getAllDiskSystems(); cta::disk::DiskSystemFreeSpaceList diskSystemFreeSpaceList (allDiskSystem); std::set<std::string> diskSystemsToFetch {"DiskSystemNotExists"}; diff --git a/frontend-grpc/FrontendGRpcSvc.cpp b/frontend-grpc/FrontendGRpcSvc.cpp index 6e76a5aa94..3ca755654f 100644 --- a/frontend-grpc/FrontendGRpcSvc.cpp +++ b/frontend-grpc/FrontendGRpcSvc.cpp @@ -220,7 +220,7 @@ Status CtaRpcImpl::Delete(::grpc::ServerContext* context, const ::cta::frontend: // Delete the file from the catalogue or from the objectstore if archive request is created cta::utils::Timer t; try { - deleteRequest.archiveFile = m_catalogue->getArchiveFileById(deleteRequest.archiveFileID); + deleteRequest.archiveFile = m_catalogue->ArchiveFile()->getArchiveFileById(deleteRequest.archiveFileID); } catch (cta::exception::Exception &ex){ lc.log(cta::log::WARNING, "Deleted file is not in catalog."); } diff --git a/frontend-grpc/Main.cpp b/frontend-grpc/Main.cpp index 8335c79db9..ce134dfacf 100644 --- a/frontend-grpc/Main.cpp +++ b/frontend-grpc/Main.cpp @@ -135,8 +135,9 @@ int main(const int argc, char *const *const argv) { nbArchiveFileListingConns); auto catalogue = catalogueFactory->create(); try { - catalogue->ping(); - lc.log(log::INFO, "Connected to catalog " + catalogue->getSchemaVersion().getSchemaVersion<std::string>()); + catalogue->Schema()->ping(); + lc.log(log::INFO, "Connected to catalog " + catalogue->Schema()->getSchemaVersion(). + getSchemaVersion<std::string>()); } catch (cta::exception::Exception &ex) { lc.log(cta::log::CRIT, ex.getMessageValue()); exit(1); diff --git a/frontend/common/FrontendService.cpp b/frontend/common/FrontendService.cpp index 0ad7331b71..4ed101bb0a 100644 --- a/frontend/common/FrontendService.cpp +++ b/frontend/common/FrontendService.cpp @@ -115,7 +115,7 @@ FrontendService::FrontendService(const std::string& configFilename) : m_archiveF catalogue_numberofconnections.value(), nbArchiveFileListingConns); m_catalogue = catalogueFactory->create(); try { - m_catalogue->ping(); + m_catalogue->Schema()->ping(); } catch(cta::exception::Exception& ex) { auto lc = getLogContext(); lc.log(cta::log::CRIT, ex.getMessageValue()); diff --git a/objectstore/AlgorithmsTest.cpp b/objectstore/AlgorithmsTest.cpp index 32a13eaa62..46a2c7cb21 100644 --- a/objectstore/AlgorithmsTest.cpp +++ b/objectstore/AlgorithmsTest.cpp @@ -21,7 +21,7 @@ #include "AgentReference.hpp" #include "ArchiveQueueAlgorithms.hpp" #include "BackendVFS.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "common/dataStructures/JobQueueType.hpp" #include "common/log/DummyLogger.hpp" #ifdef STDOUT_LOGGING diff --git a/objectstore/GarbageCollectorTest.cpp b/objectstore/GarbageCollectorTest.cpp index e49a07d779..f89d3e4fe9 100644 --- a/objectstore/GarbageCollectorTest.cpp +++ b/objectstore/GarbageCollectorTest.cpp @@ -24,7 +24,8 @@ #include "ArchiveQueue.hpp" #include "ArchiveRequest.hpp" #include "BackendVFS.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyTapeCatalogue.hpp" #include "common/dataStructures/ArchiveFile.hpp" #include "common/dataStructures/JobQueueType.hpp" #include "common/exception/Exception.hpp" @@ -618,9 +619,9 @@ TEST_F(ObjectStore, GarbageCollectorRetrieveRequest) { break; } // Mark the tape as enabled - catalogue.addEnabledTape("Tape0"); + static_cast<cta::catalogue::DummyTapeCatalogue*>(catalogue.Tape().get())->addEnabledTape("Tape0"); // Mark the other tape as disabled - catalogue.addDisabledTape("Tape1"); + static_cast<cta::catalogue::DummyTapeCatalogue*>(catalogue.Tape().get())->addDisabledTape("Tape1"); // Create the garbage collector and run it twice. cta::objectstore::AgentReference gcAgentRef("unitTestGarbageCollector", dl); cta::objectstore::Agent gcAgent(gcAgentRef.getAgentAddress(), be); @@ -1668,7 +1669,7 @@ TEST_F(ObjectStore, GarbageCollectorRetrieveRequestRepackRepackingTape) { gcAgent.setTimeout_us(0); gcAgent.insertAndRegisterSelf(lc); - catalogue.addRepackingTape("Tape0"); + static_cast<cta::catalogue::DummyTapeCatalogue*>(catalogue.Tape().get())->addRepackingTape("Tape0"); cta::objectstore::GarbageCollector gc(be, gcAgentRef, catalogue); gc.runOnePass(lc); diff --git a/objectstore/Helpers.cpp b/objectstore/Helpers.cpp index 75ac3be204..8fd30b4678 100644 --- a/objectstore/Helpers.cpp +++ b/objectstore/Helpers.cpp @@ -392,7 +392,7 @@ std::string Helpers::selectBestRetrieveQueue(const std::set<std::string>& candid } } // Add in all the entries we need for this batch of candidates - auto tapeStatuses = catalogue.getTapesByVid(candidateVids); + auto tapeStatuses = catalogue.Tape()->getTapesByVid(candidateVids); for(auto& ts : tapeStatuses) { g_tapeStatuses[ts.first].tapeStatus = ts.second; g_tapeStatuses[ts.first].updateTime = time(nullptr); @@ -450,7 +450,7 @@ std::string Helpers::selectBestRetrieveQueue(const std::set<std::string>& candid // Get the cached tape status value before releasing the lock if(g_tapeStatuses.find(v) == g_tapeStatuses.end()) { // Handle corner case where there are two candidate vids and the second candidate was evicted because it is stale - auto tapeStatuses = catalogue.getTapesByVid(v); + auto tapeStatuses = catalogue.Tape()->getTapesByVid(v); if(tapeStatuses.size() != 1) { throw cta::exception::Exception("In Helpers::selectBestRetrieveQueue(): candidate vid not found in the TAPE table."); } diff --git a/objectstore/QueueCleanupRunner.cpp b/objectstore/QueueCleanupRunner.cpp index 21a6c4228a..e9115e5359 100644 --- a/objectstore/QueueCleanupRunner.cpp +++ b/objectstore/QueueCleanupRunner.cpp @@ -76,7 +76,7 @@ void QueueCleanupRunner::runOnePass(log::LogContext &logContext) { cta::common::dataStructures::Tape tapeToCheck; try { - auto vidToTapesMap = m_catalogue.getTapesByVid(queue.vid); //throws an exception if the vid is not found on the database + auto vidToTapesMap = m_catalogue.Tape()->getTapesByVid(queue.vid); //throws an exception if the vid is not found on the database tapeToCheck = vidToTapesMap.at(queue.vid); } catch (const exception::UserError &ex) { log::ScopedParamContainer params(logContext); @@ -189,7 +189,7 @@ void QueueCleanupRunner::runOnePass(log::LogContext &logContext) { cta::common::dataStructures::Tape tapeToModify; try { - auto vidToTapesMap = m_catalogue.getTapesByVid(qForCleanup.vid); //throws an exception if the vid is not found on the database + auto vidToTapesMap = m_catalogue.Tape()->getTapesByVid(qForCleanup.vid); //throws an exception if the vid is not found on the database tapeToModify = vidToTapesMap.at(qForCleanup.vid); } catch (const exception::UserError &ex) { log::ScopedParamContainer params(logContext); @@ -204,15 +204,18 @@ void QueueCleanupRunner::runOnePass(log::LogContext &logContext) { std::optional<std::string> prevReason = tapeToModify.stateReason; switch (tapeToModify.state) { case common::dataStructures::Tape::REPACKING_PENDING: - m_catalogue.modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::REPACKING, common::dataStructures::Tape::REPACKING_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to REPACKING")); + m_catalogue.Tape()->modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::REPACKING, + common::dataStructures::Tape::REPACKING_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to REPACKING")); m_db.clearRetrieveQueueStatisticsCache(qForCleanup.vid); break; case common::dataStructures::Tape::BROKEN_PENDING: - m_catalogue.modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::BROKEN, common::dataStructures::Tape::BROKEN_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to BROKEN")); + m_catalogue.Tape()->modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::BROKEN, + common::dataStructures::Tape::BROKEN_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to BROKEN")); m_db.clearRetrieveQueueStatisticsCache(qForCleanup.vid); break; case common::dataStructures::Tape::EXPORTED_PENDING: - m_catalogue.modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::EXPORTED, common::dataStructures::Tape::EXPORTED_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to EXPORTED")); + m_catalogue.Tape()->modifyTapeState(admin, qForCleanup.vid, common::dataStructures::Tape::EXPORTED, + common::dataStructures::Tape::EXPORTED_PENDING, prevReason.value_or("QueueCleanupRunner: changed tape state to EXPORTED")); m_db.clearRetrieveQueueStatisticsCache(qForCleanup.vid); break; default: diff --git a/objectstore/QueueCleanupRunnerConcurrentTest.cpp b/objectstore/QueueCleanupRunnerConcurrentTest.cpp index f37ba98443..877694b963 100644 --- a/objectstore/QueueCleanupRunnerConcurrentTest.cpp +++ b/objectstore/QueueCleanupRunnerConcurrentTest.cpp @@ -32,15 +32,16 @@ #include <algorithm> #include <uuid/uuid.h> -#include "objectstore/ObjectStoreFixture.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyTapeCatalogue.hpp" +#include "common/log/StdoutLogger.hpp" #include "objectstore/BackendVFS.hpp" #include "objectstore/GarbageCollector.hpp" +#include "objectstore/ObjectStoreFixture.hpp" #include "objectstore/QueueCleanupRunner.hpp" #include "scheduler/OStoreDB/OStoreDBFactory.hpp" #include "scheduler/OStoreDB/OStoreDBWithAgent.hpp" #include "scheduler/Scheduler.hpp" -#include "common/log/StdoutLogger.hpp" #include "objectstore/QueueCleanupRunnerTestUtils.hpp" @@ -298,7 +299,7 @@ TEST_P(QueueCleanupRunnerConcurrentTest, CleanupRunnerParameterizedTest) { auto initialRetrieveQueueToReportJobs = tapeQueueStateTrans.initialSetup.retrieveQueueToReportJobs; // Initial tape state - catalogue.modifyTapeState(dummyAdmin, vid, initialState, std::nullopt, "Testing"); + catalogue.Tape()->modifyTapeState(dummyAdmin, vid, initialState, std::nullopt, "Testing"); // Assert initial queue setup, for pre-validation of tests { @@ -355,7 +356,8 @@ TEST_P(QueueCleanupRunnerConcurrentTest, CleanupRunnerParameterizedTest) { auto expectedRetrieveQueueToReportJobs = tapeQueueStateTrans.finalSetup.retrieveQueueToReportJobs; // Check final tape state - ASSERT_EQ(expectedState, catalogue.getTapeState(vid)); + const auto tapeState = static_cast<cta::catalogue::DummyTapeCatalogue*>(catalogue.Tape().get())->getTapeState(vid); + ASSERT_EQ(expectedState, tapeState); // Assert final queue setup { diff --git a/objectstore/QueueCleanupRunnerTest.cpp b/objectstore/QueueCleanupRunnerTest.cpp index 0333a2614b..bce276abf5 100644 --- a/objectstore/QueueCleanupRunnerTest.cpp +++ b/objectstore/QueueCleanupRunnerTest.cpp @@ -32,15 +32,16 @@ #include <algorithm> #include <uuid/uuid.h> -#include "objectstore/ObjectStoreFixture.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyTapeCatalogue.hpp" +#include "common/log/StdoutLogger.hpp" #include "objectstore/BackendVFS.hpp" #include "objectstore/GarbageCollector.hpp" -#include "objectstore/QueueCleanupRunnerTestUtils.hpp" +#include "objectstore/ObjectStoreFixture.hpp" #include "objectstore/QueueCleanupRunner.hpp" +#include "objectstore/QueueCleanupRunnerTestUtils.hpp" #include "scheduler/OStoreDB/OStoreDBFactory.hpp" #include "scheduler/Scheduler.hpp" -#include "common/log/StdoutLogger.hpp" //#define STDOUT_LOGGING @@ -274,7 +275,7 @@ TEST_P(QueueCleanupRunnerTest, CleanupRunnerParameterizedTest) { auto initialRetrieveQueueToReportJobs = tapeQueueStateTrans.initialSetup.retrieveQueueToReportJobs; // Initial tape state - catalogue.modifyTapeState(dummyAdmin, vid, initialState, std::nullopt, "Testing"); + catalogue.Tape()->modifyTapeState(dummyAdmin, vid, initialState, std::nullopt, "Testing"); // Assert initial queue setup, for pre-validation of tests { @@ -327,7 +328,8 @@ TEST_P(QueueCleanupRunnerTest, CleanupRunnerParameterizedTest) { auto finalRetrieveQueueToReportJobs = tapeQueueStateTrans.finalSetup.retrieveQueueToReportJobs; // Check final tape state - ASSERT_EQ(finalDesiredState, catalogue.getTapeState(vid)); + const auto tapeState = static_cast<cta::catalogue::DummyTapeCatalogue*>(catalogue.Tape().get())->getTapeState(vid); + ASSERT_EQ(finalDesiredState, tapeState); // Assert final queue setup { diff --git a/objectstore/SorterTest.cpp b/objectstore/SorterTest.cpp index 122a1b4abe..7d9b674e3f 100644 --- a/objectstore/SorterTest.cpp +++ b/objectstore/SorterTest.cpp @@ -36,7 +36,7 @@ #include "ArchiveQueue.hpp" #include "RetrieveQueue.hpp" #include "EntryLogSerDeser.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "Sorter.hpp" #include "ObjectStoreFixture.hpp" diff --git a/scheduler/ArchiveMount.cpp b/scheduler/ArchiveMount.cpp index 6cdaafdda7..eea55e9061 100644 --- a/scheduler/ArchiveMount.cpp +++ b/scheduler/ArchiveMount.cpp @@ -133,7 +133,7 @@ std::string cta::ArchiveMount::getMountTransactionId() const { // updateCatalogueWithTapeFilesWritten //------------------------------------------------------------------------------ void cta::ArchiveMount::updateCatalogueWithTapeFilesWritten(const std::set<cta::catalogue::TapeItemWrittenPointer>& tapeFilesWritten) { - m_catalogue.filesWrittenToTape(tapeFilesWritten); + m_catalogue.TapeFile()->filesWrittenToTape(tapeFilesWritten); } //------------------------------------------------------------------------------ @@ -339,7 +339,7 @@ void cta::ArchiveMount::setTapeMounted(cta::log::LogContext& logContext) const { utils::Timer t; log::ScopedParamContainer spc(logContext); try { - m_catalogue.tapeMountedForArchive(m_dbMount->getMountInfo().vid, m_dbMount->getMountInfo().drive); + m_catalogue.Tape()->tapeMountedForArchive(m_dbMount->getMountInfo().vid, m_dbMount->getMountInfo().drive); auto catalogueTime = t.secs(cta::utils::Timer::resetCounter); spc.add("catalogueTime", catalogueTime); logContext.log(log::INFO, "In ArchiveMount::setTapeMounted(): success."); @@ -355,5 +355,5 @@ void cta::ArchiveMount::setTapeMounted(cta::log::LogContext& logContext) const { // setTapeFull() //------------------------------------------------------------------------------ void cta::ArchiveMount::setTapeFull() { - m_catalogue.noSpaceLeftOnTape(m_dbMount->getMountInfo().vid); + m_catalogue.Tape()->noSpaceLeftOnTape(m_dbMount->getMountInfo().vid); } diff --git a/scheduler/OStoreDB/OStoreDB.cpp b/scheduler/OStoreDB/OStoreDB.cpp index 66c347d65a..3c09822f29 100644 --- a/scheduler/OStoreDB/OStoreDB.cpp +++ b/scheduler/OStoreDB/OStoreDB.cpp @@ -229,7 +229,7 @@ std::list<SchedulerDatabase::RetrieveQueueCleanupInfo> OStoreDB::getRetrieveQueu void OStoreDB::fetchMountInfo(SchedulerDatabase::TapeMountDecisionInfo& tmdi, RootEntry& re, SchedulerDatabase::PurposeGetMountInfo purpose, log::LogContext & logContext) { utils::Timer t, t2; - std::list<common::dataStructures::MountPolicy> mountPolicies = m_catalogue.getCachedMountPolicies(); + std::list<common::dataStructures::MountPolicy> mountPolicies = m_catalogue.MountPolicy()->getCachedMountPolicies(); // Walk the archive queues for USER for statistics for (auto & aqp : re.dumpArchiveQueues(common::dataStructures::JobQueueType::JobsToTransferForUser)) { objectstore::ArchiveQueue aqueue(aqp.address, m_objectStore); @@ -385,7 +385,7 @@ void OStoreDB::fetchMountInfo(SchedulerDatabase::TapeMountDecisionInfo& tmdi, Ro // mount candidates list. auto rqSummary = rqueue.getJobsSummary(); bool isPotentialMount = false; - auto vidToTapeMap = m_catalogue.getTapesByVid(rqp.vid); + auto vidToTapeMap = m_catalogue.Tape()->getTapesByVid(rqp.vid); common::dataStructures::Tape::State tapeState = vidToTapeMap.at(rqp.vid).state; if (tapeState == common::dataStructures::Tape::ACTIVE || tapeState == common::dataStructures::Tape::REPACKING) { @@ -502,7 +502,7 @@ void OStoreDB::fetchMountInfo(SchedulerDatabase::TapeMountDecisionInfo& tmdi, Ro // If a next mount exists the drive "counts double", but the corresponding drive // is either about to mount, or about to replace its current mount. double registerFetchTime = 0; - const auto driveStates = m_catalogue.getTapeDrives(); + const auto driveStates = m_catalogue.DriveState()->getTapeDrives(); registerFetchTime = t.secs(utils::Timer::resetCounter); using common::dataStructures::DriveStatus; std::set<int> activeDriveStatuses = { @@ -3671,12 +3671,12 @@ bool OStoreDB::RetrieveMount::testReserveDiskSpace(const cta::DiskSpaceReservati // Get the current file systems list from the catalogue cta::disk::DiskSystemList diskSystemList; - diskSystemList = m_oStoreDB.m_catalogue.getAllDiskSystems(); + diskSystemList = m_oStoreDB.m_catalogue.DiskSystem()->getAllDiskSystems(); diskSystemList.setExternalFreeDiskSpaceScript(externalFreeDiskSpaceScript); cta::disk::DiskSystemFreeSpaceList diskSystemFreeSpace(diskSystemList); // Get the existing reservation map from drives. - auto previousDrivesReservations = m_oStoreDB.m_catalogue.getDiskSpaceReservations(); + auto previousDrivesReservations = m_oStoreDB.m_catalogue.DriveState()->getDiskSpaceReservations(); // Get the free space from disk systems involved. std::set<std::string> diskSystemNames; for (auto const & dsrr: diskSpaceReservationRequest) { @@ -3747,12 +3747,12 @@ bool OStoreDB::RetrieveMount::reserveDiskSpace(const cta::DiskSpaceReservationRe // Get the current file systems list from the catalogue cta::disk::DiskSystemList diskSystemList; - diskSystemList = m_oStoreDB.m_catalogue.getAllDiskSystems(); + diskSystemList = m_oStoreDB.m_catalogue.DiskSystem()->getAllDiskSystems(); diskSystemList.setExternalFreeDiskSpaceScript(externalFreeDiskSpaceScript); cta::disk::DiskSystemFreeSpaceList diskSystemFreeSpace(diskSystemList); // Get the existing reservation map from drives. - auto previousDrivesReservations = m_oStoreDB.m_catalogue.getDiskSpaceReservations(); + auto previousDrivesReservations = m_oStoreDB.m_catalogue.DriveState()->getDiskSpaceReservations(); // Get the free space from disk systems involved. std::set<std::string> diskSystemNames; for (auto const & dsrr: diskSpaceReservationRequest) { @@ -3812,7 +3812,8 @@ bool OStoreDB::RetrieveMount::reserveDiskSpace(const cta::DiskSpaceReservationRe } } - m_oStoreDB.m_catalogue.reserveDiskSpace(mountInfo.drive, mountInfo.mountId, diskSpaceReservationRequest, logContext); + m_oStoreDB.m_catalogue.DriveState()->reserveDiskSpace(mountInfo.drive, mountInfo.mountId, diskSpaceReservationRequest, + logContext); return true; } @@ -3975,7 +3976,8 @@ void OStoreDB::RetrieveMount::flushAsyncSuccessReports(std::list<cta::SchedulerD } } } - this->m_oStoreDB.m_catalogue.releaseDiskSpace(mountInfo.drive, mountInfo.mountId, diskSpaceReservationRequest, lc); + this->m_oStoreDB.m_catalogue.DriveState()->releaseDiskSpace(mountInfo.drive, mountInfo.mountId, + diskSpaceReservationRequest, lc); // 2) Queue the retrieve requests for repack. for (auto & repackRequestQueue: jobsToRequeueForRepackMap) { typedef objectstore::ContainerAlgorithms<RetrieveQueue,RetrieveQueueToReportToRepackForSuccess> RQTRTRFSAlgo; @@ -4573,7 +4575,7 @@ objectstore::ArchiveRequest::RepackInfo OStoreDB::ArchiveJob::getRepackInfoAfter void OStoreDB::RepackArchiveSuccessesReportBatch::report(log::LogContext& lc) { objectstore::RepackRequest req(m_repackRequest.getAddressIfSet(),this->m_oStoreDb.m_objectStore); req.fetchNoLock(); - this->m_oStoreDb.m_catalogue.setTapeDirty(req.getInfo().vid); + this->m_oStoreDb.m_catalogue.Tape()->setTapeDirty(req.getInfo().vid); OStoreDB::RepackArchiveReportBatch::report(lc); } @@ -4937,7 +4939,7 @@ void OStoreDB::RetrieveJob::failTransfer(const std::string &failureReason, log:: if (diskSystemName) { cta::DiskSpaceReservationRequest dsrr; dsrr.addRequest(diskSystemName.value(), archiveFile.fileSize); - this->m_oStoreDB.m_catalogue.releaseDiskSpace(m_retrieveMount->getMountInfo().drive, + this->m_oStoreDB.m_catalogue.DriveState()->releaseDiskSpace(m_retrieveMount->getMountInfo().drive, m_retrieveMount->getMountInfo().mountId, dsrr, lc); } diff --git a/scheduler/OStoreDB/OStoreDBTest.cpp b/scheduler/OStoreDB/OStoreDBTest.cpp index e4180c96f3..9863d36330 100644 --- a/scheduler/OStoreDB/OStoreDBTest.cpp +++ b/scheduler/OStoreDB/OStoreDBTest.cpp @@ -21,7 +21,7 @@ #include <string> #include <utility> -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "catalogue/InMemoryCatalogue.hpp" #include "common/exception/Exception.hpp" #include "common/log/Logger.hpp" diff --git a/scheduler/RetrieveMount.cpp b/scheduler/RetrieveMount.cpp index 992f5bc49b..5e3bfd4660 100644 --- a/scheduler/RetrieveMount.cpp +++ b/scheduler/RetrieveMount.cpp @@ -356,7 +356,7 @@ void cta::RetrieveMount::setTapeMounted(cta::log::LogContext& logContext) const utils::Timer t; log::ScopedParamContainer spc(logContext); try { - m_catalogue.tapeMountedForRetrieve(m_dbMount->getMountInfo().vid, m_dbMount->getMountInfo().drive); + m_catalogue.Tape()->tapeMountedForRetrieve(m_dbMount->getMountInfo().vid, m_dbMount->getMountInfo().drive); auto catalogueTime = t.secs(cta::utils::Timer::resetCounter); spc.add("catalogueTime", catalogueTime); logContext.log(log::INFO, "In RetrieveMount::setTapeMounted(): success."); diff --git a/scheduler/Scheduler.cpp b/scheduler/Scheduler.cpp index 958255b396..fc02eccbc7 100644 --- a/scheduler/Scheduler.cpp +++ b/scheduler/Scheduler.cpp @@ -73,7 +73,7 @@ Scheduler::~Scheduler() throw() { } //------------------------------------------------------------------------------ void Scheduler::ping(log::LogContext & lc) { cta::utils::Timer t; - m_catalogue.ping(); + m_catalogue.Schema()->ping(); auto catalogueTime = t.secs(cta::utils::Timer::resetCounter); m_db.ping(); auto schedulerDbTime = t.secs(cta::utils::Timer::resetCounter); @@ -98,7 +98,7 @@ void Scheduler::waitSchedulerDbSubthreadsComplete() { //------------------------------------------------------------------------------ void Scheduler::authorizeAdmin(const common::dataStructures::SecurityIdentity &cliIdentity, log::LogContext & lc){ cta::utils::Timer t; - if(!(m_catalogue.isAdmin(cliIdentity))) { + if(!(m_catalogue.AdminUser()->isAdmin(cliIdentity))) { std::stringstream msg; msg << "User: " << cliIdentity.username << " on host: " << cliIdentity.host << " is not authorized to execute CTA admin commands"; throw exception::UserError(msg.str()); @@ -115,7 +115,8 @@ void Scheduler::authorizeAdmin(const common::dataStructures::SecurityIdentity &c uint64_t Scheduler::checkAndGetNextArchiveFileId(const std::string &instanceName, const std::string &storageClassName, const common::dataStructures::RequesterIdentity &user, log::LogContext &lc) { cta::utils::Timer t; - const uint64_t archiveFileId = m_catalogue.checkAndGetNextArchiveFileId(instanceName, storageClassName, user); + const uint64_t archiveFileId = m_catalogue.ArchiveFile()->checkAndGetNextArchiveFileId(instanceName, storageClassName, + user); const auto catalogueTime = t.secs(); const auto schedulerDbTime = catalogueTime; @@ -144,7 +145,7 @@ std::string Scheduler::queueArchiveWithGivenId(const uint64_t archiveFileId, con if (!request.fileSize) throw cta::exception::UserError(std::string("Rejecting archive request for zero-length file: ")+request.diskFileInfo.path); - const auto queueCriteria = m_catalogue.getArchiveFileQueueCriteria(instanceName, request.storageClass, + const auto queueCriteria = m_catalogue.ArchiveFile()->getArchiveFileQueueCriteria(instanceName, request.storageClass, request.requester); auto catalogueTime = t.secs(cta::utils::Timer::resetCounter); @@ -198,10 +199,11 @@ std::string Scheduler::queueRetrieve( // Get the queue criteria common::dataStructures::RetrieveFileQueueCriteria queueCriteria; - queueCriteria = m_catalogue.prepareToRetrieveFile(instanceName, request.archiveFileID, request.requester, request.activity, lc, request.mountPolicy); + queueCriteria = m_catalogue.TapeFile()->prepareToRetrieveFile(instanceName, request.archiveFileID, request.requester, + request.activity, lc, request.mountPolicy); queueCriteria.archiveFile.diskFileInfo = request.diskFileInfo; - auto diskSystemList = m_catalogue.getAllDiskSystems(); + auto diskSystemList = m_catalogue.DiskSystem()->getAllDiskSystems(); auto catalogueTime = t.secs(cta::utils::Timer::resetCounter); // By default, the scheduler makes its decision based on all available vids. But if a vid is specified in the protobuf, // ignore all the others. @@ -282,7 +284,7 @@ void Scheduler::deleteArchive(const std::string &instanceName, const common::dat // no need to do anything else, if file was failed it will not be in the catalogue. } tl.insertAndReset("schedulerDbTime",t); - m_catalogue.moveArchiveFileToRecycleLog(request,lc); + m_catalogue.ArchiveFile()->moveArchiveFileToRecycleLog(request,lc); tl.insertAndReset("catalogueTime",t); log::ScopedParamContainer spc(lc); tl.addToLog(spc); @@ -302,7 +304,7 @@ void Scheduler::deleteFailed(const std::string &objectId, log::LogContext & lc) void Scheduler::checkTapeCanBeRepacked(const std::string & vid, const SchedulerDatabase::QueueRepackRequest & repackRequest){ try{ - auto vidToTapesMap = m_catalogue.getTapesByVid(vid); //throws an exception if the vid is not found on the database + auto vidToTapesMap = m_catalogue.Tape()->getTapesByVid(vid); //throws an exception if the vid is not found on the database cta::common::dataStructures::Tape tapeToCheck = vidToTapesMap.at(vid); if(!tapeToCheck.full){ @@ -478,7 +480,7 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques //We need to get the ArchiveRoutes to allow the retrieval of the tapePool in which the //tape where the file is is located - std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue.getArchiveRoutes(); + std::list<common::dataStructures::ArchiveRoute> routes = m_catalogue.ArchiveRoute()->getArchiveRoutes(); timingList.insertAndReset("catalogueGetArchiveRoutesTime",t); //To identify the routes, we need to have both the dist instance name and the storage class name //thus, the key of the map is a pair of string @@ -491,7 +493,8 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques cta::SchedulerDatabase::RepackRequest::TotalStatsFiles totalStatsFile; repackRequest->m_dbReq->fillLastExpandedFSeqAndTotalStatsFile(fSeq,totalStatsFile); timingList.insertAndReset("fillTotalStatsFileBeforeExpandTime",t); - cta::catalogue::Catalogue::ArchiveFileItor archiveFilesForCatalogue = m_catalogue.getArchiveFilesForRepackItor(repackInfo.vid, fSeq); + cta::catalogue::ArchiveFileItor archiveFilesForCatalogue = m_catalogue.ArchiveFile()->getArchiveFilesForRepackItor( + repackInfo.vid, fSeq); timingList.insertAndReset("catalogueGetArchiveFilesForRepackItorTime",t); std::stringstream dirBufferURL; @@ -519,7 +522,7 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques } } - std::list<common::dataStructures::StorageClass> storageClasses = m_catalogue.getStorageClasses(); + std::list<common::dataStructures::StorageClass> storageClasses = m_catalogue.StorageClass()->getStorageClasses(); repackRequest->m_dbReq->setExpandStartedAndChangeStatus(); uint64_t nbRetrieveSubrequestsQueued = 0; @@ -677,7 +680,7 @@ void Scheduler::expandRepackRequest(std::unique_ptr<RepackRequest>& repackReques retrieveSubRequest.fileBufferURL = dirBufferURL.str() + fileName.str(); } } - auto diskSystemList = m_catalogue.getAllDiskSystems(); + auto diskSystemList = m_catalogue.DiskSystem()->getAllDiskSystems(); timingList.insertAndReset("getDisksystemsListTime",t); try{ // Note: the highest fSeq will be recorded internally in the following call. @@ -795,7 +798,7 @@ void Scheduler::RepackReportBatch::report(log::LogContext& lc) { //------------------------------------------------------------------------------ common::dataStructures::DesiredDriveState Scheduler::getDesiredDriveState(const std::string& driveName, log::LogContext & lc) { utils::Timer t; - const auto driveStates = m_catalogue.getTapeDrives(); + const auto driveStates = m_catalogue.DriveState()->getTapeDrives(); for (const auto & driveState : driveStates) { if (driveState.driveName == driveName) { const auto schedulerDbTime = t.secs(); @@ -920,7 +923,7 @@ std::map<std::string, std::list<common::dataStructures::ArchiveJob> > Scheduler: //------------------------------------------------------------------------------ std::list<common::dataStructures::ArchiveJob> Scheduler::getPendingArchiveJobs(const std::string &tapePoolName, log::LogContext & lc) const { utils::Timer t; - if(!m_catalogue.tapePoolExists(tapePoolName)) { + if(!m_catalogue.TapePool()->tapePoolExists(tapePoolName)) { throw exception::UserError(std::string("Tape pool ") + tapePoolName + " does not exist"); } auto catalogueTime = t.secs(utils::Timer::resetCounter); @@ -965,7 +968,7 @@ std::list<common::dataStructures::RetrieveJob> Scheduler::getPendingRetrieveJobs std::optional<cta::common::dataStructures::TapeDrive> Scheduler::getDriveState(const std::string& tapeDriveName, log::LogContext* lc) const { utils::Timer t; - auto ret = m_catalogue.getTapeDrive(tapeDriveName); + auto ret = m_catalogue.DriveState()->getTapeDrive(tapeDriveName); auto schedulerDbTime = t.secs(); log::ScopedParamContainer spc(*lc); spc.add("schedulerDbTime", schedulerDbTime); @@ -978,7 +981,7 @@ std::optional<cta::common::dataStructures::TapeDrive> Scheduler::getDriveState(c //------------------------------------------------------------------------------ std::list<common::dataStructures::TapeDrive> Scheduler::getDriveStates(const common::dataStructures::SecurityIdentity &cliIdentity, log::LogContext & lc) const { utils::Timer t; - const auto ret = m_catalogue.getTapeDrives(); + const auto ret = m_catalogue.DriveState()->getTapeDrives(); auto schedulerDbTime = t.secs(); log::ScopedParamContainer spc(lc); spc.add("schedulerDbTime", schedulerDbTime); @@ -999,7 +1002,7 @@ void Scheduler::sortAndGetTapesForMountInfo(std::unique_ptr<SchedulerDatabase::T // we can filter the potential mounts to the ones that this tape server can serve. catalogue::TapeSearchCriteria searchCriteria; searchCriteria.logicalLibrary = logicalLibraryName; - auto eligibleTapesList = m_catalogue.getTapes(searchCriteria); + auto eligibleTapesList = m_catalogue.Tape()->getTapes(searchCriteria); std::set<std::string> eligibleTapeSet; for(auto& t : eligibleTapesList) { eligibleTapeSet.insert(t.vid); @@ -1022,7 +1025,7 @@ void Scheduler::sortAndGetTapesForMountInfo(std::unique_ptr<SchedulerDatabase::T common::dataStructures::VidToTapeMap retrieveTapesInfo; if(!retrieveTapeSet.empty()) { - retrieveTapesInfo = m_catalogue.getTapesByVid(retrieveTapeSet); + retrieveTapesInfo = m_catalogue.Tape()->getTapesByVid(retrieveTapeSet); getTapeInfoTime = timer.secs(utils::Timer::resetCounter); for(auto& m : mountInfo->potentialMounts) { if(m.type == common::dataStructures::MountType::Retrieve) { @@ -1049,7 +1052,7 @@ void Scheduler::sortAndGetTapesForMountInfo(std::unique_ptr<SchedulerDatabase::T std::map<std::string,common::dataStructures::VirtualOrganization> tapepoolVoMap; for (auto & tapepool: tapepoolsPotentialOrExistingMounts) { try { - tapepoolVoMap[tapepool] = m_catalogue.getCachedVirtualOrganizationOfTapepool(tapepool); + tapepoolVoMap[tapepool] = m_catalogue.VO()->getCachedVirtualOrganizationOfTapepool(tapepool); } catch (cta::exception::Exception & ex){ //The VO of this tapepool does not exist, abort the scheduling as we need it to know the number of allocated drives //the VO is allowed to use @@ -1200,7 +1203,7 @@ void Scheduler::sortAndGetTapesForMountInfo(std::unique_ptr<SchedulerDatabase::T // https://trac.cppcheck.net/ticket/10739 // cppcheck-suppress internalAstError [](decltype(*mountInfo->potentialMounts.cbegin())& m){ return common::dataStructures::getMountBasicType(m.type) == common::dataStructures::MountType::ArchiveAllTypes; } )) { - tapeList = m_catalogue.getTapesForWriting(logicalLibraryName); + tapeList = m_catalogue.Tape()->getTapesForWriting(logicalLibraryName); getTapeForWriteTime = timer.secs(utils::Timer::resetCounter); } @@ -1220,7 +1223,7 @@ void Scheduler::sortAndGetTapesForMountInfo(std::unique_ptr<SchedulerDatabase::T //------------------------------------------------------------------------------ std::optional<common::dataStructures::LogicalLibrary> Scheduler::getLogicalLibrary(const std::string& libraryName, double& getLogicalLibraryTime){ utils::Timer timer; - auto logicalLibraries = m_catalogue.getLogicalLibraries(); + auto logicalLibraries = m_catalogue.LogicalLibrary()->getLogicalLibraries(); std::optional<common::dataStructures::LogicalLibrary> ret; auto logicalLibraryItor = std::find_if(logicalLibraries.begin(),logicalLibraries.end(),[libraryName](const cta::common::dataStructures::LogicalLibrary& ll){ return (ll.name == libraryName); @@ -1693,7 +1696,7 @@ std::list<common::dataStructures::QueueAndMountSummary> Scheduler::getQueuesAndM // Obtain a map of vids to tape info from the catalogue utils::Timer catalogueVidToLogicalLibraryTimer; - const auto vid_to_logical_library = m_catalogue.getVidToLogicalLibrary(tapesWithAQueue); + const auto vid_to_logical_library = m_catalogue.Tape()->getVidToLogicalLibrary(tapesWithAQueue); const auto catalogueVidToLogicalLibraryTime = catalogueVidToLogicalLibraryTimer.secs(); for (auto & pm: mountDecisionInfo->potentialMounts) { @@ -1773,11 +1776,11 @@ std::list<common::dataStructures::QueueAndMountSummary> Scheduler::getQueuesAndM for (auto & mountOrQueue: ret) { if (common::dataStructures::MountType::ArchiveForUser==mountOrQueue.mountType || common::dataStructures::MountType::ArchiveForRepack==mountOrQueue.mountType) { utils::Timer catalogueGetTapePoolTimer; - const auto tapePool = m_catalogue.getTapePool(mountOrQueue.tapePool); + const auto tapePool = m_catalogue.TapePool()->getTapePool(mountOrQueue.tapePool); catalogueGetTapePoolTotalTime += catalogueGetTapePoolTimer.secs(); if (tapePool) { utils::Timer catalogueGetVoTimer; - const auto vo = m_catalogue.getCachedVirtualOrganizationOfTapepool(tapePool->name); + const auto vo = m_catalogue.VO()->getCachedVirtualOrganizationOfTapepool(tapePool->name); catalogueGetVoTotalTime += catalogueGetVoTimer.secs(); mountOrQueue.vo = vo.name; mountOrQueue.readMaxDrives = vo.readMaxDrives; @@ -1793,14 +1796,14 @@ std::list<common::dataStructures::QueueAndMountSummary> Scheduler::getQueuesAndM cta::catalogue::TapeSearchCriteria tsc; tsc.vid = mountOrQueue.vid; utils::Timer catalogueGetTapesTimer; - auto tapes=m_catalogue.getTapes(tsc); + auto tapes=m_catalogue.Tape()->getTapes(tsc); catalogueGetTapesTotalTime += catalogueGetTapesTimer.secs(); if (tapes.size() != 1) { throw cta::exception::Exception("In Scheduler::getQueuesAndMountSummaries(): got unexpected number of tapes from catalogue for a retrieve."); } auto &t=tapes.front(); utils::Timer catalogueGetVoTimer; - const auto vo = m_catalogue.getCachedVirtualOrganizationOfTapepool(t.tapePoolName); + const auto vo = m_catalogue.VO()->getCachedVirtualOrganizationOfTapepool(t.tapePoolName); catalogueGetVoTotalTime += catalogueGetVoTimer.secs(); mountOrQueue.vo = vo.name; mountOrQueue.readMaxDrives = vo.readMaxDrives; @@ -1831,12 +1834,12 @@ void Scheduler::triggerTapeStateChange(const common::dataStructures::SecurityIde using Tape = common::dataStructures::Tape; // Tape must exist on catalogue - if (!m_catalogue.tapeExists(vid)) { + if (!m_catalogue.Tape()->tapeExists(vid)) { throw cta::exception::UserError("The VID " + vid + " does not exist"); } // Validate tape state change based on previous state - auto prev_state = m_catalogue.getTapesByVid(vid)[vid].state; + auto prev_state = m_catalogue.Tape()->getTapesByVid(vid)[vid].state; // If previous and desired states are the same, do nothing if (prev_state == new_state) return; @@ -1889,11 +1892,11 @@ void Scheduler::triggerTapeStateChange(const common::dataStructures::SecurityIde case Tape::DISABLED: case Tape::REPACKING_DISABLED: // Simply set the new tape state - m_catalogue.modifyTapeState(admin, vid, new_state, prev_state, stateReason); + m_catalogue.Tape()->modifyTapeState(admin, vid, new_state, prev_state, stateReason); break; case Tape::BROKEN: try { - m_catalogue.modifyTapeState(admin, vid, Tape::BROKEN_PENDING, prev_state, stateReason); + m_catalogue.Tape()->modifyTapeState(admin, vid, Tape::BROKEN_PENDING, prev_state, stateReason); } catch (catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive & ex) { throw catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive( std::regex_replace(ex.getMessageValue(), std::regex(Tape::stateToString(Tape::BROKEN_PENDING)), Tape::stateToString(Tape::BROKEN))); @@ -1903,10 +1906,10 @@ void Scheduler::triggerTapeStateChange(const common::dataStructures::SecurityIde case Tape::REPACKING: if (prev_state == Tape::REPACKING_DISABLED) { // If tape is on REPACKING_DISABLED state, move it directly to REPACKING - m_catalogue.modifyTapeState(admin, vid, new_state, prev_state, stateReason); + m_catalogue.Tape()->modifyTapeState(admin, vid, new_state, prev_state, stateReason); } else { try { - m_catalogue.modifyTapeState(admin, vid, Tape::REPACKING_PENDING, prev_state, stateReason); + m_catalogue.Tape()->modifyTapeState(admin, vid, Tape::REPACKING_PENDING, prev_state, stateReason); } catch (catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive & ex) { throw catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive( std::regex_replace(ex.getMessageValue(), std::regex(Tape::stateToString(Tape::REPACKING_PENDING)), Tape::stateToString(Tape::REPACKING))); @@ -1916,7 +1919,7 @@ void Scheduler::triggerTapeStateChange(const common::dataStructures::SecurityIde break; case Tape::EXPORTED: try { - m_catalogue.modifyTapeState(admin, vid, Tape::EXPORTED_PENDING, prev_state, stateReason); + m_catalogue.Tape()->modifyTapeState(admin, vid, Tape::EXPORTED_PENDING, prev_state, stateReason); } catch (catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive & ex) { throw catalogue::UserSpecifiedAnEmptyStringReasonWhenTapeStateNotActive( std::regex_replace(ex.getMessageValue(), std::regex(Tape::stateToString(Tape::EXPORTED_PENDING)), Tape::stateToString(Tape::EXPORTED))); diff --git a/scheduler/SchedulerDatabaseTest.cpp b/scheduler/SchedulerDatabaseTest.cpp index d61ddb797b..294f3a9d61 100644 --- a/scheduler/SchedulerDatabaseTest.cpp +++ b/scheduler/SchedulerDatabaseTest.cpp @@ -22,7 +22,7 @@ #include <exception> #include <future> -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "catalogue/InMemoryCatalogue.hpp" #include "common/dataStructures/SecurityIdentity.hpp" #include "common/log/DummyLogger.hpp" @@ -640,14 +640,14 @@ TEST_P(SchedulerDatabaseTest, popRetrieveRequestsWithDisksytem) { cta::SchedulerDatabase &db = getDb(); cta::catalogue::Catalogue &catalogue = getCatalogue(); - catalogue.createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); - catalogue.createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-A", "di", "constantFreeSpace:999999999999", 60, "No comment"); - catalogue.createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-A", "di", "dis-A", "$root://a.disk.system/", 10UL*1000*1000*1000, 15*60, "No comment"); + catalogue.DiskInstance()->createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-A", "di", "constantFreeSpace:999999999999", 60, "No comment"); + catalogue.DiskSystem()->createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-A", "di", "dis-A", "$root://a.disk.system/", 10UL*1000*1000*1000, 15*60, "No comment"); - catalogue.createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-B", "di", "constantFreeSpace:999999999999", 60, "No comment"); - catalogue.createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-B", "di", "dis-B", "$root://b.disk.system/", 10UL*1000*1000*1000, 15*60,"No comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-B", "di", "constantFreeSpace:999999999999", 60, "No comment"); + catalogue.DiskSystem()->createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-B", "di", "dis-B", "$root://b.disk.system/", 10UL*1000*1000*1000, 15*60,"No comment"); - auto diskSystemList = catalogue.getAllDiskSystems(); + auto diskSystemList = catalogue.DiskSystem()->getAllDiskSystems(); // Inject 10 retrieve jobs to the db. const size_t filesToDo = 10; @@ -734,11 +734,11 @@ TEST_P(SchedulerDatabaseTest, popRetrieveRequestsWithBackpressure) { // Create the disk system list // only one disk system per queue, like in the production - catalogue.createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); - catalogue.createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-A", "di", "constantFreeSpace:6000", 60, "No comment"); - catalogue.createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-A", "di", "dis-A", "$root://a.disk.system/", 0UL, 15*60, "No comment"); + catalogue.DiskInstance()->createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-A", "di", "constantFreeSpace:6000", 60, "No comment"); + catalogue.DiskSystem()->createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-A", "di", "dis-A", "$root://a.disk.system/", 0UL, 15*60, "No comment"); - auto diskSystemList = catalogue.getAllDiskSystems(); + auto diskSystemList = catalogue.DiskSystem()->getAllDiskSystems(); // Inject 10 retrieve jobs to the db. const size_t filesToDo = 10; @@ -827,13 +827,13 @@ TEST_P(SchedulerDatabaseTest, popRetrieveRequestsWithDiskSystemNotFetcheable) { cta::SchedulerDatabase &db = getDb(); cta::catalogue::Catalogue &catalogue = getCatalogue(); - catalogue.createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); - catalogue.createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-error", "di", "constantFreeSpace-6000", 60, "No comment"); + catalogue.DiskInstance()->createDiskInstance(common::dataStructures::SecurityIdentity(), "di", "No comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace(common::dataStructures::SecurityIdentity(), "dis-error", "di", "constantFreeSpace-6000", 60, "No comment"); - catalogue.createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-Error", "di", "dis-error", "$root://error.disk.system/", 0UL, + catalogue.DiskSystem()->createDiskSystem(common::dataStructures::SecurityIdentity(), "ds-Error", "di", "dis-error", "$root://error.disk.system/", 0UL, 15*60,"No comment"); - auto diskSystemList = catalogue.getAllDiskSystems(); + auto diskSystemList = catalogue.DiskSystem()->getAllDiskSystems(); // Inject 10 retrieve jobs to the db. const size_t filesToDo = 10; std::list<std::future<void>> jobInsertions; diff --git a/scheduler/SchedulerTest.cpp b/scheduler/SchedulerTest.cpp index a0d5e64ae6..013f6ed0b3 100644 --- a/scheduler/SchedulerTest.cpp +++ b/scheduler/SchedulerTest.cpp @@ -27,6 +27,7 @@ #include "catalogue/InMemoryCatalogue.hpp" #include "catalogue/MediaType.hpp" #include "catalogue/SchemaCreatingSqliteCatalogue.hpp" +#include "catalogue/TapeFileWritten.hpp" #include "catalogue/TapeItemWrittenPointer.hpp" #include "common/dataStructures/DiskInstance.hpp" #include "common/dataStructures/JobQueueType.hpp" @@ -213,13 +214,13 @@ public: mountPolicy.minRetrieveRequestAge = minRetrieveRequestAge; mountPolicy.comment = mountPolicyComment; - ASSERT_TRUE(catalogue.getMountPolicies().empty()); + ASSERT_TRUE(catalogue.MountPolicy()->getMountPolicies().empty()); - catalogue.createMountPolicy( + catalogue.MountPolicy()->createMountPolicy( s_adminOnAdminHost, mountPolicy); - const std::list<common::dataStructures::MountPolicy> groups = catalogue.getMountPolicies(); + const std::list<common::dataStructures::MountPolicy> groups = catalogue.MountPolicy()->getMountPolicies(); ASSERT_EQ(1, groups.size()); const common::dataStructures::MountPolicy group = groups.front(); ASSERT_EQ(mountPolicyName, group.name); @@ -229,12 +230,12 @@ public: ASSERT_EQ(minRetrieveRequestAge, group.retrieveMinRequestAge); ASSERT_EQ(mountPolicyComment, group.comment); - m_catalogue->createDiskInstance(s_adminOnAdminHost, s_diskInstance, "comment"); + m_catalogue->DiskInstance()->createDiskInstance(s_adminOnAdminHost, s_diskInstance, "comment"); const std::string ruleComment = "create requester mount-rule"; - catalogue.createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, s_diskInstance, s_userName, ruleComment); + catalogue.RequesterMountRule()->createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, s_diskInstance, s_userName, ruleComment); - const std::list<common::dataStructures::RequesterMountRule> rules = catalogue.getRequesterMountRules(); + const auto rules = catalogue.RequesterMountRule()->getRequesterMountRules(); ASSERT_EQ(1, rules.size()); const common::dataStructures::RequesterMountRule rule = rules.front(); @@ -253,24 +254,24 @@ public: vo.readMaxDrives = 1; vo.maxFileSize = 0; vo.diskInstanceName = s_diskInstance; - m_catalogue->createVirtualOrganization(s_adminOnAdminHost,vo); + m_catalogue->VO()->createVirtualOrganization(s_adminOnAdminHost,vo); common::dataStructures::StorageClass storageClass; storageClass.name = s_storageClassName; storageClass.nbCopies = 1; storageClass.vo.name = vo.name; storageClass.comment = "create storage class"; - m_catalogue->createStorageClass(s_adminOnAdminHost, storageClass); + m_catalogue->StorageClass()->createStorageClass(s_adminOnAdminHost, storageClass); const uint16_t nbPartialTapes = 1; const std::string tapePoolComment = "Tape-pool comment"; const bool tapePoolEncryption = false; const std::optional<std::string> tapePoolSupply("value for the supply pool mechanism"); - catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName, vo.name, nbPartialTapes, tapePoolEncryption, tapePoolSupply, - tapePoolComment); + catalogue.TapePool()->createTapePool(s_adminOnAdminHost, s_tapePoolName, vo.name, nbPartialTapes, tapePoolEncryption, + tapePoolSupply, tapePoolComment); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Archive-route comment"; - catalogue.createArchiveRoute(s_adminOnAdminHost, s_storageClassName, copyNb, s_tapePoolName, + catalogue.ArchiveRoute()->createArchiveRoute(s_adminOnAdminHost, s_storageClassName, copyNb, s_tapePoolName, archiveRouteComment); cta::catalogue::MediaType mediaType; @@ -278,14 +279,14 @@ public: mediaType.capacityInBytes = s_mediaTypeCapacityInBytes; mediaType.cartridge = "cartridge"; mediaType.comment = "comment"; - catalogue.createMediaType(s_adminOnAdminHost, mediaType); + catalogue.MediaType()->createMediaType(s_adminOnAdminHost, mediaType); const std::string driveName = "tape_drive"; const auto tapeDrive = getDefaultTapeDrive(driveName); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); const std::string driveName2 = "drive0"; const auto tapeDrive2 = getDefaultTapeDrive(driveName2); - catalogue.createTapeDrive(tapeDrive2); + catalogue.DriveState()->createTapeDrive(tapeDrive2); } cta::catalogue::CreateTapeAttributes getDefaultTape() { @@ -545,10 +546,10 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = true; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -556,11 +557,11 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); { // Emulate a tape server by asking for a mount and then a file (and succeed the transfer) @@ -572,7 +573,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file) { mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); //Test that no mount is available when a logical library is disabled ASSERT_EQ(nullptr, mount.get()); - catalogue.setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); + catalogue.LogicalLibrary()->setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); //continue our test mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); ASSERT_NE(nullptr, mount.get()); @@ -749,10 +750,10 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file_with_specific_mount_p // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = true; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -760,12 +761,12 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file_with_specific_mount_p { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, "tape_drive"); + catalogue.Tape()->tapeLabelled(s_vid, "tape_drive"); { // Emulate a tape server by asking for a mount and then a file (and succeed the transfer) @@ -777,7 +778,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file_with_specific_mount_p mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); //Test that no mount is available when a logical library is disabled ASSERT_EQ(nullptr, mount.get()); - catalogue.setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); + catalogue.LogicalLibrary()->setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); //continue our test mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); ASSERT_NE(nullptr, mount.get()); @@ -831,7 +832,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_file_with_specific_mount_p mountPolicy.minRetrieveRequestAge = s_minRetrieveRequestAge; mountPolicy.comment = "custom mount policy"; - catalogue.createMountPolicy(s_adminOnAdminHost, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(s_adminOnAdminHost, mountPolicy); } { @@ -938,13 +939,13 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { mountPolicy.minRetrieveRequestAge = minRetrieveRequestAge; mountPolicy.comment = mountPolicyComment; - ASSERT_TRUE(catalogue.getMountPolicies().empty()); + ASSERT_TRUE(catalogue.MountPolicy()->getMountPolicies().empty()); - catalogue.createMountPolicy( + catalogue.MountPolicy()->createMountPolicy( s_adminOnAdminHost, mountPolicy); - const std::list<common::dataStructures::MountPolicy> groups = catalogue.getMountPolicies(); + const std::list<common::dataStructures::MountPolicy> groups = catalogue.MountPolicy()->getMountPolicies(); ASSERT_EQ(1, groups.size()); const common::dataStructures::MountPolicy group = groups.front(); ASSERT_EQ(mountPolicyName, group.name); @@ -957,12 +958,13 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { cta::common::dataStructures::DiskInstance di; di.name = s_diskInstance; di.comment = "comment"; - catalogue.createDiskInstance(s_adminOnAdminHost, di.name, di.comment); + catalogue.DiskInstance()->createDiskInstance(s_adminOnAdminHost, di.name, di.comment); const std::string ruleComment = "create requester mount-rule"; - catalogue.createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, di.name, s_userName, ruleComment); + catalogue.RequesterMountRule()->createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, di.name, s_userName, + ruleComment); - const std::list<common::dataStructures::RequesterMountRule> rules = catalogue.getRequesterMountRules(); + const auto rules = catalogue.RequesterMountRule()->getRequesterMountRules(); ASSERT_EQ(1, rules.size()); const common::dataStructures::RequesterMountRule rule = rules.front(); @@ -981,32 +983,32 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { vo.readMaxDrives = 1; vo.maxFileSize = 0; vo.diskInstanceName = s_diskInstance; - catalogue.createVirtualOrganization(s_adminOnAdminHost,vo); + catalogue.VO()->createVirtualOrganization(s_adminOnAdminHost,vo); common::dataStructures::StorageClass storageClass; storageClass.name = dualCopyStorageClassName; storageClass.nbCopies = 2; storageClass.vo.name = vo.name; storageClass.comment = "create dual copy storage class"; - catalogue.createStorageClass(s_adminOnAdminHost, storageClass); + catalogue.StorageClass()->createStorageClass(s_adminOnAdminHost, storageClass); const uint16_t nbPartialTapes = 1; const std::string tapePool1Comment = "Tape-pool for copy number 1"; const std::string tapePool2Comment = "Tape-pool for copy number 2"; const bool tapePoolEncryption = false; const std::optional<std::string> tapePoolSupply("value for the supply pool mechanism"); - catalogue.createTapePool(s_adminOnAdminHost, tapePool1Name, vo.name, nbPartialTapes, tapePoolEncryption, + catalogue.TapePool()->createTapePool(s_adminOnAdminHost, tapePool1Name, vo.name, nbPartialTapes, tapePoolEncryption, tapePoolSupply, tapePool1Comment); - catalogue.createTapePool(s_adminOnAdminHost, tapePool2Name, vo.name, nbPartialTapes, tapePoolEncryption, + catalogue.TapePool()->createTapePool(s_adminOnAdminHost, tapePool2Name, vo.name, nbPartialTapes, tapePoolEncryption, tapePoolSupply, tapePool2Comment); const std::string archiveRoute1Comment = "Archive-route for copy number 1"; const std::string archiveRoute2Comment = "Archive-route for copy number 2"; const uint32_t archiveRoute1CopyNb = 1; const uint32_t archiveRoute2CopyNb = 2; - catalogue.createArchiveRoute(s_adminOnAdminHost, dualCopyStorageClassName, archiveRoute1CopyNb, tapePool1Name, + catalogue.ArchiveRoute()->createArchiveRoute(s_adminOnAdminHost, dualCopyStorageClassName, archiveRoute1CopyNb, tapePool1Name, archiveRoute1Comment); - catalogue.createArchiveRoute(s_adminOnAdminHost, dualCopyStorageClassName, archiveRoute2CopyNb, tapePool2Name, + catalogue.ArchiveRoute()->createArchiveRoute(s_adminOnAdminHost, dualCopyStorageClassName, archiveRoute2CopyNb, tapePool2Name, archiveRoute1Comment); cta::catalogue::MediaType mediaType; @@ -1014,14 +1016,14 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { mediaType.capacityInBytes = s_mediaTypeCapacityInBytes; mediaType.cartridge = "cartridge"; mediaType.comment = "comment"; - catalogue.createMediaType(s_adminOnAdminHost, mediaType); + catalogue.MediaType()->createMediaType(s_adminOnAdminHost, mediaType); const std::string driveName = "tape_drive"; const auto tapeDrive = getDefaultTapeDrive(driveName); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); const std::string driveName2 = "drive0"; const auto tapeDrive2 = getDefaultTapeDrive(driveName2); - catalogue.createTapeDrive(tapeDrive2); + catalogue.DriveState()->createTapeDrive(tapeDrive2); } #ifdef STDOUT_LOGGING @@ -1076,10 +1078,10 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { // tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = true; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1098,12 +1100,12 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { tape.full = false; tape.state = common::dataStructures::Tape::ACTIVE; tape.comment = "Comment"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(copy1TapeVid, driveName); + catalogue.Tape()->tapeLabelled(copy1TapeVid, driveName); // Archive copy 1 to tape { @@ -1117,7 +1119,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); //Test that no mount is available when a logical library is disabled ASSERT_EQ(nullptr, mount.get()); - catalogue.setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); + catalogue.LogicalLibrary()->setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); //continue our test mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); ASSERT_NE(nullptr, mount.get()); @@ -1159,7 +1161,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { // Create the environment for the migration of copy 2 to happen (library + // tape) - catalogue.setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,true); + catalogue.LogicalLibrary()->setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,true); const std::string copy2TapeVid = "COPY_2_TAPE"; { using namespace cta; @@ -1173,10 +1175,10 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { tape.full = false; tape.state = common::dataStructures::Tape::ACTIVE; tape.comment = "Comment"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } - catalogue.tapeLabelled(copy2TapeVid, driveName); + catalogue.Tape()->tapeLabelled(copy2TapeVid, driveName); // Archive copy 2 to tape { @@ -1189,7 +1191,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); //Test that no mount is available when a logical library is disabled ASSERT_EQ(nullptr, mount.get()); - catalogue.setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); + catalogue.LogicalLibrary()->setLogicalLibraryDisabled(s_adminOnAdminHost,s_libraryName,false); //continue our test mount.reset(scheduler.getNextMount(s_libraryName, driveName, lc).release()); ASSERT_NE(nullptr, mount.get()); @@ -1240,7 +1242,7 @@ TEST_P(SchedulerTest, archive_report_and_retrieve_new_dual_copy_file) { requester.group = "userGroup"; std::optional<std::string> activity; const common::dataStructures::RetrieveFileQueueCriteria queueCriteria = - catalogue.prepareToRetrieveFile(s_diskInstance, archiveFileId, requester, activity, lc); + catalogue.TapeFile()->prepareToRetrieveFile(s_diskInstance, archiveFileId, requester, activity, lc); ASSERT_EQ(2, queueCriteria.archiveFile.tapeFiles.size()); std::map<uint8_t, common::dataStructures::TapeFile> copyNbToTape; @@ -1399,10 +1401,10 @@ TEST_P(SchedulerTest, archive_and_retrieve_failure) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1410,12 +1412,12 @@ TEST_P(SchedulerTest, archive_and_retrieve_failure) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); { // Emulate a tape server by asking for a mount and then a file (and succeed the transfer) @@ -1649,10 +1651,10 @@ TEST_P(SchedulerTest, archive_and_retrieve_report_failure) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1660,12 +1662,12 @@ TEST_P(SchedulerTest, archive_and_retrieve_report_failure) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); { // Emulate a tape server by asking for a mount and then a file (and succeed the transfer) @@ -1893,10 +1895,10 @@ TEST_P(SchedulerTest, retry_archive_until_max_reached) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1904,11 +1906,11 @@ TEST_P(SchedulerTest, retry_archive_until_max_reached) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); { // Emulate a tape server by asking for a mount and then a file @@ -2025,7 +2027,7 @@ TEST_P(SchedulerTest, repack) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); common::dataStructures::SecurityIdentity cliId; @@ -2038,7 +2040,7 @@ TEST_P(SchedulerTest, repack) { tape.vid = tape1; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(cliId, tape); + catalogue.Tape()->createTape(cliId, tape); } //The queueing of a repack request should fail if the tape to repack is not full @@ -2049,7 +2051,7 @@ TEST_P(SchedulerTest, repack) { qrr.m_vid = "NOT_EXIST"; ASSERT_THROW(scheduler.queueRepack(cliId, qrr, lc),cta::exception::UserError); - catalogue.setTapeFull(cliId,tape1,true); + catalogue.Tape()->setTapeFull(cliId,tape1,true); // Create and then cancel repack qrr.m_vid = tape1; @@ -2066,12 +2068,12 @@ TEST_P(SchedulerTest, repack) { std::string tape2 = "TAPE2"; { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); tape.vid = tape2; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; tape.full = true; - catalogue.createTape(cliId, tape); + catalogue.Tape()->createTape(cliId, tape); } qrr.m_vid = tape2; scheduler.queueRepack(cliId, qrr, lc); @@ -2104,7 +2106,7 @@ TEST_P(SchedulerTest, getNextRepackRequestToExpand) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); common::dataStructures::SecurityIdentity cliId; @@ -2117,7 +2119,7 @@ TEST_P(SchedulerTest, getNextRepackRequestToExpand) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(cliId, tape); + catalogue.Tape()->createTape(cliId, tape); } //Queue the first repack request @@ -2133,7 +2135,7 @@ TEST_P(SchedulerTest, getNextRepackRequestToExpand) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(cliId, tape); + catalogue.Tape()->createTape(cliId, tape); } //Queue the second repack request @@ -2179,9 +2181,9 @@ TEST_P(SchedulerTest, expandRepackRequest) { auto &schedulerDB = getSchedulerDB(); setupDefaultCatalogue(); - catalogue.createDiskInstance({"user", "host"}, "diskInstance", "no comment"); - catalogue.createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "constantFreeSpace:10", 10, "no comment"); - catalogue.createDiskSystem({"user", "host"}, "diskSystem", "diskInstance", "diskInstanceSpace", "/public_dir/public_file", 10L*1000*1000*1000, 15*60, "no comment"); + catalogue.DiskInstance()->createDiskInstance({"user", "host"}, "diskInstance", "no comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "constantFreeSpace:10", 10, "no comment"); + catalogue.DiskSystem()->createDiskSystem({"user", "host"}, "diskSystem", "diskInstance", "diskInstanceSpace", "/public_dir/public_file", 10L*1000*1000*1000, 15*60, "no comment"); #ifdef STDOUT_LOGGING @@ -2202,7 +2204,7 @@ TEST_P(SchedulerTest, expandRepackRequest) { //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); uint64_t nbTapesToRepack = 10; uint64_t nbTapesForTest = 2; //corresponds to the targetAvailableRequests variable in the Scheduler::promoteRepackRequestsToToExpand() method @@ -2221,7 +2223,7 @@ TEST_P(SchedulerTest, expandRepackRequest) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -2265,7 +2267,7 @@ TEST_P(SchedulerTest, expandRepackRequest) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } } @@ -2533,7 +2535,7 @@ TEST_P(SchedulerTest, expandRepackRequestRetrieveFailed) { //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -2545,7 +2547,7 @@ TEST_P(SchedulerTest, expandRepackRequestRetrieveFailed) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -2588,7 +2590,7 @@ TEST_P(SchedulerTest, expandRepackRequestRetrieveFailed) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expandRepackRequest method @@ -2739,7 +2741,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -2751,7 +2753,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a repack destination tape @@ -2760,7 +2762,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { { auto tape = getDefaultTape(); tape.vid = vidDestination; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -2803,7 +2805,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveSuccess) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expandRepackRequest method @@ -2998,7 +3000,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3010,7 +3012,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a repack destination tape @@ -3018,7 +3020,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { { auto tape = getDefaultTape(); tape.vid = vidDestinationRepack; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -3061,7 +3063,7 @@ TEST_P(SchedulerTest, expandRepackRequestArchiveFailed) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expandRepackRequest method @@ -3262,7 +3264,7 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingTape) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3274,7 +3276,7 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingTape) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -3317,7 +3319,7 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingTape) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } // Queue the repack request for a repacking tape @@ -3369,7 +3371,8 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingDisabledTape) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, + "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3381,7 +3384,7 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingDisabledTape) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING_DISABLED; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -3424,7 +3427,7 @@ TEST_P(SchedulerTest, expandRepackRequestRepackingDisabledTape) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } // Queue the repack request for a repacking tape @@ -3476,7 +3479,7 @@ TEST_P(SchedulerTest, expandRepackRequestBrokenTape) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3488,7 +3491,7 @@ TEST_P(SchedulerTest, expandRepackRequestBrokenTape) { tape.full = true; tape.state = common::dataStructures::Tape::BROKEN; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } { @@ -3538,7 +3541,7 @@ TEST_P(SchedulerTest, expandRepackRequestDisabledTape) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3550,12 +3553,12 @@ TEST_P(SchedulerTest, expandRepackRequestDisabledTape) { tape.full = true; tape.state = common::dataStructures::Tape::DISABLED; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } { cta::SchedulerDatabase::QueueRepackRequest qrr(vid,"file://"+tempDirectory.path(),common::dataStructures::RepackInfo::Type::MoveOnly, - common::dataStructures::MountPolicy::s_defaultMountPolicyForRepack,s_defaultRepackNoRecall); + common::dataStructures::MountPolicy::s_defaultMountPolicyForRepack,s_defaultRepackNoRecall); ASSERT_THROW(scheduler.queueRepack(admin,qrr,lc),cta::exception::UserError); scheduler.waitSchedulerDbSubthreadsComplete(); @@ -3600,7 +3603,7 @@ TEST_P(SchedulerTest, expandRepackRequestActiveTape) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3612,12 +3615,12 @@ TEST_P(SchedulerTest, expandRepackRequestActiveTape) { tape.full = true; tape.state = common::dataStructures::Tape::ACTIVE; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } { cta::SchedulerDatabase::QueueRepackRequest qrr(vid,"file://"+tempDirectory.path(),common::dataStructures::RepackInfo::Type::MoveOnly, - common::dataStructures::MountPolicy::s_defaultMountPolicyForRepack,s_defaultRepackNoRecall); + common::dataStructures::MountPolicy::s_defaultMountPolicyForRepack,s_defaultRepackNoRecall); ASSERT_THROW(scheduler.queueRepack(admin,qrr,lc),cta::exception::UserError); scheduler.waitSchedulerDbSubthreadsComplete(); @@ -3631,7 +3634,8 @@ TEST_P(SchedulerTest, expandRepackRequestActiveTape) { ASSERT_EQ(nullptr,repackRequestToExpand); } } -/* Disabled tapes should be ok to be mounted, because it is a transient state + +/* TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { using namespace cta; using namespace cta::objectstore; @@ -3662,7 +3666,7 @@ TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3672,7 +3676,7 @@ TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { auto tape = getDefaultTape(); tape.vid = vid; tape.full = true; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -3715,7 +3719,7 @@ TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the queueing of the Retrieve Request and try to mount after having disabled the tape @@ -3733,20 +3737,20 @@ TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { //disabled the tape std::string disabledReason = "Disabled reason"; - catalogue.setTapeDisabled(admin,vid,disabledReason); + catalogue.Tape()->setTapeDisabled(admin,vid,disabledReason); const std::string driveName = "tape_drive"; //No mount should be returned by getNextMount ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); //enable the tape - catalogue.modifyTapeState(admin,vid,common::dataStructures::Tape::ACTIVE,std::nullopt,std::nullopt); + catalogue.Tape()->modifyTapeState(admin, vid, common::dataStructures::Tape::ACTIVE, std::nullopt, std::nullopt); //A mount should be returned by getNextMount ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName,driveName,lc)); //disable the tape - catalogue.setTapeDisabled(admin,vid,disabledReason); + catalogue.Tape()->setTapeDisabled(admin,vid,disabledReason); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName,driveName,lc)); //create repack mount policy @@ -3765,9 +3769,9 @@ TEST_P(SchedulerTest, noMountIsTriggeredWhenTapeIsDisabled) { mountPolicy.minRetrieveRequestAge = minRetrieveRequestAge; mountPolicy.comment = mountPolicyComment; - catalogue.createMountPolicy(s_adminOnAdminHost, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(s_adminOnAdminHost, mountPolicy); - auto mountPolicies = catalogue.getMountPolicies(); + auto mountPolicies = catalogue.MountPolicy()->getMountPolicies(); auto mountPolicyItor = std::find_if(mountPolicies.begin(),mountPolicies.end(), [](const common::dataStructures::MountPolicy &mountPolicy){ return mountPolicy.name.rfind("repack", 0) == 0; @@ -3834,7 +3838,7 @@ TEST_P(SchedulerTest, emptyMountIsTriggeredWhenCancelledRetrieveRequest) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -3844,7 +3848,7 @@ TEST_P(SchedulerTest, emptyMountIsTriggeredWhenCancelledRetrieveRequest) { auto tape = getDefaultTape(); tape.vid = vid; tape.full = true; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -3887,7 +3891,7 @@ TEST_P(SchedulerTest, emptyMountIsTriggeredWhenCancelledRetrieveRequest) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the queueing of the Retrieve Request and try to mount after having disabled the tape @@ -3906,7 +3910,7 @@ TEST_P(SchedulerTest, emptyMountIsTriggeredWhenCancelledRetrieveRequest) { } //disabled the tape std::string disabledReason = "reason"; - catalogue.setTapeDisabled(admin,vid,disabledReason); + catalogue.Tape()->setTapeDisabled(admin,vid,disabledReason); //No mount should be returned by getNextMount ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); @@ -4004,10 +4008,10 @@ TEST_P(SchedulerTest, DISABLED_archiveReportMultipleAndQueueRetrievesWithActivit // Create the environment for the migrations to happen (library + tapes) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -4017,8 +4021,8 @@ TEST_P(SchedulerTest, DISABLED_archiveReportMultipleAndQueueRetrievesWithActivit auto tape = getDefaultTape(); std::string vid = s_vid + std::to_string(i); tape.vid = vid; - catalogue.createTape(s_adminOnAdminHost, tape); - catalogue.tapeLabelled(vid, driveName); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->tapeLabelled(vid, driveName); } @@ -4190,7 +4194,7 @@ TEST_P(SchedulerTest, expandRepackRequestAddCopiesOnly) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); //Create the source tape std::string vid = "VIDSOURCE"; @@ -4200,27 +4204,27 @@ TEST_P(SchedulerTest, expandRepackRequestAddCopiesOnly) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create two different destination tapepool std::string tapepool2Name = "tapepool2"; const std::optional<std::string> supply; - catalogue.createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); + catalogue.TapePool()->createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); std::string tapepool3Name = "tapepool3"; - catalogue.createTapePool(admin,tapepool3Name,"vo",1,false,supply,"comment"); + catalogue.TapePool()->createTapePool(admin,tapepool3Name,"vo",1,false,supply,"comment"); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; storageClass.name = s_storageClassName; storageClass.nbCopies = 3; storageClass.comment = "Create storage class"; - catalogue.modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); + catalogue.StorageClass()->modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); //Create the two archive routes for the new copies - catalogue.createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute2"); - catalogue.createArchiveRoute(admin,storageClass.name,3,tapepool3Name,"ArchiveRoute3"); + catalogue.ArchiveRoute()->createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute2"); + catalogue.ArchiveRoute()->createArchiveRoute(admin,storageClass.name,3,tapepool3Name,"ArchiveRoute3"); //Create two other destinationTape std::string vidDestination1 = "VIDDESTINATION1"; @@ -4228,7 +4232,7 @@ TEST_P(SchedulerTest, expandRepackRequestAddCopiesOnly) { auto tape = getDefaultTape(); tape.vid = vidDestination1; tape.tapePoolName = tapepool2Name; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } std::string vidDestination2 = "VIDDESTINATION2"; @@ -4236,7 +4240,7 @@ TEST_P(SchedulerTest, expandRepackRequestAddCopiesOnly) { auto tape = getDefaultTape(); tape.vid = vidDestination2; tape.tapePoolName = tapepool3Name; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string tapeDrive = "tape_drive"; @@ -4273,7 +4277,7 @@ TEST_P(SchedulerTest, expandRepackRequestAddCopiesOnly) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expanding requeue the Repack after the creation of @@ -4442,7 +4446,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); //Create the source tape std::string vidCopyNb1 = "VIDSOURCE"; @@ -4452,23 +4456,23 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create two different destination tapepool std::string tapepool2Name = "tapepool2"; const std::optional<std::string> supply; - catalogue.createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); + catalogue.TapePool()->createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; storageClass.name = s_storageClassName; storageClass.nbCopies = 2; storageClass.comment = "Create storage class"; - catalogue.modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); + catalogue.StorageClass()->modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); //Create the one archive route for the second copy - catalogue.createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute3"); + catalogue.ArchiveRoute()->createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute3"); //Create two other destinationTape std::string vidCopyNb2_source = "VIDCOPYNB2_SOURCE"; @@ -4478,7 +4482,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { tape.tapePoolName = tapepool2Name; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } std::string vidCopyNb2_destination = "VIDCOPYNB2_DESTINATION"; @@ -4486,7 +4490,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { auto tape = getDefaultTape(); tape.vid = vidCopyNb2_destination; tape.tapePoolName = tapepool2Name; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string tapeDrive = "tape_drive"; @@ -4523,7 +4527,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { tapeFilesWrittenCopy.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy); tapeFilesWrittenCopy.clear(); } //Archive the second copy of the files in the tape located in the tapepool2 @@ -4555,12 +4559,12 @@ TEST_P(SchedulerTest, expandRepackRequestShouldFailIfArchiveRouteMissing) { tapeFilesWrittenCopy.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy); tapeFilesWrittenCopy.clear(); } - catalogue.setTapeFull(admin,vidCopyNb2_source,true); + catalogue.Tape()->setTapeFull(admin,vidCopyNb2_source,true); //Delete the archive route of the second copy and repack the tape that contains these second copies - catalogue.deleteArchiveRoute(storageClass.name,2); + catalogue.ArchiveRoute()->deleteArchiveRoute(storageClass.name,2); { std::string vid = vidCopyNb2_source; cta::SchedulerDatabase::QueueRepackRequest qrr(vid,"file://"+tempDirectory.path(),common::dataStructures::RepackInfo::Type::MoveAndAddCopies, @@ -4624,7 +4628,7 @@ TEST_P(SchedulerTest, expandRepackRequestMoveAndAddCopies){ //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); //Create the source tape std::string vid = "VIDSOURCE"; @@ -4634,27 +4638,27 @@ TEST_P(SchedulerTest, expandRepackRequestMoveAndAddCopies){ tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create two different destination tapepool std::string tapepool2Name = "tapepool2"; const std::optional<std::string> supply; - catalogue.createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); + catalogue.TapePool()->createTapePool(admin,tapepool2Name,"vo",1,false,supply,"comment"); std::string tapepool3Name = "tapepool3"; - catalogue.createTapePool(admin,tapepool3Name,"vo",1,false,supply,"comment"); + catalogue.TapePool()->createTapePool(admin,tapepool3Name,"vo",1,false,supply,"comment"); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; storageClass.name = s_storageClassName; storageClass.nbCopies = 3; storageClass.comment = "Create storage class"; - catalogue.modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); + catalogue.StorageClass()->modifyStorageClassNbCopies(admin,storageClass.name,storageClass.nbCopies); //Create the two archive routes for the new copies - catalogue.createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute2"); - catalogue.createArchiveRoute(admin,storageClass.name,3,tapepool3Name,"ArchiveRoute3"); + catalogue.ArchiveRoute()->createArchiveRoute(admin,storageClass.name,2,tapepool2Name,"ArchiveRoute2"); + catalogue.ArchiveRoute()->createArchiveRoute(admin,storageClass.name,3,tapepool3Name,"ArchiveRoute3"); //Create two other destinationTape and one for the move workflow std::string vidDestination1 = "VIDDESTINATION1"; @@ -4662,7 +4666,7 @@ TEST_P(SchedulerTest, expandRepackRequestMoveAndAddCopies){ auto tape = getDefaultTape(); tape.vid = vidDestination1; tape.tapePoolName = tapepool2Name; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } std::string vidDestination2 = "VIDDESTINATION2"; @@ -4671,14 +4675,14 @@ TEST_P(SchedulerTest, expandRepackRequestMoveAndAddCopies){ tape.vid = vidDestination2; tape.tapePoolName = tapepool3Name; tape.full = false; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } std::string vidMove = "VIDMOVE"; { auto tape = getDefaultTape(); tape.vid = vidMove; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string tapeDrive = "tape_drive"; @@ -4715,7 +4719,7 @@ TEST_P(SchedulerTest, expandRepackRequestMoveAndAddCopies){ tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expanding requeue the Repack after the creation of @@ -4904,7 +4908,7 @@ TEST_P(SchedulerTest, cancelRepackRequest) { //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); std::ostringstream ossVid; ossVid << s_vid << "_" << 1; @@ -4915,14 +4919,14 @@ TEST_P(SchedulerTest, cancelRepackRequest) { tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a repack destination tape std::string vidDestination = "VIDDESTINATION"; { auto tape = getDefaultTape(); tape.vid = vidDestination; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -4965,7 +4969,7 @@ TEST_P(SchedulerTest, cancelRepackRequest) { tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the expandRepackRequest method @@ -5143,15 +5147,15 @@ TEST_P(SchedulerTest, getNextMountEmptyArchiveForRepackIfNbFilesQueuedIsLessThan //Create environment for the test const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,10000); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,10000); Sorter sorter(agentReference,backend,catalogue); for(uint64_t i = 0; i < s_minFilesToWarrantAMount; ++i) { @@ -5247,17 +5251,17 @@ TEST_P(SchedulerTest, getNextMountTapeStatesThatShouldNotReturnAMount) { // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); auto tape = getDefaultTape(); { - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); { // This first initialization is normally done by the dataSession function. @@ -5294,24 +5298,24 @@ TEST_P(SchedulerTest, getNextMountTapeStatesThatShouldNotReturnAMount) { scheduler.waitSchedulerDbSubthreadsComplete(); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::BROKEN,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::BROKEN,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::BROKEN,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::BROKEN,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::EXPORTED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::EXPORTED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::EXPORTED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::EXPORTED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::DISABLED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::DISABLED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::DISABLED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::DISABLED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); { @@ -5360,24 +5364,24 @@ TEST_P(SchedulerTest, getNextMountTapeStatesThatShouldNotReturnAMount) { scheduler.queueRetrieve(s_diskInstance, request, lc); scheduler.waitSchedulerDbSubthreadsComplete(); } - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::BROKEN,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::BROKEN,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::BROKEN,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::BROKEN,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::EXPORTED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::EXPORTED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::EXPORTED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::EXPORTED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::REPACKING_DISABLED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::DISABLED,std::nullopt,std::string("Test")); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::DISABLED,std::nullopt,std::string("Test")); ASSERT_EQ(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); - catalogue.modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::DISABLED,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost,tape.vid,common::dataStructures::Tape::ACTIVE,common::dataStructures::Tape::DISABLED,std::nullopt); ASSERT_NE(nullptr,scheduler.getNextMount(s_libraryName, driveName, lc)); } @@ -5392,9 +5396,9 @@ TEST_P(SchedulerTest, repackRetrieveRequestsFailToFetchDiskSystem){ //cta::objectstore::Backend& backend = schedulerDB.getBackend(); setupDefaultCatalogue(); - catalogue.createDiskInstance({"user", "host"}, "diskInstance", "no comment"); - catalogue.createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); - catalogue.createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace", tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); + catalogue.DiskInstance()->createDiskInstance({"user", "host"}, "diskInstance", "no comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); + catalogue.DiskSystem()->createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace", tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); #ifdef STDOUT_LOGGING log::StdoutLogger dl("dummy", "unitTest"); @@ -5413,14 +5417,14 @@ TEST_P(SchedulerTest, repackRetrieveRequestsFailToFetchDiskSystem){ //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); { auto tape = getDefaultTape(); tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -5462,7 +5466,7 @@ TEST_P(SchedulerTest, repackRetrieveRequestsFailToFetchDiskSystem){ tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } @@ -5497,11 +5501,11 @@ TEST_P(SchedulerTest, repackRetrieveRequestsFailToFetchDiskSystem){ reservationRequest.addRequest(job->diskSystemName().value(), job->archiveFile.fileSize); } ASSERT_EQ(10,jobBatch.size()); - auto diskSpaceReservedBefore = catalogue.getTapeDrive(driveName).value().reservedBytes; + auto diskSpaceReservedBefore = catalogue.DriveState()->getTapeDrive(driveName).value().reservedBytes; //Trying to reserve disk space should result in 10 jobs should fail ASSERT_FALSE(retrieveMount->reserveDiskSpace(reservationRequest, lc)); //No extra disk space was reserved - auto diskSpaceReservedAfter = catalogue.getTapeDrive(driveName).value().reservedBytes; + auto diskSpaceReservedAfter = catalogue.DriveState()->getTapeDrive(driveName).value().reservedBytes; ASSERT_EQ(diskSpaceReservedAfter, diskSpaceReservedBefore); } /* @@ -5541,9 +5545,9 @@ TEST_P(SchedulerTest, expandRepackRequestShouldThrowIfUseBufferNotRecallButNoDir auto &scheduler = getScheduler(); setupDefaultCatalogue(); - catalogue.createDiskInstance({"user", "host"}, "diskInstance", "no comment"); - catalogue.createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); - catalogue.createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace", tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); + catalogue.DiskInstance()->createDiskInstance({"user", "host"}, "diskInstance", "no comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); + catalogue.DiskSystem()->createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace", tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); #ifdef STDOUT_LOGGING log::StdoutLogger dl("dummy", "unitTest"); @@ -5562,14 +5566,14 @@ TEST_P(SchedulerTest, expandRepackRequestShouldThrowIfUseBufferNotRecallButNoDir //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); { auto tape = getDefaultTape(); tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -5611,7 +5615,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldThrowIfUseBufferNotRecallButNoDir tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } @@ -5640,9 +5644,9 @@ TEST_P(SchedulerTest, expandRepackRequestShouldNotThrowIfTapeDisabledButNoRecall auto &scheduler = getScheduler(); setupDefaultCatalogue(); - catalogue.createDiskInstance({"user", "host"}, "diskInstance", "no comment"); - catalogue.createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); - catalogue.createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace",tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); + catalogue.DiskInstance()->createDiskInstance({"user", "host"}, "diskInstance", "no comment"); + catalogue.DiskInstanceSpace()->createDiskInstanceSpace({"user", "host"}, "diskInstanceSpace", "diskInstance", "eos:ctaeos:default", 10, "no comment"); + catalogue.DiskSystem()->createDiskSystem({"user", "host"}, "repackBuffer", "diskInstance", "diskInstanceSpace",tempDirectory.path(), 10L*1000*1000*1000, 15*60, "no comment"); #ifdef STDOUT_LOGGING log::StdoutLogger dl("dummy", "unitTest"); @@ -5661,14 +5665,14 @@ TEST_P(SchedulerTest, expandRepackRequestShouldNotThrowIfTapeDisabledButNoRecall //Create a logical library in the catalogue const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(admin, s_libraryName, libraryIsDisabled, "Create logical library"); { auto tape = getDefaultTape(); tape.full = true; tape.state = common::dataStructures::Tape::REPACKING; tape.stateReason = "Test"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } //Create a storage class in the catalogue @@ -5710,7 +5714,7 @@ TEST_P(SchedulerTest, expandRepackRequestShouldNotThrowIfTapeDisabledButNoRecall tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } @@ -5763,21 +5767,21 @@ TEST_P(SchedulerTest, archiveMaxDrivesVoInFlightChangeScheduleMount){ // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); } auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); const std::string driveName = "tape_drive"; - catalogue.tapeLabelled(s_vid, driveName); + catalogue.Tape()->tapeLabelled(s_vid, driveName); log::DummyLogger dl("", ""); @@ -5787,7 +5791,7 @@ TEST_P(SchedulerTest, archiveMaxDrivesVoInFlightChangeScheduleMount){ scheduler.queueArchiveWithGivenId(archiveFileId, s_diskInstance, request, lc); scheduler.waitSchedulerDbSubthreadsComplete(); - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,0); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,0); { // Emulate a tape server @@ -5799,7 +5803,7 @@ TEST_P(SchedulerTest, archiveMaxDrivesVoInFlightChangeScheduleMount){ bool nextMount = scheduler.getNextMountDryRun(s_libraryName, driveName, lc); //nextMount should be false as the VO write max drives is 0 ASSERT_FALSE(nextMount); - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); //Reset the VO write max drives to a positive number should give a new mount nextMount = scheduler.getNextMountDryRun(s_libraryName,driveName,lc); ASSERT_TRUE(nextMount); @@ -5833,10 +5837,10 @@ TEST_P(SchedulerTest, retrieveMaxDrivesVoInFlightChangeScheduleMount) //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; @@ -5878,7 +5882,7 @@ TEST_P(SchedulerTest, retrieveMaxDrivesVoInFlightChangeScheduleMount) tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Test the queueing of the Retrieve Request and try to mount after having changed the readMaxDrives of the VO @@ -5896,11 +5900,11 @@ TEST_P(SchedulerTest, retrieveMaxDrivesVoInFlightChangeScheduleMount) ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,"drive",lc)); - catalogue.modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,0); + catalogue.VO()->modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,0); ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,"drive",lc)); - catalogue.modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,1); + catalogue.VO()->modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,1); ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,"drive",lc)); } @@ -5936,43 +5940,43 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo std::string drive1 = "drive1"; { const auto tapeDrive = getDefaultTapeDrive(drive1); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } std::string drive2 = "drive2"; { const auto tapeDrive = getDefaultTapeDrive(drive2); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } std::string drive3 = "drive3"; { const auto tapeDrive = getDefaultTapeDrive(drive3); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); //This tape will contain files for triggering a Retrieve auto tape1 = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape1); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape1); //Two tapes for ArchiveForUser and ArchiveForRepack mounts std::string vid2 = "VID_2"; auto tape2 = tape1; tape2.vid = vid2; - catalogue.createTape(s_adminOnAdminHost, tape2); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape2); //Create a new tapepool on the same VO std::string newTapepool = "new_tapepool"; - catalogue.createTapePool(s_adminOnAdminHost,newTapepool,s_vo,1,false,std::nullopt,"Test"); + catalogue.TapePool()->createTapePool(s_adminOnAdminHost,newTapepool,s_vo,1,false,std::nullopt,"Test"); //Create the third tape in the new tapepool std::string vid3 = "VID_3"; auto tape3 = tape1; tape3.vid = vid3; tape3.tapePoolName = newTapepool; - catalogue.createTape(s_adminOnAdminHost,tape3); + catalogue.Tape()->createTape(s_adminOnAdminHost,tape3); //Create a storage class in the catalogue common::dataStructures::StorageClass storageClass; @@ -5980,10 +5984,10 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo storageClass.nbCopies = 2; storageClass.comment = "Create storage class"; - catalogue.modifyStorageClassNbCopies(s_adminOnAdminHost,storageClass.name,storageClass.nbCopies); + catalogue.StorageClass()->modifyStorageClassNbCopies(s_adminOnAdminHost,storageClass.name,storageClass.nbCopies); //Create the new archive routes for the second copy - catalogue.createArchiveRoute(s_adminOnAdminHost,storageClass.name,2,newTapepool,"ArchiveRoute2"); + catalogue.ArchiveRoute()->createArchiveRoute(s_adminOnAdminHost,storageClass.name,2,newTapepool,"ArchiveRoute2"); const std::string tapeDrive = "tape_drive"; const uint64_t nbArchiveFilesPerTape = 10; @@ -6019,7 +6023,7 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo tapeFilesWrittenCopy1.emplace(fileWrittenUP.release()); } //update the DB tape - catalogue.filesWrittenToTape(tapeFilesWrittenCopy1); + catalogue.TapeFile()->filesWrittenToTape(tapeFilesWrittenCopy1); tapeFilesWrittenCopy1.clear(); } //Queue the Retrieve request @@ -6068,8 +6072,8 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo sorter.flushAll(lc); - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); - catalogue.modifyMountPolicyRetrieveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); + catalogue.MountPolicy()->modifyMountPolicyRetrieveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); //Wait 2 second to be sure the minRequestAge will not prevent a mount ::sleep(1); @@ -6077,16 +6081,16 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,drive1,lc)); //No read nor write allowed - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,0); - catalogue.modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,0); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,0); + catalogue.VO()->modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,0); ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive1,lc)); //Allow one drive for write and trigger the mount - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); //Set the tape 1 to disabled state to prevent the mount in it (should be the Retrieve) - catalogue.setTapeDisabled(s_adminOnAdminHost,tape1.vid,"test"); + catalogue.Tape()->setTapeDisabled(s_adminOnAdminHost,tape1.vid,"test"); ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,drive1,lc)); { std::unique_ptr<cta::TapeMount> tapeMount = scheduler.getNextMount(s_libraryName,drive1,lc); @@ -6109,7 +6113,7 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive2,lc)); //Now allocate one more drive for Archival - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,2); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,2); //A new Archive mount should be triggered ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,drive2,lc)); @@ -6133,11 +6137,12 @@ TEST_P(SchedulerTest, retrieveArchiveAllTypesMaxDrivesVoInFlightChangeScheduleMo //As 2 drives are writing and only 2 drives are allowed on this VO, the third drive should not trigger a new mount ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive3,lc)); //Now allocate one drive for Retrieve - catalogue.modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,1); - //The retrieve mount should not be triggered as the tape 1 state is broken + catalogue.VO()->modifyVirtualOrganizationReadMaxDrives(s_adminOnAdminHost,s_vo,1); + //The retrieve mount should not be triggered as the tape 1 is disabled ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive3,lc)); //Setting the state of the tape back to active - catalogue.modifyTapeState(s_adminOnAdminHost,tape1.vid,common::dataStructures::Tape::ACTIVE,std::nullopt,std::nullopt); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost, tape1.vid, common::dataStructures::Tape::ACTIVE, std::nullopt, + std::nullopt); //The mount should be triggered on tape 1 ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,drive3,lc)); //The mount should be a Retrieve mount @@ -6187,15 +6192,15 @@ TEST_P(SchedulerTest, getQueuesAndMountSummariesTest) //Create a logical library in the catalogue const bool logicalLibraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, logicalLibraryIsDisabled, "Create logical library"); //Create two tapes auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); std::string vid2 = s_vid + "2"; tape.vid = vid2; - catalogue.createTape(s_adminOnAdminHost,tape); + catalogue.Tape()->createTape(s_adminOnAdminHost,tape); //Create a RetrieveQueue with the vid s_vid std::string retrieveQueueAddress; @@ -6343,33 +6348,33 @@ TEST_P(SchedulerTest, getNextMountWithArchiveForUserAndArchiveForRepackShouldRet //Create environment for the test const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); std::string drive0 = "drive0"; std::string drive1 = "drive1"; { const auto tapeDrive = getDefaultTapeDrive(drive1); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } std::string drive2 = "drive2"; { const auto tapeDrive = getDefaultTapeDrive(drive2); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } //Create two tapes (ArchiveForRepack and ArchiveForUser) { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } { auto tape = getDefaultTape(); tape.vid = s_vid+"_1"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } uint64_t fileSize = 667; @@ -6405,13 +6410,13 @@ TEST_P(SchedulerTest, getNextMountWithArchiveForUserAndArchiveForRepackShouldRet ar->insert(); } - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,100); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,100); sorter.flushAll(lc); ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive0,lc)); - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); //The archiveMinRequestAge should have 1 second to trigger a mount ::sleep(1); @@ -6467,23 +6472,23 @@ TEST_P(SchedulerTest, getNextMountWithArchiveForUserAndArchiveForRepackShouldRet sorter.flushAll(lc); - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,100); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,100); //mount should not be triggered ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive0,lc)); - catalogue.modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); + catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(s_adminOnAdminHost,s_mountPolicyName,0); //Sleeping one seconds to trigger a mount ::sleep(1); - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,1); //Test the per VO writeMaxDrives: no mount should be triggered as only one drive for write //has been configured for this VO ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive1,lc)); //Adding a second drive for write for this VO - catalogue.modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,2); + catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(s_adminOnAdminHost,s_vo,2); //The next mount should be an ArchiveForUser mount as there is already a mount ongoing with an ArchiveForRepack ASSERT_TRUE(scheduler.getNextMountDryRun(s_libraryName,drive1,lc)); @@ -6509,7 +6514,7 @@ TEST_P(SchedulerTest, getNextMountWithArchiveForUserAndArchiveForRepackShouldRet { auto tape = getDefaultTape(); tape.vid = s_vid+"_2"; - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } ASSERT_FALSE(scheduler.getNextMountDryRun(s_libraryName,drive2,lc)); } @@ -6540,17 +6545,17 @@ TEST_P(SchedulerTestTriggerTapeStateChangeBehaviour, triggerTapeStateChangeValid // Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); auto tape = getDefaultTape(); { - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Setup initial conditions schedulerDB.setRetrieveQueueCleanupFlag(tape.vid, false, lc); - catalogue.modifyTapeState(s_adminOnAdminHost, tape.vid,triggerTapeStateChangeBehaviour.fromState,std::nullopt,"Test"); + catalogue.Tape()->modifyTapeState(s_adminOnAdminHost, tape.vid,triggerTapeStateChangeBehaviour.fromState,std::nullopt,"Test"); // Trigger change if (triggerTapeStateChangeBehaviour.changeRaisedException) { @@ -6560,7 +6565,7 @@ TEST_P(SchedulerTestTriggerTapeStateChangeBehaviour, triggerTapeStateChangeValid } // Observe results - ASSERT_EQ(catalogue.getTapesByVid(tape.vid).at(tape.vid).state, triggerTapeStateChangeBehaviour.observedState); + ASSERT_EQ(catalogue.Tape()->getTapesByVid(tape.vid).at(tape.vid).state, triggerTapeStateChangeBehaviour.observedState); ASSERT_EQ(schedulerDB.getRetrieveQueuesCleanupInfo(lc).front().doCleanup, triggerTapeStateChangeBehaviour.cleanupFlagActivated); } diff --git a/scheduler/testingMocks/MockArchiveJob.hpp b/scheduler/testingMocks/MockArchiveJob.hpp index 78179047c0..0479fc95e0 100644 --- a/scheduler/testingMocks/MockArchiveJob.hpp +++ b/scheduler/testingMocks/MockArchiveJob.hpp @@ -17,10 +17,12 @@ #pragma once -#include "scheduler/RetrieveMount.hpp" -#include "scheduler/RetrieveJob.hpp" #include <memory> +#include "catalogue/TapeFileWritten.hpp" +#include "scheduler/RetrieveJob.hpp" +#include "scheduler/RetrieveMount.hpp" + namespace cta { class MockArchiveJob: public cta::ArchiveJob { public: diff --git a/scheduler/testingMocks/MockArchiveMount.hpp b/scheduler/testingMocks/MockArchiveMount.hpp index dc475c08b7..9e68032a07 100644 --- a/scheduler/testingMocks/MockArchiveMount.hpp +++ b/scheduler/testingMocks/MockArchiveMount.hpp @@ -67,7 +67,7 @@ public: skippedFiles.pop(); tapeItemsWritten.emplace(tiwup.release()); } - m_catalogue.filesWrittenToTape(tapeItemsWritten); + m_catalogue.TapeFile()->filesWrittenToTape(tapeItemsWritten); catalogue_updated = true; for (auto &job : validatedSuccessfulArchiveJobs) { auto *maj = dynamic_cast<MockArchiveJob *>(job.get()); diff --git a/tapeserver/castor/tape/tapeserver/RAO/FilePositionEstimatorFactory.cpp b/tapeserver/castor/tape/tapeserver/RAO/FilePositionEstimatorFactory.cpp index 39c203515d..bdd91b7148 100644 --- a/tapeserver/castor/tape/tapeserver/RAO/FilePositionEstimatorFactory.cpp +++ b/tapeserver/castor/tape/tapeserver/RAO/FilePositionEstimatorFactory.cpp @@ -26,7 +26,7 @@ namespace castor { namespace tape { namespace tapeserver { namespace rao { std::unique_ptr<FilePositionEstimator> FilePositionEstimatorFactory::createInterpolationFilePositionEstimator(const std::string & vid, cta::catalogue::Catalogue *catalogue, drive::DriveInterface *drive, cta::log::TimingList &tl){ std::unique_ptr<FilePositionEstimator> ret; cta::utils::Timer t; - cta::catalogue::MediaType tapeMediaType = catalogue->getMediaTypeByVid(vid); + cta::catalogue::MediaType tapeMediaType = catalogue->MediaType()->getMediaTypeByVid(vid); tl.insertAndReset("catalogueGetMediaTypeByVidTime",t); std::vector<drive::endOfWrapPosition> endOfWrapPositions = drive->getEndOfWrapPositions(); tl.insertAndReset("getEndOfWrapPositionsTime",t); diff --git a/tapeserver/castor/tape/tapeserver/daemon/CleanerSession.cpp b/tapeserver/castor/tape/tapeserver/daemon/CleanerSession.cpp index 1f2d09585f..34f2b9146d 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/CleanerSession.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/CleanerSession.cpp @@ -159,11 +159,11 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction try { std::string disabledReason = cta::utils::getCurrentLocalTime("%F %T") + ":" + currentExceptionMsg; - auto curr_state = m_catalogue.getTapesByVid(m_vid).at(m_vid).state; + auto curr_state = m_catalogue.Tape()->getTapesByVid(m_vid).at(m_vid).state; if (curr_state == cta::common::dataStructures::Tape::REPACKING) { - m_catalogue.setTapeRepackingDisabled(admin, m_vid, disabledReason); + m_catalogue.Tape()->setTapeRepackingDisabled(admin, m_vid, disabledReason); } else { - m_catalogue.setTapeDisabled(admin, m_vid, disabledReason); + m_catalogue.Tape()->setTapeDisabled(admin, m_vid, disabledReason); } } catch(cta::exception::Exception &ex) { cta::log::Param param("exceptionMsg", ex.getMessageValue()); @@ -340,7 +340,7 @@ std::string castor::tape::tapeserver::daemon::CleanerSession::checkVolumeLabel( params.push_back(cta::log::Param("tapeDrive", m_driveConfig.unitName)); using LabelFormat = cta::common::dataStructures::Label::Format; - const LabelFormat labelFormat = m_catalogue.getTapeLabelFormat(m_vid); + const LabelFormat labelFormat = m_catalogue.Tape()->getTapeLabelFormat(m_vid); const std::string volumeLabelVSN = tapeFile::HeaderChecker::checkVolumeLabel(drive, labelFormat); diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp index c7ba5d3e4d..017cd5a4da 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp @@ -45,7 +45,7 @@ #include "catalogue/CreateTapeAttributes.hpp" #include "catalogue/InMemoryCatalogue.hpp" #include "catalogue/MediaType.hpp" -#include "catalogue/OracleCatalogue.hpp" +#include "catalogue/rdbms/oracle/OracleCatalogue.hpp" #include "catalogue/OracleCatalogueSchema.hpp" #include "catalogue/TapeItemWrittenPointer.hpp" #include "common/dataStructures/DiskInstance.hpp" @@ -333,13 +333,13 @@ public: const uint64_t minRetrieveRequestAge = mountPolicy.minRetrieveRequestAge; const std::string mountPolicyComment = "create mount group"; - ASSERT_TRUE(catalogue.getMountPolicies().empty()); + ASSERT_TRUE(catalogue.MountPolicy()->getMountPolicies().empty()); - catalogue.createMountPolicy( + catalogue.MountPolicy()->createMountPolicy( s_adminOnAdminHost, mountPolicy); - const std::list<common::dataStructures::MountPolicy> groups = catalogue.getMountPolicies(); + const std::list<common::dataStructures::MountPolicy> groups = catalogue.MountPolicy()->getMountPolicies(); ASSERT_EQ(1, groups.size()); const common::dataStructures::MountPolicy group = groups.front(); ASSERT_EQ(mountPolicyName, group.name); @@ -350,12 +350,12 @@ public: ASSERT_EQ(mountPolicyComment, group.comment); const auto di = getDefaultDiskInstance(); - catalogue.createDiskInstance(s_adminOnAdminHost, di.name, di.comment); + catalogue.DiskInstance()->createDiskInstance(s_adminOnAdminHost, di.name, di.comment); const std::string ruleComment = "create requester mount-rule"; - catalogue.createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, di.name, s_userName, ruleComment); + catalogue.RequesterMountRule()->createRequesterMountRule(s_adminOnAdminHost, mountPolicyName, di.name, s_userName, ruleComment); - const std::list<common::dataStructures::RequesterMountRule> rules = catalogue.getRequesterMountRules(); + const std::list<common::dataStructures::RequesterMountRule> rules = catalogue.RequesterMountRule()->getRequesterMountRules(); ASSERT_EQ(1, rules.size()); const common::dataStructures::RequesterMountRule rule = rules.front(); @@ -367,28 +367,27 @@ public: ASSERT_EQ(s_adminOnAdminHost.host, rule.creationLog.host); ASSERT_EQ(rule.creationLog, rule.lastModificationLog); - cta::common::dataStructures::VirtualOrganization vo = getDefaultVirtualOrganization(); - catalogue.createVirtualOrganization(s_adminOnAdminHost, vo); + catalogue.VO()->createVirtualOrganization(s_adminOnAdminHost, vo); common::dataStructures::StorageClass storageClass; storageClass.name = s_storageClassName; storageClass.nbCopies = 1; storageClass.vo.name = vo.name; storageClass.comment = "create storage class"; - m_catalogue->createStorageClass(s_adminOnAdminHost, storageClass); + m_catalogue->StorageClass()->createStorageClass(s_adminOnAdminHost, storageClass); const uint16_t nbPartialTapes = 1; const std::string tapePoolComment = "Tape-pool comment"; const bool tapePoolEncryption = false; const std::optional<std::string> tapePoolSupply("value for the supply pool mechanism"); - ASSERT_NO_THROW(catalogue.createTapePool(s_adminOnAdminHost, s_tapePoolName, vo.name, nbPartialTapes, tapePoolEncryption, - tapePoolSupply, tapePoolComment)); + ASSERT_NO_THROW(catalogue.TapePool()->createTapePool(s_adminOnAdminHost, s_tapePoolName, vo.name, nbPartialTapes, + tapePoolEncryption, tapePoolSupply, tapePoolComment)); const uint32_t copyNb = 1; const std::string archiveRouteComment = "Archive-route comment"; - catalogue.createArchiveRoute(s_adminOnAdminHost, s_storageClassName, copyNb, s_tapePoolName, - archiveRouteComment); + catalogue.ArchiveRoute()->createArchiveRoute(s_adminOnAdminHost, s_storageClassName, copyNb, s_tapePoolName, + archiveRouteComment); cta::catalogue::MediaType mediaType; mediaType.name = s_mediaType; @@ -398,11 +397,11 @@ public: mediaType.maxLPos = 171097; mediaType.nbWraps = 112; mediaType.comment = "comment"; - catalogue.createMediaType(s_adminOnAdminHost, mediaType); + catalogue.MediaType()->createMediaType(s_adminOnAdminHost, mediaType); const std::string driveName = "T10D6116"; const auto tapeDrive = getDefaultTapeDrive(driveName); - catalogue.createTapeDrive(tapeDrive); + catalogue.DriveState()->createTapeDrive(tapeDrive); } /** @@ -502,10 +501,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -513,7 +512,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // 6) Prepare files for reading by writing them to the mock system @@ -570,7 +569,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayRecall) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -682,10 +681,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumRecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -693,7 +692,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumRecall) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // 6) Prepare files for reading by writing them to the mock system @@ -756,7 +755,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumRecall) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance=s_diskInstance; @@ -882,10 +881,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -893,7 +892,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // 6) Prepare files for reading by writing them to the mock system @@ -950,7 +949,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); } { @@ -973,7 +972,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongRecall) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); } // Schedule the retrieval of the file @@ -1076,10 +1075,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1087,7 +1086,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } int MAX_RECALLS = 50; @@ -1150,7 +1149,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -1266,10 +1265,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallLinearAlgorithm) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1277,7 +1276,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallLinearAlgorithm) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } int MAX_RECALLS = 50; @@ -1341,7 +1340,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallLinearAlgorithm) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -1453,10 +1452,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallRAOAlgoDoesNotExistS // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1464,7 +1463,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallRAOAlgoDoesNotExistS { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } int MAX_RECALLS = 50; @@ -1528,7 +1527,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallRAOAlgoDoesNotExistS tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -1644,10 +1643,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallSLTFRAOAlgorithm) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1655,7 +1654,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallSLTFRAOAlgorithm) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } int MAX_RECALLS = 30; @@ -1719,7 +1718,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallSLTFRAOAlgorithm) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -1836,10 +1835,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1847,7 +1846,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // 6) Prepare files for reading by writing them to the mock system @@ -1904,7 +1903,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -1986,10 +1985,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionFailtoMount) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -1997,7 +1996,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionFailtoMount) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // 6) Prepare files for reading by writing them to the mock system @@ -2054,7 +2053,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionFailtoMount) { tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; tapeFileWritten.storageClassName = s_storageClassName; tapeFileWritten.tapeDrive = "drive0"; - catalogue.filesWrittenToTape(tapeFileWrittenSet); + catalogue.TapeFile()->filesWrittenToTape(tapeFileWrittenSet); // Schedule the retrieval of the file std::string diskInstance = s_diskInstance; @@ -2146,10 +2145,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -2157,15 +2156,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -2179,7 +2178,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -2243,7 +2242,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionGooddayMigration) { auto afiiter = archiveFileIds.begin(); for (const auto& sf: sourceFiles) { auto afi = *(afiiter++); - auto afs = catalogue.getArchiveFileById(afi); + auto afs = catalogue.ArchiveFile()->getArchiveFileById(afi); ASSERT_EQ(1, afs.tapeFiles.size()); cta::checksum::ChecksumBlob checksumBlob; checksumBlob.insert(cta::checksum::ADLER32, sf->adler32()); @@ -2297,10 +2296,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFileSizeMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -2308,15 +2307,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFileSizeMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -2330,7 +2329,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFileSizeMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -2420,9 +2419,9 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFileSizeMigration) { for(auto & sf: sourceFiles) { auto afi = *(afiiter++); if (afi == 1) { - ASSERT_THROW(catalogue.getArchiveFileById(afi), cta::exception::Exception); + ASSERT_THROW(catalogue.ArchiveFile()->getArchiveFileById(afi), cta::exception::Exception); } else { - auto afs = catalogue.getArchiveFileById(afi); + auto afs = catalogue.ArchiveFile()->getArchiveFileById(afi); ASSERT_EQ(1, afs.tapeFiles.size()); cta::checksum::ChecksumBlob checksumBlob; checksumBlob.insert(cta::checksum::ADLER32, sf->adler32()); @@ -2477,10 +2476,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -2488,15 +2487,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -2510,7 +2509,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -2599,7 +2598,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongChecksumMigration) { // None of the files made it to the catalogue for(__attribute__ ((unused)) auto & sf: sourceFiles) { auto afi = *(afiiter++); - ASSERT_THROW(catalogue.getArchiveFileById(afi), cta::exception::Exception); + ASSERT_THROW(catalogue.ArchiveFile()->getArchiveFileById(afi), cta::exception::Exception); } // Check logs for drive statistics @@ -2648,10 +2647,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFilesizeInMiddleOfBatchM // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -2659,15 +2658,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFilesizeInMiddleOfBatchM { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -2681,7 +2680,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFilesizeInMiddleOfBatchM { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -2792,14 +2791,14 @@ TEST_P(DataTransferSessionTest, DataTransferSessionWrongFilesizeInMiddleOfBatchM auto afi = *(afiiter++); if (fseq != 5) { // Files queued without the wrong file size made it to the catalogue - auto afs = catalogue.getArchiveFileById(afi); + auto afs = catalogue.ArchiveFile()->getArchiveFileById(afi); ASSERT_EQ(1, afs.tapeFiles.size()); cta::checksum::ChecksumBlob checksumBlob; checksumBlob.insert(cta::checksum::ADLER32, sf->adler32()); ASSERT_EQ(afs.checksumBlob, checksumBlob); ASSERT_EQ(1000, afs.fileSize); } else { - ASSERT_THROW(catalogue.getArchiveFileById(afi), cta::exception::Exception); + ASSERT_THROW(catalogue.ArchiveFile()->getArchiveFileById(afi), cta::exception::Exception); } fseq++; } @@ -2851,10 +2850,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -2862,15 +2861,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -2884,7 +2883,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -2962,7 +2961,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionMissingFilesMigration) { ASSERT_EQ(5, count); cta::catalogue::TapeSearchCriteria tapeCriteria; tapeCriteria.vid = s_vid; - auto tapeInfo = catalogue.getTapes(tapeCriteria); + auto tapeInfo = catalogue.Tape()->getTapes(tapeCriteria); ASSERT_EQ(1, tapeInfo.size()); // We should have max fseq at least 10. It could be higher is a retry manages to sneak in. ASSERT_LE(10, tapeInfo.begin()->lastFSeq); @@ -3017,10 +3016,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -3029,14 +3028,14 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -3051,7 +3050,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -3113,7 +3112,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { temp += ""; ASSERT_EQ(s_vid, sess.getVid()); cta::catalogue::TapeFileSearchCriteria criteria; - auto afsItor = catalogue.getArchiveFilesItor(criteria); + auto afsItor = catalogue.ArchiveFile()->getArchiveFilesItor(criteria); for (size_t i = 1; i <= sourceFiles.size(); ++i) { // Only the first files made it through. if (i <= 3) { @@ -3135,7 +3134,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullMigration) { // The tape should now be marked as full cta::catalogue::TapeSearchCriteria crit; crit.vid = s_vid; - auto tapes = catalogue.getTapes(crit); + auto tapes = catalogue.Tape()->getTapes(crit); ASSERT_EQ(1, tapes.size()); ASSERT_EQ(s_vid, tapes.front().vid); ASSERT_EQ(true, tapes.front().full); @@ -3187,10 +3186,10 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -3198,15 +3197,15 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { { auto tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, @@ -3222,7 +3221,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { { // Label the tape castor::tape::tapeFile::LabelSession::label(mockSys.fake.m_pathToDrive["/dev/nst0"], s_vid, false); - catalogue.tapeLabelled(s_vid, "T10D6116"); + catalogue.Tape()->tapeLabelled(s_vid, "T10D6116"); mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); // Create the files and schedule the archivals @@ -3284,7 +3283,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { temp += ""; ASSERT_EQ(s_vid, sess.getVid()); cta::catalogue::TapeFileSearchCriteria criteria; - auto afsItor = catalogue.getArchiveFilesItor(criteria); + auto afsItor = catalogue.ArchiveFile()->getArchiveFilesItor(criteria); for (size_t i = 1; i <= sourceFiles.size(); ++i) { // Only the first files made it through. if (i <= 3) { @@ -3306,7 +3305,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionTapeFullOnFlushMigration) { // The tape should now be marked as full cta::catalogue::TapeSearchCriteria crit; crit.vid = s_vid; - auto tapes = catalogue.getTapes(crit); + auto tapes = catalogue.Tape()->getTapes(crit); ASSERT_EQ(1, tapes.size()); ASSERT_EQ(s_vid, tapes.front().vid); ASSERT_EQ(true, tapes.front().full); @@ -3353,10 +3352,10 @@ TEST_P(DataTransferSessionTest, CleanerSessionFailsShouldPutTheDriveDown) { // 5) Create the environment for the migration to happen (library + tape) const std::string libraryComment = "Library comment"; const bool libraryIsDisabled = false; - catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + catalogue.LogicalLibrary()->createLogicalLibrary(s_adminOnAdminHost, s_libraryName, libraryIsDisabled, libraryComment); { - auto libraries = catalogue.getLogicalLibraries(); + auto libraries = catalogue.LogicalLibrary()->getLogicalLibraries(); ASSERT_EQ(1, libraries.size()); ASSERT_EQ(s_libraryName, libraries.front().name); ASSERT_EQ(libraryComment, libraries.front().comment); @@ -3364,15 +3363,15 @@ TEST_P(DataTransferSessionTest, CleanerSessionFailsShouldPutTheDriveDown) { { cta::catalogue::CreateTapeAttributes tape = getDefaultTape(); - catalogue.createTape(s_adminOnAdminHost, tape); + catalogue.Tape()->createTape(s_adminOnAdminHost, tape); } // Create the mount criteria auto mountPolicy = getImmediateMountMountPolicy(); - catalogue.createMountPolicy(requester, mountPolicy); + catalogue.MountPolicy()->createMountPolicy(requester, mountPolicy); std::string mountPolicyName = mountPolicy.name; - catalogue.createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); + catalogue.RequesterMountRule()->createRequesterMountRule(requester, mountPolicyName, s_diskInstance, requester.username, "Rule comment"); //delete is unnecessary //pointer with ownership will be passed to the application, diff --git a/tapeserver/castor/tape/tapeserver/daemon/DiskWriteTaskTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DiskWriteTaskTest.cpp index 76a9376472..977e2244a2 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DiskWriteTaskTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DiskWriteTaskTest.cpp @@ -23,7 +23,7 @@ #include "castor/tape/tapeserver/daemon/RecallReportPacker.hpp" #include "castor/tape/tapeserver/daemon/ReportPackerInterface.hpp" #include "common/log/LogContext.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "common/log/StringLogger.hpp" #include "castor/tape/tapeserver/daemon/MigrationMemoryManager.hpp" #include "castor/tape/tapeserver/daemon/MemBlock.hpp" diff --git a/tapeserver/castor/tape/tapeserver/daemon/DiskWriteThreadPoolTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DiskWriteThreadPoolTest.cpp index 7ef08167e3..bda55f7784 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DiskWriteThreadPoolTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DiskWriteThreadPoolTest.cpp @@ -24,7 +24,7 @@ #include "castor/tape/tapeserver/daemon/MemBlock.hpp" #include "castor/messages/TapeserverProxyDummy.hpp" #include "scheduler/TapeMountDummy.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include <gtest/gtest.h> namespace unitTests{ diff --git a/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp index df1559fb22..5e823e7e20 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/MigrationReportPackerTest.cpp @@ -71,7 +71,7 @@ const uint32_t TEST_GROUP_2 = 9754; mediaType.capacityInBytes = 10; mediaType.cartridge = "cartridge"; mediaType.comment = "comment"; - m_catalogue->createMediaType(admin,mediaType); + m_catalogue->MediaType()->createMediaType(admin,mediaType); } const cta::common::dataStructures::DiskInstance getDefaultDiskInstance() const { @@ -158,11 +158,11 @@ const uint32_t TEST_GROUP_2 = 9754; cta::common::dataStructures::VirtualOrganization vo = getDefaultVo(); const auto di = getDefaultDiskInstance(); cta::common::dataStructures::SecurityIdentity admin = cta::common::dataStructures::SecurityIdentity("admin","localhost"); - m_catalogue->createDiskInstance(admin, di.name, di.comment); - m_catalogue->createVirtualOrganization(admin,vo); - - m_catalogue->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(admin, tapePoolName, vo.name, 2, true, supply, "Create tape pool"); + m_catalogue->DiskInstance()->createDiskInstance(admin, di.name, di.comment); + m_catalogue->VO()->createVirtualOrganization(admin,vo); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->TapePool()->createTapePool(admin, tapePoolName, vo.name, 2, true, supply, "Create tape pool"); createMediaType(mediaType); { @@ -176,7 +176,7 @@ const uint32_t TEST_GROUP_2 = 9754; tape.comment = createTapeComment; tape.state = cta::common::dataStructures::Tape::DISABLED; tape.stateReason = "Test"; - m_catalogue->createTape(admin, tape); + m_catalogue->Tape()->createTape(admin, tape); } cta::common::dataStructures::StorageClass storageClass; @@ -185,7 +185,7 @@ const uint32_t TEST_GROUP_2 = 9754; storageClass.nbCopies = 1; storageClass.vo.name = vo.name; storageClass.comment = "Create storage class"; - m_catalogue->createStorageClass(admin, storageClass); + m_catalogue->StorageClass()->createStorageClass(admin, storageClass); ::testing::InSequence dummy; std::unique_ptr<cta::ArchiveJob> job1; @@ -320,11 +320,11 @@ const uint32_t TEST_GROUP_2 = 9754; cta::common::dataStructures::VirtualOrganization vo = getDefaultVo(); const auto &di = getDefaultDiskInstance(); - m_catalogue->createDiskInstance(admin, di.name, di.comment); - m_catalogue->createVirtualOrganization(admin,vo); - - m_catalogue->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); - m_catalogue->createTapePool(admin, tapePoolName, vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); + m_catalogue->DiskInstance()->createDiskInstance(admin, di.name, di.comment); + m_catalogue->VO()->createVirtualOrganization(admin,vo); + + m_catalogue->LogicalLibrary()->createLogicalLibrary(admin, logicalLibraryName, logicalLibraryIsDisabled, "Create logical library"); + m_catalogue->TapePool()->createTapePool(admin, tapePoolName, vo.name, nbPartialTapes, isEncrypted, supply, "Create tape pool"); createMediaType(mediaType); { @@ -338,7 +338,7 @@ const uint32_t TEST_GROUP_2 = 9754; tape.comment = createTapeComment; tape.state = cta::common::dataStructures::Tape::DISABLED; tape.stateReason = "test"; - m_catalogue->createTape(admin, tape); + m_catalogue->Tape()->createTape(admin, tape); } cta::common::dataStructures::StorageClass storageClass; @@ -347,7 +347,7 @@ const uint32_t TEST_GROUP_2 = 9754; storageClass.nbCopies = 1; storageClass.vo.name = vo.name; storageClass.comment = "Create storage class"; - m_catalogue->createStorageClass(admin, storageClass); + m_catalogue->StorageClass()->createStorageClass(admin, storageClass); ::testing::InSequence dummy; std::unique_ptr<cta::ArchiveJob> migratedBigFile; diff --git a/tapeserver/castor/tape/tapeserver/daemon/RecallReportPackerTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/RecallReportPackerTest.cpp index a737c1a90c..8987367a6b 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/RecallReportPackerTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/RecallReportPackerTest.cpp @@ -19,7 +19,7 @@ #include <gtest/gtest.h> #include "castor/tape/tapeserver/daemon/RecallReportPacker.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "common/exception/Exception.hpp" #include "common/log/StringLogger.hpp" #include "scheduler/testingMocks/MockRetrieveJob.hpp" diff --git a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp index c6de418bec..cd14e6a700 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjectorTest.cpp @@ -24,7 +24,7 @@ #include "castor/tape/tapeserver/daemon/TapeSessionReporter.hpp" #include "castor/tape/tapeserver/daemon/TaskWatchDog.hpp" #include "castor/tape/tapeserver/drive/FakeDrive.hpp" -#include "catalogue/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" #include "common/log/DummyLogger.hpp" #include "common/log/StringLogger.hpp" #include "common/processCap/ProcessCapDummy.hpp" diff --git a/tapeserver/castor/tape/tapeserver/file/OsmReaderTest.cpp b/tapeserver/castor/tape/tapeserver/file/OsmReaderTest.cpp index 6b456b9c2b..2b570a5d7b 100644 --- a/tapeserver/castor/tape/tapeserver/file/OsmReaderTest.cpp +++ b/tapeserver/castor/tape/tapeserver/file/OsmReaderTest.cpp @@ -29,28 +29,36 @@ #include "castor/tape/tapeserver/file/ReadSessionFactory.hpp" #include "castor/tape/tapeserver/SCSI/Device.hpp" #include "castor/tape/tapeserver/system/Wrapper.hpp" -#include "scheduler/RetrieveJob.hpp" -#include "catalogue/DummyCatalogue.hpp" -#include "common/processCap/ProcessCapDummy.hpp" +#include "catalogue/dummy/DummyCatalogue.hpp" +#include "catalogue/dummy/DummyTapeCatalogue.hpp" #include "common/log/StdoutLogger.hpp" #include "common/log/StringLogger.hpp" +#include "common/processCap/ProcessCapDummy.hpp" #include "scheduler/OStoreDB/OStoreDBFactory.hpp" +#include "scheduler/RetrieveJob.hpp" namespace { std::string g_device_name; std::string g_device_path; } -class OSMCatalogue: public cta::catalogue::DummyCatalogue { +class OSMTapeCatalogue: public cta::catalogue::DummyTapeCatalogue { public: using LabelFormat = cta::common::dataStructures::Label::Format; - OSMCatalogue() = default; + OSMTapeCatalogue() = default; LabelFormat getTapeLabelFormat(const std::string& vid) const override { return LabelFormat::OSM; } }; +class OSMCatalogue: public cta::catalogue::DummyCatalogue { +public: + OSMCatalogue() : DummyCatalogue() { + DummyCatalogue::m_tape = std::make_unique<OSMTapeCatalogue>(); + } +}; + class BasicRetrieveJob: public cta::RetrieveJob { public: BasicRetrieveJob() : cta::RetrieveJob(nullptr, @@ -128,7 +136,7 @@ TEST_F(OsmReaderTest, ReadOsmTape) { castor::tape::tapeserver::daemon::VolumeInfo m_volInfo; m_volInfo.vid = m_vid; m_volInfo.nbFiles = 1; - m_volInfo.labelFormat = m_catalogue->getTapeLabelFormat(m_volInfo.vid); + m_volInfo.labelFormat = static_cast<OSMTapeCatalogue*>(m_catalogue->Tape().get())->getTapeLabelFormat(m_volInfo.vid); m_volInfo.mountType = cta::common::dataStructures::MountType::Retrieve; // Now read a random file diff --git a/tapeserver/daemon/DriveHandler.cpp b/tapeserver/daemon/DriveHandler.cpp index 3cf70df3ce..da65077b65 100644 --- a/tapeserver/daemon/DriveHandler.cpp +++ b/tapeserver/daemon/DriveHandler.cpp @@ -1205,7 +1205,7 @@ int DriveHandler::setDriveDownForShutdown(const std::string& reason, cta::log::L driveInfo.logicalLibrary = m_configLine.logicalLibrary; driveInfo.host = cta::utils::getShortHostname(); - auto driveState = m_catalogue->getTapeDrive(driveInfo.driveName); + auto driveState = m_catalogue->DriveState()->getTapeDrive(driveInfo.driveName); if (!driveState) { lc->log(cta::log::WARNING, "In DriveHandler::setDriveDownForShutdown(). TapeDrive to set down doesn't exist."); return castor::tape::tapeserver::daemon::Session::MARK_DRIVE_AS_DOWN; diff --git a/tapeserver/readtp/ReadtpCmd.cpp b/tapeserver/readtp/ReadtpCmd.cpp index f88e5700ed..3e44487102 100644 --- a/tapeserver/readtp/ReadtpCmd.cpp +++ b/tapeserver/readtp/ReadtpCmd.cpp @@ -363,8 +363,8 @@ void ReadtpCmd::readTapeFiles( catalogue::TapeSearchCriteria searchCriteria; searchCriteria.vid = m_vid; - - auto tapeList = m_catalogue->getTapes(searchCriteria); + + auto tapeList = m_catalogue->Tape()->getTapes(searchCriteria); if (tapeList.empty()) { std::list<cta::log::Param> params; params.push_back(cta::log::Param("userName", getUsername())); @@ -465,7 +465,7 @@ void ReadtpCmd::readTapeFile( catalogue::TapeFileSearchCriteria searchCriteria; searchCriteria.vid = m_vid; searchCriteria.fSeq = fSeq; - auto itor = m_catalogue->getArchiveFilesItor(searchCriteria); + auto itor = m_catalogue->ArchiveFile()->getArchiveFilesItor(searchCriteria); if (!itor.hasMore()) { throw tapeserver::readtp::NoSuchFSeqException(); diff --git a/tapeserver/tapelabel/TapeLabelCmd.cpp b/tapeserver/tapelabel/TapeLabelCmd.cpp index d934fe931a..a73af72ccd 100644 --- a/tapeserver/tapelabel/TapeLabelCmd.cpp +++ b/tapeserver/tapelabel/TapeLabelCmd.cpp @@ -87,7 +87,7 @@ int TapeLabelCmd::exceptionThrowingMain(const int argc, char *const *const argv) const std::string capabilities("cap_sys_rawio+ep"); setProcessCapabilities(capabilities); - m_catalogue->checkTapeForLabel(m_vid); + m_catalogue->Tape()->checkTapeForLabel(m_vid); std::unique_ptr<castor::tape::tapeserver::drive::DriveInterface> drivePtr = createDrive(); castor::tape::tapeserver::drive::DriveInterface &drive = *drivePtr.get(); @@ -145,7 +145,7 @@ int TapeLabelCmd::exceptionThrowingMain(const int argc, char *const *const argv) dismountTape(m_vid); drive.disableLogicalBlockProtection(); if(!returnCode) { - m_catalogue->tapeLabelled(m_vid, m_unitName); + m_catalogue->Tape()->tapeLabelled(m_vid, m_unitName); } return returnCode; } diff --git a/xroot_plugins/XrdCtaActivityMountRuleLs.hpp b/xroot_plugins/XrdCtaActivityMountRuleLs.hpp index eb11a4e7d1..656180c489 100644 --- a/xroot_plugins/XrdCtaActivityMountRuleLs.hpp +++ b/xroot_plugins/XrdCtaActivityMountRuleLs.hpp @@ -58,7 +58,7 @@ private: ActivityMountRuleLsStream::ActivityMountRuleLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_activityMountRuleList(catalogue.getRequesterActivityMountRules()) + m_activityMountRuleList(catalogue.RequesterActivityMountRule()->getRequesterActivityMountRules()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaAdminLs.hpp b/xroot_plugins/XrdCtaAdminLs.hpp index 3063f08a17..e671b6122a 100644 --- a/xroot_plugins/XrdCtaAdminLs.hpp +++ b/xroot_plugins/XrdCtaAdminLs.hpp @@ -61,7 +61,7 @@ private: AdminLsStream::AdminLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_adminList(catalogue.getAdminUsers()) + m_adminList(catalogue.AdminUser()->getAdminUsers()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaArchiveRouteLs.hpp b/xroot_plugins/XrdCtaArchiveRouteLs.hpp index 8d424eaf11..0166080712 100644 --- a/xroot_plugins/XrdCtaArchiveRouteLs.hpp +++ b/xroot_plugins/XrdCtaArchiveRouteLs.hpp @@ -58,7 +58,7 @@ private: ArchiveRouteLsStream::ArchiveRouteLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_archiveRouteList(catalogue.getArchiveRoutes()) + m_archiveRouteList(catalogue.ArchiveRoute()->getArchiveRoutes()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaChangeStorageClass.hpp b/xroot_plugins/XrdCtaChangeStorageClass.hpp index 1f3f1395ef..5bbdccd197 100644 --- a/xroot_plugins/XrdCtaChangeStorageClass.hpp +++ b/xroot_plugins/XrdCtaChangeStorageClass.hpp @@ -28,7 +28,7 @@ public: XrdCtaChangeStorageClass(cta::catalogue::Catalogue &catalogue, cta::log::LogContext &lc); void updateCatalogue(const std::vector<std::basic_string<char>>& archiveFileIds, const std::string& newStorageClassName); private: - const cta::catalogue::Catalogue &m_catalogue; + cta::catalogue::Catalogue &m_catalogue; cta::log::LogContext &m_lc; }; @@ -37,7 +37,7 @@ XrdCtaChangeStorageClass::XrdCtaChangeStorageClass(cta::catalogue::Catalogue &ca void XrdCtaChangeStorageClass::updateCatalogue(const std::vector<std::basic_string<char>>& archiveFileIds, const std::string& newStorageClassName) { for (auto & id : archiveFileIds) { const uint64_t archiveFileId = std::stoul(id); - m_catalogue.modifyArchiveFileStorageClassId(archiveFileId, newStorageClassName); + m_catalogue.ArchiveFile()->modifyArchiveFileStorageClassId(archiveFileId, newStorageClassName); } } } // namespace xrd diff --git a/xroot_plugins/XrdCtaDiskInstanceLs.hpp b/xroot_plugins/XrdCtaDiskInstanceLs.hpp index d87c290aa5..2e875c3ac9 100644 --- a/xroot_plugins/XrdCtaDiskInstanceLs.hpp +++ b/xroot_plugins/XrdCtaDiskInstanceLs.hpp @@ -60,7 +60,7 @@ private: DiskInstanceLsStream::DiskInstanceLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_diskInstanceList(catalogue.getAllDiskInstances()) + m_diskInstanceList(catalogue.DiskInstance()->getAllDiskInstances()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaDiskInstanceSpaceLs.hpp b/xroot_plugins/XrdCtaDiskInstanceSpaceLs.hpp index 2ba9572a88..e12771ad0d 100644 --- a/xroot_plugins/XrdCtaDiskInstanceSpaceLs.hpp +++ b/xroot_plugins/XrdCtaDiskInstanceSpaceLs.hpp @@ -60,7 +60,7 @@ private: DiskInstanceSpaceLsStream::DiskInstanceSpaceLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_diskInstanceSpaceList(catalogue.getAllDiskInstanceSpaces()) + m_diskInstanceSpaceList(catalogue.DiskInstanceSpace()->getAllDiskInstanceSpaces()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaDiskSystemLs.hpp b/xroot_plugins/XrdCtaDiskSystemLs.hpp index b5178547e8..4a8cc9b5c2 100644 --- a/xroot_plugins/XrdCtaDiskSystemLs.hpp +++ b/xroot_plugins/XrdCtaDiskSystemLs.hpp @@ -60,7 +60,7 @@ private: DiskSystemLsStream::DiskSystemLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_diskSystemList(catalogue.getAllDiskSystems()) + m_diskSystemList(catalogue.DiskSystem()->getAllDiskSystems()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaDriveLs.hpp b/xroot_plugins/XrdCtaDriveLs.hpp index b6a9d618da..7244c4ea01 100644 --- a/xroot_plugins/XrdCtaDriveLs.hpp +++ b/xroot_plugins/XrdCtaDriveLs.hpp @@ -22,10 +22,11 @@ #include <string> #include <utility> -#include <common/dataStructures/DriveStatusSerDeser.hpp> -#include <common/dataStructures/MountTypeSerDeser.hpp> -#include <xroot_plugins/XrdCtaStream.hpp> -#include <xroot_plugins/XrdSsiCtaRequestMessage.hpp> +#include "catalogue/Catalogue.hpp" +#include "common/dataStructures/DriveStatusSerDeser.hpp" +#include "common/dataStructures/MountTypeSerDeser.hpp" +#include "xroot_plugins/XrdCtaStream.hpp" +#include "xroot_plugins/XrdSsiCtaRequestMessage.hpp" namespace cta { namespace xrd { @@ -62,7 +63,7 @@ class DriveLsStream: public XrdCtaStream{ static constexpr const char* const LOG_SUFFIX = "DriveLsStream"; //!< Identifier for log messages std::list<common::dataStructures::TapeDrive> m_tapeDrives; - std::list<cta::catalogue::Catalogue::DriveConfig> m_tapeDrivesConfigs; + std::list<cta::catalogue::DriveConfigCatalogue::DriveConfig> m_tapeDrivesConfigs; }; @@ -71,8 +72,8 @@ DriveLsStream::DriveLsStream(const RequestMessage &requestMsg, cta::catalogue::C log::LogContext &lc) : XrdCtaStream(catalogue, scheduler), m_lc(lc), - m_tapeDrives(m_catalogue.getTapeDrives()), - m_tapeDrivesConfigs(m_catalogue.getTapeDriveConfigs()) { + m_tapeDrives(m_catalogue.DriveState()->getTapeDrives()), + m_tapeDrivesConfigs(m_catalogue.DriveConfig()->getTapeDriveConfigs()) { XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "DriveLsStream() constructor"); auto driveRegexOpt = requestMsg.getOptional(cta::admin::OptionString::DRIVE); diff --git a/xroot_plugins/XrdCtaGroupMountRuleLs.hpp b/xroot_plugins/XrdCtaGroupMountRuleLs.hpp index 8f94f853d3..ad6f9fb497 100644 --- a/xroot_plugins/XrdCtaGroupMountRuleLs.hpp +++ b/xroot_plugins/XrdCtaGroupMountRuleLs.hpp @@ -59,7 +59,7 @@ private: GroupMountRuleLsStream::GroupMountRuleLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_groupMountRuleList(catalogue.getRequesterGroupMountRules()) + m_groupMountRuleList(catalogue.RequesterGroupMountRule()->getRequesterGroupMountRules()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaLogicalLibraryLs.hpp b/xroot_plugins/XrdCtaLogicalLibraryLs.hpp index fdd1e666b4..c68e2af826 100644 --- a/xroot_plugins/XrdCtaLogicalLibraryLs.hpp +++ b/xroot_plugins/XrdCtaLogicalLibraryLs.hpp @@ -65,7 +65,7 @@ private: LogicalLibraryLsStream::LogicalLibraryLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler, const std::optional<bool>& disabled) : XrdCtaStream(catalogue, scheduler), - m_logicalLibraryList(catalogue.getLogicalLibraries()), + m_logicalLibraryList(catalogue.LogicalLibrary()->getLogicalLibraries()), m_disabled(disabled) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaMediaTypeLs.hpp b/xroot_plugins/XrdCtaMediaTypeLs.hpp index d24126da5b..dd6a7a461d 100644 --- a/xroot_plugins/XrdCtaMediaTypeLs.hpp +++ b/xroot_plugins/XrdCtaMediaTypeLs.hpp @@ -58,7 +58,7 @@ private: MediaTypeLsStream::MediaTypeLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_mediaTypeList(catalogue.getMediaTypes()) + m_mediaTypeList(catalogue.MediaType()->getMediaTypes()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaMountPolicyLs.hpp b/xroot_plugins/XrdCtaMountPolicyLs.hpp index 0b0ce3019f..1cef92fa98 100644 --- a/xroot_plugins/XrdCtaMountPolicyLs.hpp +++ b/xroot_plugins/XrdCtaMountPolicyLs.hpp @@ -58,7 +58,7 @@ private: MountPolicyLsStream::MountPolicyLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_mountPolicyList(catalogue.getMountPolicies()) + m_mountPolicyList(catalogue.MountPolicy()->getMountPolicies()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp b/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp index bcb4f6b38c..272f5771bc 100644 --- a/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp +++ b/xroot_plugins/XrdCtaRecycleTapeFileLs.hpp @@ -51,7 +51,7 @@ private: */ virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf); - cta::catalogue::Catalogue::FileRecycleLogItor m_fileRecycleLogItor; //!< List of recycle tape files from the catalogue + cta::catalogue::FileRecycleLogItor m_fileRecycleLogItor; //!< List of recycle tape files from the catalogue static constexpr const char* const LOG_SUFFIX = "RecycleTapeFileLsStream"; //!< Identifier for log messages }; @@ -95,7 +95,7 @@ RecycleTapeFileLsStream::RecycleTapeFileLsStream(const RequestMessage &requestMs throw cta::exception::UserError("Must specify at least one of the following search options: vid, fxid, fxidfile or archiveFileId"); } - m_fileRecycleLogItor = catalogue.getFileRecycleLogItor(searchCriteria); + m_fileRecycleLogItor = catalogue.FileRecycleLog()->getFileRecycleLogItor(searchCriteria); XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "RecycleTapeFileLsStream() constructor"); } diff --git a/xroot_plugins/XrdCtaRepackLs.hpp b/xroot_plugins/XrdCtaRepackLs.hpp index d35baf0024..974cfe24c1 100644 --- a/xroot_plugins/XrdCtaRepackLs.hpp +++ b/xroot_plugins/XrdCtaRepackLs.hpp @@ -60,7 +60,7 @@ namespace cta { namespace xrd { std::inserter(tapeVids, tapeVids.begin()), [](cta::common::dataStructures::RepackInfo &ri) {return ri.vid;}); - cta::common::dataStructures::VidToTapeMap tapeVidMap = m_catalogue.getTapesByVid(tapeVids); // throws an exception if a vid does not exist + cta::common::dataStructures::VidToTapeMap tapeVidMap = m_catalogue.Tape()->getTapesByVid(tapeVids); // throws an exception if a vid does not exist for(bool is_buffer_full = false; !m_repackList.empty() && !is_buffer_full; m_repackList.pop_front()){ Data record; diff --git a/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp b/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp index 199dc63fcd..3767ce5fbf 100644 --- a/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp +++ b/xroot_plugins/XrdCtaRequesterMountRuleLs.hpp @@ -58,7 +58,7 @@ private: RequesterMountRuleLsStream::RequesterMountRuleLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_requesterMountRuleList(catalogue.getRequesterMountRules()) + m_requesterMountRuleList(catalogue.RequesterMountRule()->getRequesterMountRules()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdCtaStorageClassLs.hpp b/xroot_plugins/XrdCtaStorageClassLs.hpp index a881f809fa..93c522651f 100644 --- a/xroot_plugins/XrdCtaStorageClassLs.hpp +++ b/xroot_plugins/XrdCtaStorageClassLs.hpp @@ -68,9 +68,9 @@ StorageClassLsStream::StorageClassLsStream(const RequestMessage &requestMsg, cta XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "StorageClassLsStream() constructor"); if(m_storageClassName) { - m_storageClassList.push_back(m_catalogue.getStorageClass(m_storageClassName.value())); + m_storageClassList.push_back(m_catalogue.StorageClass()->getStorageClass(m_storageClassName.value())); } else { - for(const auto &storageClass : m_catalogue.getStorageClasses()) { + for(const auto &storageClass : m_catalogue.StorageClass()->getStorageClasses()) { m_storageClassList.push_back(storageClass); } } diff --git a/xroot_plugins/XrdCtaTapeFileLs.hpp b/xroot_plugins/XrdCtaTapeFileLs.hpp index 43cbc9bf61..6f53c41a9b 100644 --- a/xroot_plugins/XrdCtaTapeFileLs.hpp +++ b/xroot_plugins/XrdCtaTapeFileLs.hpp @@ -53,9 +53,9 @@ private: */ virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf); - catalogue::Catalogue::ArchiveFileItor m_tapeFileItor; //!< Iterator across files which have been archived - grpc::EndpointMap m_endpoints; //!< List of gRPC endpoints - bool m_LookupNamespace; //!< True if namespace lookup is required + catalogue::ArchiveFileItor m_tapeFileItor; //!< Iterator across files which have been archived + grpc::EndpointMap m_endpoints; //!< List of gRPC endpoints + bool m_LookupNamespace; //!< True if namespace lookup is required static constexpr const char* const LOG_SUFFIX = "TapeFileLsStream"; //!< Identifier for log messages }; @@ -101,7 +101,7 @@ TapeFileLsStream::TapeFileLsStream(const RequestMessage &requestMsg, throw cta::exception::UserError("Must specify at least one of the following search options: vid, fxid, fxidfile or archiveFileId"); } - m_tapeFileItor = m_catalogue.getArchiveFilesItor(searchCriteria); + m_tapeFileItor = m_catalogue.ArchiveFile()->getArchiveFilesItor(searchCriteria); } diff --git a/xroot_plugins/XrdCtaTapeLs.hpp b/xroot_plugins/XrdCtaTapeLs.hpp index df99d6936f..24132dcb7f 100644 --- a/xroot_plugins/XrdCtaTapeLs.hpp +++ b/xroot_plugins/XrdCtaTapeLs.hpp @@ -88,7 +88,7 @@ TapeLsStream::TapeLsStream(const RequestMessage &requestMsg, cta::catalogue::Cat throw cta::exception::UserError("Cannot specify --all together with other search options"); } - m_tapeList = m_catalogue.getTapes(searchCriteria); + m_tapeList = m_catalogue.Tape()->getTapes(searchCriteria); } diff --git a/xroot_plugins/XrdCtaTapePoolLs.hpp b/xroot_plugins/XrdCtaTapePoolLs.hpp index 6af30eec99..6dca27add3 100644 --- a/xroot_plugins/XrdCtaTapePoolLs.hpp +++ b/xroot_plugins/XrdCtaTapePoolLs.hpp @@ -59,7 +59,7 @@ private: TapePoolLsStream::TapePoolLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_tapePoolList(catalogue.getTapePools()) + m_tapePoolList(catalogue.TapePool()->getTapePools()) { using namespace cta::admin; @@ -70,7 +70,7 @@ TapePoolLsStream::TapePoolLsStream(const RequestMessage &requestMsg, cta::catalo searchCriteria.vo = requestMsg.getOptional(OptionString::VO); searchCriteria.encrypted = requestMsg.getOptional(OptionBoolean::ENCRYPTED); - m_tapePoolList = m_catalogue.getTapePools(searchCriteria); + m_tapePoolList = m_catalogue.TapePool()->getTapePools(searchCriteria); } int TapePoolLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) { diff --git a/xroot_plugins/XrdCtaVersion.hpp b/xroot_plugins/XrdCtaVersion.hpp index 0616875bc3..8f6e712a06 100644 --- a/xroot_plugins/XrdCtaVersion.hpp +++ b/xroot_plugins/XrdCtaVersion.hpp @@ -68,8 +68,8 @@ VersionStream::VersionStream(const RequestMessage &requestMsg, cta::catalogue::C XrdCtaStream(catalogue, scheduler), m_client_versions(requestMsg.getClientVersions()), m_catalogue_conn_string(catalogueConnString), - m_catalogue_version(m_catalogue.getSchemaVersion().getSchemaVersion<std::string>()), - m_is_upgrading(m_catalogue.getSchemaVersion().getStatus<catalogue::SchemaVersion::Status>() + m_catalogue_version(m_catalogue.Schema()->getSchemaVersion().getSchemaVersion<std::string>()), + m_is_upgrading(m_catalogue.Schema()->getSchemaVersion().getStatus<catalogue::SchemaVersion::Status>() == catalogue::SchemaVersion::Status::UPGRADING) { XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "VersionStream() constructor"); m_server_versions.ctaVersion = CTA_VERSION; diff --git a/xroot_plugins/XrdCtaVirtualOrganizationLs.hpp b/xroot_plugins/XrdCtaVirtualOrganizationLs.hpp index 22c6c90708..1b45e21351 100644 --- a/xroot_plugins/XrdCtaVirtualOrganizationLs.hpp +++ b/xroot_plugins/XrdCtaVirtualOrganizationLs.hpp @@ -60,7 +60,7 @@ private: VirtualOrganizationLsStream::VirtualOrganizationLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) : XrdCtaStream(catalogue, scheduler), - m_virtualOrganizationList(catalogue.getVirtualOrganizations()) + m_virtualOrganizationList(catalogue.VO()->getVirtualOrganizations()) { using namespace cta::admin; diff --git a/xroot_plugins/XrdSsiCtaRequestMessage.cpp b/xroot_plugins/XrdSsiCtaRequestMessage.cpp index d81226f41a..66d64a57e6 100644 --- a/xroot_plugins/XrdSsiCtaRequestMessage.cpp +++ b/xroot_plugins/XrdSsiCtaRequestMessage.cpp @@ -538,7 +538,7 @@ void RequestMessage::processCLOSEW(const cta::eos::Notification ¬ification, c throw cta::exception::UserError("File is in fail_on_closew_test storage class, which always fails."); } - auto storageClass = m_catalogue.getStorageClass(storageClassItor->second); + auto storageClass = m_catalogue.StorageClass()->getStorageClass(storageClassItor->second); // Disallow archival of files above the specified limit if(storageClass.vo.maxFileSize && notification.file().size() > storageClass.vo.maxFileSize) { @@ -784,7 +784,7 @@ void RequestMessage::processDELETE(const cta::eos::Notification ¬ification, c cta::utils::Timer t; cta::log::TimingList tl; try { - request.archiveFile = m_catalogue.getArchiveFileById(request.archiveFileID); + request.archiveFile = m_catalogue.ArchiveFile()->getArchiveFileById(request.archiveFileID); tl.insertAndReset("catalogueGetArchiveFileByIdTime",t); } catch (cta::exception::Exception &ex){ log::ScopedParamContainer spc(m_lc); @@ -835,7 +835,7 @@ void RequestMessage::processUPDATE_FID(const cta::eos::Notification ¬ificatio // Update the disk file ID cta::utils::Timer t; - m_catalogue.updateDiskFileId(archiveFileId, diskInstance, diskFileId); + m_catalogue.ArchiveFile()->updateDiskFileId(archiveFileId, diskInstance, diskFileId); // Create a log entry cta::log::ScopedParamContainer params(m_lc); @@ -958,7 +958,7 @@ void RequestMessage::processAdmin_Add(cta::xrd::Response &response) auto &username = getRequired(OptionString::USERNAME); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createAdminUser(m_cliIdentity, username, comment); + m_catalogue.AdminUser()->createAdminUser(m_cliIdentity, username, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -972,7 +972,7 @@ void RequestMessage::processAdmin_Ch(cta::xrd::Response &response) auto &username = getRequired(OptionString::USERNAME); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.modifyAdminUserComment(m_cliIdentity, username, comment); + m_catalogue.AdminUser()->modifyAdminUserComment(m_cliIdentity, username, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -985,7 +985,7 @@ void RequestMessage::processAdmin_Rm(cta::xrd::Response &response) auto &username = getRequired(OptionString::USERNAME); - m_catalogue.deleteAdminUser(username); + m_catalogue.AdminUser()->deleteAdminUser(username); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1012,7 +1012,7 @@ void RequestMessage::processArchiveRoute_Add(cta::xrd::Response &response) auto &tapepool = getRequired(OptionString::TAPE_POOL); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createArchiveRoute(m_cliIdentity, scn, cn, tapepool, comment); + m_catalogue.ArchiveRoute()->createArchiveRoute(m_cliIdentity, scn, cn, tapepool, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1029,10 +1029,10 @@ void RequestMessage::processArchiveRoute_Ch(cta::xrd::Response &response) auto comment = getOptional(OptionString::COMMENT); if(comment) { - m_catalogue.modifyArchiveRouteComment(m_cliIdentity, scn, cn, comment.value()); + m_catalogue.ArchiveRoute()->modifyArchiveRouteComment(m_cliIdentity, scn, cn, comment.value()); } if(tapepool) { - m_catalogue.modifyArchiveRouteTapePoolName(m_cliIdentity, scn, cn, tapepool.value()); + m_catalogue.ArchiveRoute()->modifyArchiveRouteTapePoolName(m_cliIdentity, scn, cn, tapepool.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1047,7 +1047,7 @@ void RequestMessage::processArchiveRoute_Rm(cta::xrd::Response &response) auto &scn = getRequired(OptionString::STORAGE_CLASS); auto &cn = getRequired(OptionUInt64::COPY_NUMBER); - m_catalogue.deleteArchiveRoute(scn, cn); + m_catalogue.ArchiveRoute()->deleteArchiveRoute(scn, cn); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1146,7 +1146,7 @@ void RequestMessage::processDrive_Rm(cta::xrd::Response &response) regex = '^' + regex + '$'; cta::utils::Regex driveNameRegex(regex.c_str()); - const auto tapeDriveNames = m_catalogue.getTapeDriveNames(); + const auto tapeDriveNames = m_catalogue.DriveState()->getTapeDriveNames(); bool drivesFound = false; for (auto tapeDriveName : tapeDriveNames) @@ -1154,7 +1154,7 @@ void RequestMessage::processDrive_Rm(cta::xrd::Response &response) const auto regexResult = driveNameRegex.exec(tapeDriveName); if (!regexResult.empty()) { - const auto tapeDrive = m_catalogue.getTapeDrive(tapeDriveName).value(); + const auto tapeDrive = m_catalogue.DriveState()->getTapeDrive(tapeDriveName).value(); if (tapeDrive.driveStatus == cta::common::dataStructures::DriveStatus::Down || tapeDrive.driveStatus == cta::common::dataStructures::DriveStatus::Shutdown || @@ -1220,7 +1220,7 @@ void RequestMessage::processGroupMountRule_Add(cta::xrd::Response &response) auto &name = getRequired(OptionString::USERNAME); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createRequesterGroupMountRule(m_cliIdentity, mountpolicy, in, name, comment); + m_catalogue.RequesterGroupMountRule()->createRequesterGroupMountRule(m_cliIdentity, mountpolicy, in, name, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1237,10 +1237,10 @@ void RequestMessage::processGroupMountRule_Ch(cta::xrd::Response &response) auto comment = getOptional(OptionString::COMMENT); if(comment) { - m_catalogue.modifyRequesterGroupMountRuleComment(m_cliIdentity, in, name, comment.value()); + m_catalogue.RequesterGroupMountRule()->modifyRequesterGroupMountRuleComment(m_cliIdentity, in, name, comment.value()); } if(mountpolicy) { - m_catalogue.modifyRequesterGroupMountRulePolicy(m_cliIdentity, in, name, mountpolicy.value()); + m_catalogue.RequesterGroupMountRule()->modifyRequesterGroupMountRulePolicy(m_cliIdentity, in, name, mountpolicy.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1255,7 +1255,7 @@ void RequestMessage::processGroupMountRule_Rm(cta::xrd::Response &response) auto &in = getRequired(OptionString::INSTANCE); auto &name = getRequired(OptionString::USERNAME); - m_catalogue.deleteRequesterGroupMountRule(in, name); + m_catalogue.RequesterGroupMountRule()->deleteRequesterGroupMountRule(in, name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1280,7 +1280,7 @@ void RequestMessage::processLogicalLibrary_Add(cta::xrd::Response &response) auto isDisabled = getOptional(OptionBoolean::DISABLED); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createLogicalLibrary(m_cliIdentity, name, isDisabled ? isDisabled.value() : false, comment); + m_catalogue.LogicalLibrary()->createLogicalLibrary(m_cliIdentity, name, isDisabled ? isDisabled.value() : false, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1297,17 +1297,17 @@ void RequestMessage::processLogicalLibrary_Ch(cta::xrd::Response &response) auto disabledReason = getOptional(OptionString::DISABLED_REASON); if(disabled) { - m_catalogue.setLogicalLibraryDisabled(m_cliIdentity, name, disabled.value()); + m_catalogue.LogicalLibrary()->setLogicalLibraryDisabled(m_cliIdentity, name, disabled.value()); if ((!disabled.value()) && (!disabledReason)) { //if enabling the tape and the reason is not specified in the command, erase the reason - m_catalogue.modifyLogicalLibraryDisabledReason(m_cliIdentity, name, ""); + m_catalogue.LogicalLibrary()->modifyLogicalLibraryDisabledReason(m_cliIdentity, name, ""); } } if(comment) { - m_catalogue.modifyLogicalLibraryComment(m_cliIdentity, name, comment.value()); + m_catalogue.LogicalLibrary()->modifyLogicalLibraryComment(m_cliIdentity, name, comment.value()); } if (disabledReason) { - m_catalogue.modifyLogicalLibraryDisabledReason(m_cliIdentity, name, disabledReason.value()); + m_catalogue.LogicalLibrary()->modifyLogicalLibraryDisabledReason(m_cliIdentity, name, disabledReason.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1321,7 +1321,7 @@ void RequestMessage::processLogicalLibrary_Rm(cta::xrd::Response &response) auto &name = getRequired(OptionString::LOGICAL_LIBRARY); - m_catalogue.deleteLogicalLibrary(name); + m_catalogue.LogicalLibrary()->deleteLogicalLibrary(name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1380,7 +1380,7 @@ void RequestMessage::processMediaType_Add(cta::xrd::Response &response) mediaType.minLPos = getOptional(OptionUInt64::MIN_LPOS); mediaType.maxLPos = getOptional(OptionUInt64::MAX_LPOS); mediaType.comment = getRequired(OptionString::COMMENT); - m_catalogue.createMediaType(m_cliIdentity, mediaType); + m_catalogue.MediaType()->createMediaType(m_cliIdentity, mediaType); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1421,26 +1421,26 @@ void RequestMessage::processMediaType_Ch(cta::xrd::Response &response) } if(cartridge){ - m_catalogue.modifyMediaTypeCartridge(m_cliIdentity,mediaTypeName,cartridge.value()); + m_catalogue.MediaType()->modifyMediaTypeCartridge(m_cliIdentity,mediaTypeName,cartridge.value()); } if(primaryDensityCode){ - m_catalogue.modifyMediaTypePrimaryDensityCode(m_cliIdentity,mediaTypeName,primaryDensityCode.value()); + m_catalogue.MediaType()->modifyMediaTypePrimaryDensityCode(m_cliIdentity,mediaTypeName,primaryDensityCode.value()); } if(secondaryDensityCode){ - m_catalogue.modifyMediaTypeSecondaryDensityCode(m_cliIdentity,mediaTypeName,secondaryDensityCode.value()); + m_catalogue.MediaType()->modifyMediaTypeSecondaryDensityCode(m_cliIdentity,mediaTypeName,secondaryDensityCode.value()); } if(nbWraps){ std::optional<uint32_t> newNbWraps = nbWraps.value(); - m_catalogue.modifyMediaTypeNbWraps(m_cliIdentity,mediaTypeName,newNbWraps); + m_catalogue.MediaType()->modifyMediaTypeNbWraps(m_cliIdentity,mediaTypeName,newNbWraps); } if(minlpos){ - m_catalogue.modifyMediaTypeMinLPos(m_cliIdentity, mediaTypeName, minlpos); + m_catalogue.MediaType()->modifyMediaTypeMinLPos(m_cliIdentity, mediaTypeName, minlpos); } if(maxlpos){ - m_catalogue.modifyMediaTypeMaxLPos(m_cliIdentity,mediaTypeName,maxlpos); + m_catalogue.MediaType()->modifyMediaTypeMaxLPos(m_cliIdentity,mediaTypeName,maxlpos); } if(comment){ - m_catalogue.modifyMediaTypeComment(m_cliIdentity,mediaTypeName,comment.value()); + m_catalogue.MediaType()->modifyMediaTypeComment(m_cliIdentity,mediaTypeName,comment.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1453,7 +1453,7 @@ void RequestMessage::processMediaType_Rm(cta::xrd::Response &response) const auto &mtn = getRequired(OptionString::MEDIA_TYPE); - m_catalogue.deleteMediaType(mtn); + m_catalogue.MediaType()->deleteMediaType(mtn); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1492,7 +1492,7 @@ void RequestMessage::processMountPolicy_Add(cta::xrd::Response &response) mountPolicy.minRetrieveRequestAge = minretrieverequestage; mountPolicy.comment = comment; - m_catalogue.createMountPolicy(m_cliIdentity, mountPolicy); + m_catalogue.MountPolicy()->createMountPolicy(m_cliIdentity, mountPolicy); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1511,19 +1511,19 @@ void RequestMessage::processMountPolicy_Ch(cta::xrd::Response &response) auto comment = getOptional(OptionString::COMMENT); if(archivepriority) { - m_catalogue.modifyMountPolicyArchivePriority(m_cliIdentity, group, archivepriority.value()); + m_catalogue.MountPolicy()->modifyMountPolicyArchivePriority(m_cliIdentity, group, archivepriority.value()); } if(minarchiverequestage) { - m_catalogue.modifyMountPolicyArchiveMinRequestAge(m_cliIdentity, group, minarchiverequestage.value()); + m_catalogue.MountPolicy()->modifyMountPolicyArchiveMinRequestAge(m_cliIdentity, group, minarchiverequestage.value()); } if(retrievepriority) { - m_catalogue.modifyMountPolicyRetrievePriority(m_cliIdentity, group, retrievepriority.value()); + m_catalogue.MountPolicy()->modifyMountPolicyRetrievePriority(m_cliIdentity, group, retrievepriority.value()); } if(minretrieverequestage) { - m_catalogue.modifyMountPolicyRetrieveMinRequestAge(m_cliIdentity, group, minretrieverequestage.value()); + m_catalogue.MountPolicy()->modifyMountPolicyRetrieveMinRequestAge(m_cliIdentity, group, minretrieverequestage.value()); } if(comment) { - m_catalogue.modifyMountPolicyComment(m_cliIdentity, group, comment.value()); + m_catalogue.MountPolicy()->modifyMountPolicyComment(m_cliIdentity, group, comment.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1537,7 +1537,7 @@ void RequestMessage::processMountPolicy_Rm(cta::xrd::Response &response) auto &group = getRequired(OptionString::MOUNT_POLICY); - m_catalogue.deleteMountPolicy(group); + m_catalogue.MountPolicy()->deleteMountPolicy(group); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1579,7 +1579,7 @@ void RequestMessage::processRepack_Add(cta::xrd::Response &response) //Get the mountpolicy from the catalogue common::dataStructures::MountPolicy mountPolicy; typedef std::list<common::dataStructures::MountPolicy> MountPolicyList; - MountPolicyList mountPolicies = m_catalogue.getMountPolicies(); + MountPolicyList mountPolicies = m_catalogue.MountPolicy()->getMountPolicies(); MountPolicyList::const_iterator repackMountPolicyItor = std::find_if(mountPolicies.begin(),mountPolicies.end(),[mountPolicyProvidedByUser](const common::dataStructures::MountPolicy & mp){ return mp.name == mountPolicyProvidedByUser; }); @@ -1678,7 +1678,7 @@ void RequestMessage::processRequesterMountRule_Add(cta::xrd::Response &response) auto &name = getRequired(OptionString::USERNAME); auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createRequesterMountRule(m_cliIdentity, mountpolicy, in, name, comment); + m_catalogue.RequesterMountRule()->createRequesterMountRule(m_cliIdentity, mountpolicy, in, name, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1695,10 +1695,10 @@ void RequestMessage::processRequesterMountRule_Ch(cta::xrd::Response &response) auto mountpolicy = getOptional(OptionString::MOUNT_POLICY); if(comment) { - m_catalogue.modifyRequesteMountRuleComment(m_cliIdentity, in, name, comment.value()); + m_catalogue.RequesterMountRule()->modifyRequesteMountRuleComment(m_cliIdentity, in, name, comment.value()); } if(mountpolicy) { - m_catalogue.modifyRequesterMountRulePolicy(m_cliIdentity, in, name, mountpolicy.value()); + m_catalogue.RequesterMountRule()->modifyRequesterMountRulePolicy(m_cliIdentity, in, name, mountpolicy.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1713,7 +1713,7 @@ void RequestMessage::processRequesterMountRule_Rm(cta::xrd::Response &response) auto &in = getRequired(OptionString::INSTANCE); auto &name = getRequired(OptionString::USERNAME); - m_catalogue.deleteRequesterMountRule(in, name); + m_catalogue.RequesterMountRule()->deleteRequesterMountRule(in, name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1743,7 +1743,8 @@ void RequestMessage::processActivityMountRule_Add(cta::xrd::Response &response) auto &comment = getRequired(OptionString::COMMENT); auto &activityRegex = getRequired(OptionString::ACTIVITY_REGEX); - m_catalogue.createRequesterActivityMountRule(m_cliIdentity, mountpolicy, in, name, activityRegex, comment); + m_catalogue.RequesterActivityMountRule()->createRequesterActivityMountRule(m_cliIdentity, mountpolicy, in, name, + activityRegex, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1762,10 +1763,12 @@ void RequestMessage::processActivityMountRule_Ch(cta::xrd::Response &response) auto mountpolicy = getOptional(OptionString::MOUNT_POLICY); if(comment) { - m_catalogue.modifyRequesterActivityMountRuleComment(m_cliIdentity, in, name, activityRegex, comment.value()); + m_catalogue.RequesterActivityMountRule()->modifyRequesterActivityMountRuleComment(m_cliIdentity, in, name, + activityRegex, comment.value()); } if(mountpolicy) { - m_catalogue.modifyRequesterActivityMountRulePolicy(m_cliIdentity, in, name, activityRegex, mountpolicy.value()); + m_catalogue.RequesterActivityMountRule()->modifyRequesterActivityMountRulePolicy(m_cliIdentity, in, name, + activityRegex, mountpolicy.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1781,7 +1784,7 @@ void RequestMessage::processActivityMountRule_Rm(cta::xrd::Response &response) auto &name = getRequired(OptionString::USERNAME); auto &activityRegex = getRequired(OptionString::ACTIVITY_REGEX); - m_catalogue.deleteRequesterActivityMountRule(in, name, activityRegex); + m_catalogue.RequesterActivityMountRule()->deleteRequesterActivityMountRule(in, name, activityRegex); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1824,7 +1827,7 @@ void RequestMessage::processStorageClass_Add(cta::xrd::Response &response) storageClass.comment = getRequired(OptionString::COMMENT); storageClass.vo.name = getRequired(OptionString::VO); - m_catalogue.createStorageClass(m_cliIdentity, storageClass); + m_catalogue.StorageClass()->createStorageClass(m_cliIdentity, storageClass); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1841,13 +1844,13 @@ void RequestMessage::processStorageClass_Ch(cta::xrd::Response &response) auto vo = getOptional(OptionString::VO); if(comment) { - m_catalogue.modifyStorageClassComment(m_cliIdentity, scn, comment.value()); + m_catalogue.StorageClass()->modifyStorageClassComment(m_cliIdentity, scn, comment.value()); } if(cn) { - m_catalogue.modifyStorageClassNbCopies(m_cliIdentity, scn, cn.value()); + m_catalogue.StorageClass()->modifyStorageClassNbCopies(m_cliIdentity, scn, cn.value()); } if(vo){ - m_catalogue.modifyStorageClassVo(m_cliIdentity,scn,vo.value()); + m_catalogue.StorageClass()->modifyStorageClassVo(m_cliIdentity,scn,vo.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1861,7 +1864,7 @@ void RequestMessage::processStorageClass_Rm(cta::xrd::Response &response) auto &scn = getRequired(OptionString::STORAGE_CLASS); - m_catalogue.deleteStorageClass(scn); + m_catalogue.StorageClass()->deleteStorageClass(scn); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1913,7 +1916,7 @@ void RequestMessage::processTape_Add(cta::xrd::Response &response) tape.state = common::dataStructures::Tape::stringToState(state.value(), true); } tape.stateReason = stateReason; - m_catalogue.createTape(m_cliIdentity, tape); + m_catalogue.Tape()->createTape(m_cliIdentity, tape); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -1938,43 +1941,43 @@ void RequestMessage::processTape_Ch(cta::xrd::Response &response) auto verificationStatus = getOptional(OptionString::VERIFICATION_STATUS); if(mediaType) { - if (m_catalogue.getNbFilesOnTape(vid) != 0) { + if (m_catalogue.Tape()->getNbFilesOnTape(vid) != 0) { response.set_type(cta::xrd::Response::RSP_ERR_CTA); return; } - m_catalogue.modifyTapeMediaType(m_cliIdentity, vid, mediaType.value()); + m_catalogue.Tape()->modifyTapeMediaType(m_cliIdentity, vid, mediaType.value()); } if(vendor) { - m_catalogue.modifyTapeVendor(m_cliIdentity, vid, vendor.value()); + m_catalogue.Tape()->modifyTapeVendor(m_cliIdentity, vid, vendor.value()); } if(logicallibrary) { - m_catalogue.modifyTapeLogicalLibraryName(m_cliIdentity, vid, logicallibrary.value()); + m_catalogue.Tape()->modifyTapeLogicalLibraryName(m_cliIdentity, vid, logicallibrary.value()); } if(tapepool) { - m_catalogue.modifyTapeTapePoolName(m_cliIdentity, vid, tapepool.value()); + m_catalogue.Tape()->modifyTapeTapePoolName(m_cliIdentity, vid, tapepool.value()); } if(comment) { if(comment.value().empty()){ //If the comment is an empty string, the user meant to delete it comment = std::nullopt; } - m_catalogue.modifyTapeComment(m_cliIdentity, vid, comment); + m_catalogue.Tape()->modifyTapeComment(m_cliIdentity, vid, comment); } if(encryptionkeyName) { - m_catalogue.modifyTapeEncryptionKeyName(m_cliIdentity, vid, encryptionkeyName.value()); + m_catalogue.Tape()->modifyTapeEncryptionKeyName(m_cliIdentity, vid, encryptionkeyName.value()); } if(full) { - m_catalogue.setTapeFull(m_cliIdentity, vid, full.value()); + m_catalogue.Tape()->setTapeFull(m_cliIdentity, vid, full.value()); } if(state){ auto stateEnumValue = common::dataStructures::Tape::stringToState(state.value(), true); m_scheduler.triggerTapeStateChange(m_cliIdentity,vid,stateEnumValue,stateReason, m_lc); } if (dirty) { - m_catalogue.setTapeDirty(m_cliIdentity, vid, dirty.value()); + m_catalogue.Tape()->setTapeDirty(m_cliIdentity, vid, dirty.value()); } if (verificationStatus) { - m_catalogue.modifyTapeVerificationStatus(m_cliIdentity, vid, verificationStatus.value()); + m_catalogue.Tape()->modifyTapeVerificationStatus(m_cliIdentity, vid, verificationStatus.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -1991,7 +1994,7 @@ void RequestMessage::processTape_Rm(cta::xrd::Response &response) if (m_scheduler.isBeingRepacked(vid)) { throw cta::exception::UserError("Cannot delete tape " + vid + " because there is a repack for that tape"); } - m_catalogue.deleteTape(vid); + m_catalogue.Tape()->deleteTape(vid); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2004,7 +2007,7 @@ void RequestMessage::processTape_Reclaim(cta::xrd::Response &response) auto &vid = getRequired(OptionString::VID); - m_catalogue.reclaimTape(m_cliIdentity, vid, m_lc); + m_catalogue.Tape()->reclaimTape(m_cliIdentity, vid, m_lc); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2068,12 +2071,12 @@ void RequestMessage::processTapeFile_Rm(cta::xrd::Response &response) searchCriteria.diskInstance = instance.value(); } - auto archiveFile = m_catalogue.getArchiveFileForDeletion(searchCriteria); + auto archiveFile = m_catalogue.ArchiveFile()->getArchiveFileForDeletion(searchCriteria); grpc::EndpointMap endpoints(m_namespaceMap); auto diskFilePath = endpoints.getPath(archiveFile.diskInstance, archiveFile.diskFileId); archiveFile.diskFileInfo.path = diskFilePath; - m_catalogue.deleteTapeFileCopy(archiveFile, reason); + m_catalogue.TapeFile()->deleteTapeFileCopy(archiveFile, reason); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2089,7 +2092,7 @@ void RequestMessage::processTapePool_Add(cta::xrd::Response &response) auto &encrypted = getRequired(OptionBoolean::ENCRYPTED); auto supply = getOptional(OptionString::SUPPLY); - m_catalogue.createTapePool(m_cliIdentity, name, vo, ptn, encrypted, supply, comment); + m_catalogue.TapePool()->createTapePool(m_cliIdentity, name, vo, ptn, encrypted, supply, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2108,19 +2111,19 @@ void RequestMessage::processTapePool_Ch(cta::xrd::Response &response) auto supply = getOptional(OptionString::SUPPLY); if(comment) { - m_catalogue.modifyTapePoolComment(m_cliIdentity, name, comment.value()); + m_catalogue.TapePool()->modifyTapePoolComment(m_cliIdentity, name, comment.value()); } if(vo) { - m_catalogue.modifyTapePoolVo(m_cliIdentity, name, vo.value()); + m_catalogue.TapePool()->modifyTapePoolVo(m_cliIdentity, name, vo.value()); } if(ptn) { - m_catalogue.modifyTapePoolNbPartialTapes(m_cliIdentity, name, ptn.value()); + m_catalogue.TapePool()->modifyTapePoolNbPartialTapes(m_cliIdentity, name, ptn.value()); } if(encrypted) { - m_catalogue.setTapePoolEncryption(m_cliIdentity, name, encrypted.value()); + m_catalogue.TapePool()->setTapePoolEncryption(m_cliIdentity, name, encrypted.value()); } if(supply) { - m_catalogue.modifyTapePoolSupply(m_cliIdentity, name, supply.value()); + m_catalogue.TapePool()->modifyTapePoolSupply(m_cliIdentity, name, supply.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -2134,7 +2137,7 @@ void RequestMessage::processTapePool_Rm(cta::xrd::Response &response) auto &name = getRequired(OptionString::TAPE_POOL); - m_catalogue.deleteTapePool(name); + m_catalogue.TapePool()->deleteTapePool(name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2177,7 +2180,8 @@ void RequestMessage::processDiskSystem_Add(cta::xrd::Response &response) const auto &sleepTime = getRequired(OptionUInt64::SLEEP_TIME); const auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createDiskSystem(m_cliIdentity, name,diskInstance, diskInstanceSpace, fileRegexp, targetedFreeSpace, sleepTime, comment); + m_catalogue.DiskSystem()->createDiskSystem(m_cliIdentity, name,diskInstance, diskInstanceSpace, fileRegexp, + targetedFreeSpace, sleepTime, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2195,22 +2199,22 @@ void RequestMessage::processDiskSystem_Ch(cta::xrd::Response &response) const auto diskInstanceSpaceName = getOptional(OptionString::DISK_INSTANCE_SPACE); if(comment) { - m_catalogue.modifyDiskSystemComment(m_cliIdentity, name, comment.value()); + m_catalogue.DiskSystem()->modifyDiskSystemComment(m_cliIdentity, name, comment.value()); } if(fileRegexp) { - m_catalogue.modifyDiskSystemFileRegexp(m_cliIdentity, name, fileRegexp.value()); + m_catalogue.DiskSystem()->modifyDiskSystemFileRegexp(m_cliIdentity, name, fileRegexp.value()); } if (sleepTime) { - m_catalogue.modifyDiskSystemSleepTime(m_cliIdentity, name, sleepTime.value()); + m_catalogue.DiskSystem()->modifyDiskSystemSleepTime(m_cliIdentity, name, sleepTime.value()); } if(targetedFreeSpace) { - m_catalogue.modifyDiskSystemTargetedFreeSpace(m_cliIdentity, name, targetedFreeSpace.value()); + m_catalogue.DiskSystem()->modifyDiskSystemTargetedFreeSpace(m_cliIdentity, name, targetedFreeSpace.value()); } if (diskInstanceName) { - m_catalogue.modifyDiskSystemDiskInstanceName(m_cliIdentity, name, diskInstanceName.value()); + m_catalogue.DiskSystem()->modifyDiskSystemDiskInstanceName(m_cliIdentity, name, diskInstanceName.value()); } if (diskInstanceSpaceName) { - m_catalogue.modifyDiskSystemDiskInstanceSpaceName(m_cliIdentity, name, diskInstanceSpaceName.value()); + m_catalogue.DiskSystem()->modifyDiskSystemDiskInstanceSpaceName(m_cliIdentity, name, diskInstanceSpaceName.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -2222,7 +2226,7 @@ void RequestMessage::processDiskSystem_Rm(cta::xrd::Response &response) const auto &name = getRequired(OptionString::DISK_SYSTEM); - m_catalogue.deleteDiskSystem(name); + m_catalogue.DiskSystem()->deleteDiskSystem(name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2245,7 +2249,7 @@ void RequestMessage::processDiskInstance_Add(cta::xrd::Response &response) const auto &name = getRequired(OptionString::DISK_INSTANCE); const auto &comment = getRequired(OptionString::COMMENT); - m_catalogue.createDiskInstance(m_cliIdentity, name, comment); + m_catalogue.DiskInstance()->createDiskInstance(m_cliIdentity, name, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2258,7 +2262,7 @@ void RequestMessage::processDiskInstance_Ch(cta::xrd::Response &response) const auto comment = getOptional(OptionString::COMMENT); if(comment) { - m_catalogue.modifyDiskInstanceComment(m_cliIdentity, name, comment.value()); + m_catalogue.DiskInstance()->modifyDiskInstanceComment(m_cliIdentity, name, comment.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -2270,7 +2274,7 @@ void RequestMessage::processDiskInstance_Rm(cta::xrd::Response &response) const auto &name = getRequired(OptionString::DISK_INSTANCE); - m_catalogue.deleteDiskInstance(name); + m_catalogue.DiskInstance()->deleteDiskInstance(name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2296,7 +2300,8 @@ void RequestMessage::processDiskInstanceSpace_Add(cta::xrd::Response &response) const auto &freeSpaceQueryURL = getRequired(OptionString::FREE_SPACE_QUERY_URL); const auto refreshInterval = getRequired(OptionUInt64::REFRESH_INTERVAL); - m_catalogue.createDiskInstanceSpace(m_cliIdentity, name, diskInstance, freeSpaceQueryURL, refreshInterval, comment); + m_catalogue.DiskInstanceSpace()->createDiskInstanceSpace(m_cliIdentity, name, diskInstance, freeSpaceQueryURL, + refreshInterval, comment); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2312,13 +2317,16 @@ void RequestMessage::processDiskInstanceSpace_Ch(cta::xrd::Response &response) const auto refreshInterval = getOptional(OptionUInt64::REFRESH_INTERVAL); if(comment) { - m_catalogue.modifyDiskInstanceSpaceComment(m_cliIdentity, name, diskInstance, comment.value()); + m_catalogue.DiskInstanceSpace()->modifyDiskInstanceSpaceComment(m_cliIdentity, name, diskInstance, + comment.value()); } if(freeSpaceQueryURL) { - m_catalogue.modifyDiskInstanceSpaceQueryURL(m_cliIdentity, name, diskInstance, freeSpaceQueryURL.value()); + m_catalogue.DiskInstanceSpace()->modifyDiskInstanceSpaceQueryURL(m_cliIdentity, name, diskInstance, + freeSpaceQueryURL.value()); } if(refreshInterval) { - m_catalogue.modifyDiskInstanceSpaceRefreshInterval(m_cliIdentity, name, diskInstance, refreshInterval.value()); + m_catalogue.DiskInstanceSpace()->modifyDiskInstanceSpaceRefreshInterval(m_cliIdentity, name, diskInstance, + refreshInterval.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); @@ -2331,7 +2339,7 @@ void RequestMessage::processDiskInstanceSpace_Rm(cta::xrd::Response &response) const auto &name = getRequired(OptionString::DISK_INSTANCE_SPACE); const auto &diskInstance = getRequired(OptionString::DISK_INSTANCE); - m_catalogue.deleteDiskInstanceSpace(name, diskInstance); + m_catalogue.DiskInstanceSpace()->deleteDiskInstanceSpace(name, diskInstance); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2359,7 +2367,7 @@ void RequestMessage::processVirtualOrganization_Add(cta::xrd::Response &response vo.maxFileSize = m_archiveFileMaxSize; } - m_catalogue.createVirtualOrganization(m_cliIdentity,vo); + m_catalogue.VO()->createVirtualOrganization(m_cliIdentity,vo); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2375,19 +2383,19 @@ void RequestMessage::processVirtualOrganization_Ch(cta::xrd::Response &response) const auto diskInstanceName = getOptional(OptionString::DISK_INSTANCE); if(comment) - m_catalogue.modifyVirtualOrganizationComment(m_cliIdentity,name,comment.value()); + m_catalogue.VO()->modifyVirtualOrganizationComment(m_cliIdentity,name,comment.value()); if(readMaxDrives) - m_catalogue.modifyVirtualOrganizationReadMaxDrives(m_cliIdentity,name,readMaxDrives.value()); + m_catalogue.VO()->modifyVirtualOrganizationReadMaxDrives(m_cliIdentity,name,readMaxDrives.value()); if(writeMaxDrives) - m_catalogue.modifyVirtualOrganizationWriteMaxDrives(m_cliIdentity,name,writeMaxDrives.value()); + m_catalogue.VO()->modifyVirtualOrganizationWriteMaxDrives(m_cliIdentity,name,writeMaxDrives.value()); if(maxFileSize) - m_catalogue.modifyVirtualOrganizationMaxFileSize(m_cliIdentity,name,maxFileSize.value()); + m_catalogue.VO()->modifyVirtualOrganizationMaxFileSize(m_cliIdentity,name,maxFileSize.value()); - if(diskInstanceName) - m_catalogue.modifyVirtualOrganizationDiskInstanceName(m_cliIdentity, name, diskInstanceName.value()); + if(diskInstanceName) + m_catalogue.VO()->modifyVirtualOrganizationDiskInstanceName(m_cliIdentity, name, diskInstanceName.value()); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2397,7 +2405,7 @@ void RequestMessage::processVirtualOrganization_Rm(cta::xrd::Response& response) const auto &name = getRequired(OptionString::VO); - m_catalogue.deleteVirtualOrganization(name); + m_catalogue.VO()->deleteVirtualOrganization(name); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2421,7 +2429,7 @@ std::string RequestMessage::setDriveState(const std::string ®ex, const cta::c cta::utils::Regex driveNameRegex(regex.c_str()); - const auto tapeDriveNames = m_catalogue.getTapeDriveNames(); + const auto tapeDriveNames = m_catalogue.DriveState()->getTapeDriveNames(); bool is_found = false; for(auto tapeDriveName: tapeDriveNames) @@ -2523,7 +2531,7 @@ void RequestMessage::processRecycleTapeFile_Restore(cta::xrd::Response& response if(!has_any){ throw cta::exception::UserError("Must specify at least one of the following search options: vid, fxid, fxidfile or archiveFileId"); } - m_catalogue.restoreFileInRecycleLog(searchCriteria, std::to_string(fid)); + m_catalogue.FileRecycleLog()->restoreFileInRecycleLog(searchCriteria, std::to_string(fid)); response.set_type(cta::xrd::Response::RSP_SUCCESS); } @@ -2545,7 +2553,8 @@ void RequestMessage::processModifyArchiveFile(cta::xrd::Response& response) { } // call is from cta-eos-namespace-inject if(fxId && diskInstance) { - m_catalogue.modifyArchiveFileFxIdAndDiskInstance(cta::utils::toUint64(archiveFileIds[0]), fxId.value(), diskInstance.value()); + m_catalogue.ArchiveFile()->modifyArchiveFileFxIdAndDiskInstance(cta::utils::toUint64(archiveFileIds[0]), + fxId.value(), diskInstance.value()); } response.set_type(cta::xrd::Response::RSP_SUCCESS); } catch(exception::UserError &ue) { -- GitLab