diff --git a/rdbms/wrapper/MysqlStmt.cpp b/rdbms/wrapper/MysqlStmt.cpp index 21c35f68ab2ae5101f5cf67568adeacc76f479cf..a73c0717cf67118f5c5d6a447e7e575396810e4c 100644 --- a/rdbms/wrapper/MysqlStmt.cpp +++ b/rdbms/wrapper/MysqlStmt.cpp @@ -600,7 +600,7 @@ bool MysqlStmt::do_bind_results() { case MYSQL_TYPE_STRING: case MYSQL_TYPE_LONG_BLOB: { - const unsigned int buf_size = m_fields_info->maxsizes[i] + 1; + const unsigned int buf_size = m_fields_info->maxsizes[i] + 1; // +1 For CR+LF if (buf_size < m_fields_info->maxsizes[i]) { throw exception::Exception(std::string(__FUNCTION__) + " buf size < m_fields_info->maxsizes[" + std::to_string(i) + "]"); } diff --git a/statistics/CMakeLists.txt b/statistics/CMakeLists.txt index 4982069fa05e77651053b9f1ce4846f7790b4783..ae14e311c7a3043db3ab735e319523f293a31b7c 100644 --- a/statistics/CMakeLists.txt +++ b/statistics/CMakeLists.txt @@ -22,25 +22,6 @@ include_directories (${ORACLE-INSTANTCLIENT_INCLUDE_DIRS}) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow") -set (STATISTICS_LIB_SRC_FILES - StatisticsSchema.cpp - TapeStatisticsUpdater.cpp -) - -add_library (ctastatistics SHARED - ${STATISTICS_LIB_SRC_FILES}) - -set_property(TARGET ctastatistics PROPERTY SOVERSION "${CTA_SOVERSION}") -set_property(TARGET ctastatistics PROPERTY VERSION "${CTA_LIBVERSION}") - -install (TARGETS ctastatistics DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) - -target_link_libraries (ctastatistics - ctacatalogue - ctacommon - ctaschemachecker - ctardbms) - add_custom_command (OUTPUT mysql_statistics_schema.sql COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/common_statistics_schema.sql @@ -62,6 +43,27 @@ add_custom_command(OUTPUT MysqlStatisticsSchema.cpp COMMAND sed -e '/CTA_SQL_SCHEMA/r mysql_statistics_schema.cpp' ${CMAKE_CURRENT_SOURCE_DIR}/MysqlStatisticsSchema.before_SQL.cpp > MysqlStatisticsSchema.cpp DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/MysqlStatisticsSchema.before_SQL.cpp mysql_statistics_schema.cpp) +set (STATISTICS_LIB_SRC_FILES + StatisticsSchema.cpp + MysqlStatisticsSchema.cpp + StatisticsSchemaFactory.cpp + TapeStatisticsUpdater.cpp +) + +add_library (ctastatistics SHARED + ${STATISTICS_LIB_SRC_FILES}) + +set_property(TARGET ctastatistics PROPERTY SOVERSION "${CTA_SOVERSION}") +set_property(TARGET ctastatistics PROPERTY VERSION "${CTA_LIBVERSION}") + +install (TARGETS ctastatistics DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) + +target_link_libraries (ctastatistics + ctacatalogue + ctacommon + ctaschemachecker + ctardbms) + install (FILES ${CMAKE_SOURCE_DIR}/catalogue/cta-catalogue.conf.example DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/cta PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) diff --git a/statistics/StatisticsSaveCmd.cpp b/statistics/StatisticsSaveCmd.cpp index 3f75b95f279b5ee2a2f7dd0a30d9b30220ded290..b7919b244f74b653b21bfea6fc21c1f89d32f557 100644 --- a/statistics/StatisticsSaveCmd.cpp +++ b/statistics/StatisticsSaveCmd.cpp @@ -19,10 +19,9 @@ #include "rdbms/ConnPool.hpp" #include "rdbms/AutocommitMode.hpp" #include "StatisticsSaveCmd.hpp" -#include "StatisticsSchema.hpp" #include "catalogue/SchemaChecker.hpp" -#include "MysqlStatisticsSchema.hpp" - +#include "StatisticsSchemaFactory.hpp" +#include <algorithm> namespace cta { namespace statistics { @@ -51,16 +50,32 @@ int StatisticsSaveCmd::exceptionThrowingMain(const int argc, char *const *const printUsage(m_out); return 0; } + + verifyCmdLineArgs(cmdLineArgs); const uint64_t maxNbConns = 1; - - auto loginCatalogue = rdbms::Login::parseFile(cmdLineArgs.catalogueDbConfigPath); - rdbms::ConnPool catalogueConnPool(loginCatalogue, maxNbConns); - auto catalogueConn = catalogueConnPool.getConn(); auto loginStatistics = rdbms::Login::parseFile(cmdLineArgs.statisticsDbConfigPath); rdbms::ConnPool statisticsConnPool(loginStatistics, maxNbConns); auto statisticsConn = statisticsConnPool.getConn(); + + auto statisticsSchema = StatisticsSchemaFactory::create(loginStatistics.dbType); + + if(cmdLineArgs.buildDatabase){ + buildStatisticsDatabase(statisticsConn,*statisticsSchema); + return EXIT_SUCCESS; + } + + if(cmdLineArgs.dropDatabase){ + if(userConfirmDropStatisticsSchemaFromDb(loginStatistics)){ + dropStatisticsDatabase(statisticsConn); + } + return EXIT_SUCCESS; + } + + auto loginCatalogue = rdbms::Login::parseFile(cmdLineArgs.catalogueDbConfigPath); + rdbms::ConnPool catalogueConnPool(loginCatalogue, maxNbConns); + auto catalogueConn = catalogueConnPool.getConn(); SchemaChecker::Builder catalogueCheckerBuilder("catalogue",loginCatalogue.dbType,catalogueConn); std::unique_ptr<cta::catalogue::SchemaChecker> catalogueChecker; @@ -73,9 +88,8 @@ int StatisticsSaveCmd::exceptionThrowingMain(const int argc, char *const *const } SchemaChecker::Builder statisticsCheckerBuilder("statistics",loginStatistics.dbType,statisticsConn); - cta::statistics::MysqlStatisticsSchema mysqlSchema; std::unique_ptr<SchemaChecker> statisticsChecker = - statisticsCheckerBuilder.useCppSchemaStatementsReader(mysqlSchema) + statisticsCheckerBuilder.useCppSchemaStatementsReader(*statisticsSchema) .useSQLiteSchemaComparer() .build(); statisticsChecker->compareTablesLocatedInSchema(); @@ -102,6 +116,57 @@ void StatisticsSaveCmd::printUsage(std::ostream &os) { StatisticsSaveCmdLineArgs::printUsage(os); } +void StatisticsSaveCmd::verifyCmdLineArgs(const StatisticsSaveCmdLineArgs& cmdLineArgs) const { + if(cmdLineArgs.buildDatabase && cmdLineArgs.dropDatabase){ + throw cta::exception::Exception("--build and --drop are mutually exclusive."); + } + if(cmdLineArgs.buildDatabase && !cmdLineArgs.catalogueDbConfigPath.empty()){ + throw cta::exception::Exception("The catalogue database configuration file should not be provided when --build flag is set."); + } + if(cmdLineArgs.dropDatabase && !cmdLineArgs.catalogueDbConfigPath.empty()){ + throw cta::exception::Exception("The catalogue database configuration file should not be provided when --drop flag is set."); + } + if(cmdLineArgs.buildDatabase && cmdLineArgs.statisticsDbConfigPath.empty()){ + throw cta::exception::Exception("The statistics database configuration file should be provided."); + } + if(cmdLineArgs.dropDatabase && cmdLineArgs.statisticsDbConfigPath.empty()){ + throw cta::exception::Exception("The statistics database configuration file should be provided."); + } +} + +void StatisticsSaveCmd::buildStatisticsDatabase(cta::rdbms::Conn& statisticsDatabaseConn, const StatisticsSchema& statisticsSchema) { + statisticsDatabaseConn.executeNonQuery(statisticsSchema.sql); +} + +bool StatisticsSaveCmd::userConfirmDropStatisticsSchemaFromDb(const rdbms::Login &dbLogin) { + m_out << "WARNING" << std::endl; + m_out << "You are about to drop the schema of the statistics database" << std::endl; + m_out << " Database name: " << dbLogin.database << std::endl; + m_out << "Are you sure you want to continue?" << std::endl; + + std::string userResponse; + while(userResponse != "yes" && userResponse != "no") { + m_out << "Please type either \"yes\" or \"no\" > "; + std::getline(m_in, userResponse); + } + return userResponse == "yes"; +} + +void StatisticsSaveCmd::dropStatisticsDatabase(cta::rdbms::Conn& statisticsDatabaseConn) { + try { + std::list<std::string> tablesInDb = statisticsDatabaseConn.getTableNames(); + std::list<std::string> statisticsTables = {"CTA_STATISTICS"}; + for(auto & tableToDrop: statisticsTables){ + const bool tableToDropIsInDb = (tablesInDb.end() != std::find(tablesInDb.begin(), tablesInDb.end(), tableToDrop)); + if(tableToDropIsInDb) { + statisticsDatabaseConn.executeNonQuery(std::string("DROP TABLE ") + tableToDrop); + m_out << "Dropped table " << tableToDrop << std::endl; + } + } + } catch(exception::Exception &ex) { + throw exception::Exception(std::string(__FUNCTION__) + " failed: " + ex.getMessage().str()); + } +} } // namespace statistics } // namespace cta diff --git a/statistics/StatisticsSaveCmd.hpp b/statistics/StatisticsSaveCmd.hpp index 56627387112e9800ae7eae231d144197a9114017..7d46f9c977473b29fe5af7878b422cbe279900b6 100644 --- a/statistics/StatisticsSaveCmd.hpp +++ b/statistics/StatisticsSaveCmd.hpp @@ -23,6 +23,7 @@ #include "rdbms/Conn.hpp" #include "rdbms/Login.hpp" #include "StatisticsSaveCmdLineArgs.hpp" +#include "StatisticsSchema.hpp" namespace cta { namespace statistics { @@ -75,6 +76,14 @@ private: */ bool tableExists(const std::string tableName, rdbms::Conn &conn) const; + void verifyCmdLineArgs(const StatisticsSaveCmdLineArgs& cmdLineArgs) const; + + void buildStatisticsDatabase(cta::rdbms::Conn &statisticsDatabaseConn,const StatisticsSchema & statisticsSchema); + + bool userConfirmDropStatisticsSchemaFromDb(const rdbms::Login &dbLogin); + + void dropStatisticsDatabase(cta::rdbms::Conn &statisticsDatabaseConn); + }; // class VerifySchemaCmd } // namespace statistics diff --git a/statistics/StatisticsSaveCmdLineArgs.cpp b/statistics/StatisticsSaveCmdLineArgs.cpp index 9318531553e55a075308b55c696c738e3cd892a3..34988e893b3bd55a77850315bf22ea46227d01cc 100644 --- a/statistics/StatisticsSaveCmdLineArgs.cpp +++ b/statistics/StatisticsSaveCmdLineArgs.cpp @@ -35,6 +35,8 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const static struct option longopts[] = { {"catalogueconf",required_argument,NULL,'c'}, {"statisticsconf",required_argument,NULL,'s'}, + {"build",no_argument, NULL, 'b'}, + {"drop", no_argument, NULL, 'd'}, {"help", no_argument, NULL, 'h'}, {NULL , 0, NULL, 0} }; @@ -44,7 +46,7 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const opterr = 0; int opt = 0; - while((opt = getopt_long(argc, argv, ":hc:s:", longopts, NULL)) != -1) { + while((opt = getopt_long(argc, argv, ":hbdc:s:", longopts, NULL)) != -1) { switch(opt) { case 'h': help = true; @@ -55,6 +57,12 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const case 's': statisticsDbConfigPath = optarg; break; + case 'b': + buildDatabase = true; + break; + case 'd': + dropDatabase = true; + break; case ':': // Missing parameter { exception::CommandLineNotParsed ex; @@ -91,9 +99,9 @@ StatisticsSaveCmdLineArgs::StatisticsSaveCmdLineArgs(const int argc, char *const const int nbArgs = argc - 1; // Check the number of arguments - if(nbArgs != 4) { + if(nbArgs < 2 ) { exception::CommandLineNotParsed ex; - ex.getMessage() << "Wrong number of command-line arguments: expected=4 actual=" << nbArgs; + ex.getMessage() << "At least 2 arguments should be provided." << nbArgs; throw ex; } } diff --git a/statistics/StatisticsSaveCmdLineArgs.hpp b/statistics/StatisticsSaveCmdLineArgs.hpp index 29f53217a4b062fe19e9142b76771af9dd6ba74b..6dc083a0314a68e9c3e260f9c86d8e4b0be35a30 100644 --- a/statistics/StatisticsSaveCmdLineArgs.hpp +++ b/statistics/StatisticsSaveCmdLineArgs.hpp @@ -45,6 +45,16 @@ struct StatisticsSaveCmdLineArgs { */ std::string statisticsDbConfigPath; + /** + * True if the --build flag has been provided + */ + bool buildDatabase = false; + + /** + * True if the --drop flag has been provided + */ + bool dropDatabase = false; + /** * Constructor that parses the specified command-line arguments. * diff --git a/statistics/StatisticsSchemaFactory.cpp b/statistics/StatisticsSchemaFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc667dca588df60dc16c013c6f85e13cd58db892 --- /dev/null +++ b/statistics/StatisticsSchemaFactory.cpp @@ -0,0 +1,36 @@ +/** + * The CERN Tape Archive (CTA) project + * Copyright © 2018 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "StatisticsSchemaFactory.hpp" +#include "MysqlStatisticsSchema.hpp" +#include "common/exception/Exception.hpp" + +namespace cta { + namespace statistics { + + std::unique_ptr<StatisticsSchema> StatisticsSchemaFactory::create(cta::rdbms::Login::DbType dbType){ + switch(dbType){ + case cta::rdbms::Login::DbType::DBTYPE_MYSQL: + return std::unique_ptr<MysqlStatisticsSchema>(new MysqlStatisticsSchema()); + default: + throw cta::exception::Exception("Only Mysql statistics schema is supported."); + } + } + } +} + diff --git a/statistics/StatisticsSchemaFactory.hpp b/statistics/StatisticsSchemaFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9c1033f8ca38ea29ba2e91e676c145d25147f055 --- /dev/null +++ b/statistics/StatisticsSchemaFactory.hpp @@ -0,0 +1,34 @@ +/** + * The CERN Tape Archive (CTA) project + * Copyright © 2018 CERN + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include <memory> + +#include "StatisticsSchema.hpp" +#include "rdbms/Login.hpp" + +namespace cta { + namespace statistics{ + class StatisticsSchemaFactory { + public: + static std::unique_ptr<StatisticsSchema> create(cta::rdbms::Login::DbType dbType); + }; + } +} + diff --git a/statistics/common_statistics_schema.sql b/statistics/common_statistics_schema.sql index bc7d67482c9b3663e0bcc1c6936d8cbe9016c457..deecea0b3a1973921816c3125905ec638b880fa8 100644 --- a/statistics/common_statistics_schema.sql +++ b/statistics/common_statistics_schema.sql @@ -1,5 +1,8 @@ CREATE TABLE CTA_STATISTICS( + GID UINT32TYPE DEFAULT 0 CONSTRAINT CTA_STATISTICS_GID_NN NOT NULL, + TIMESTAMP UINT64TYPE DEFAULT 0 CONSTRAINT CTA_STATISTICS_TS_NN NOT NULL, NB_MASTER_FILES UINT64TYPE NOT NULL, MASTER_DATA_BYTES UINT64TYPE NOT NULL, - UPDATE_TIME UINT64TYPE NOT NULL + UPDATE_TIME UINT64TYPE NOT NULL, + CONSTRAINT CTA_STATISTICS_GID_TS_PK PRIMARY KEY (GID, TIMESTAMP) ); \ No newline at end of file