diff --git a/CMakeLists.txt b/CMakeLists.txt index 4fd4155..75c121f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,7 +129,7 @@ add_subdirectory(src/common) add_subdirectory(src/machinery) add_subdirectory(lib/pbl) add_subdirectory(lib/glob2regex) -add_subdirectory(src/backends/postgresql) +add_subdirectory(src/backends) #Actions add_subdirectory(src/main) diff --git a/include/backends/backend_loader.hpp b/include/backends/backend_loader.hpp new file mode 100644 index 0000000..70bb592 --- /dev/null +++ b/include/backends/backend_loader.hpp @@ -0,0 +1,59 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +#ifndef id756A258A98B24B0DB2529BCEEC5137E2 +#define id756A258A98B24B0DB2529BCEEC5137E2 + +#include +#include +#include + +namespace YAML { + class Node; +} //namespace YAML + +namespace dindb { + class Backend; + + using BackendPtr = std::unique_ptr; + + class BackendPlugin { + public: + BackendPlugin ( void ); + BackendPlugin ( BackendPlugin&& ) = default; + BackendPlugin ( const std::string& parSOPath, const YAML::Node* parConfig ); + ~BackendPlugin ( void ) noexcept; + + const boost::string_ref& name ( void ) const; + Backend& backend ( void ); + const Backend& backend ( void ) const; + bool is_loaded ( void ) const; + + BackendPlugin& operator= ( BackendPlugin&& ) = default; + + private: + using SoHandle = std::unique_ptr; + + SoHandle m_lib; + BackendPtr m_backend; + boost::string_ref m_name; + }; + + std::string backend_name ( const std::string& parSOPath ); +} //namespace dindb + +#endif diff --git a/include/backends/db_backend.hpp b/include/backends/db_backend.hpp new file mode 100644 index 0000000..cc79b43 --- /dev/null +++ b/include/backends/db_backend.hpp @@ -0,0 +1,49 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +#ifndef id7506CA9825454B80856154ACFE8A9DE2 +#define id7506CA9825454B80856154ACFE8A9DE2 + +#include "backends/backend_loader.hpp" +#include +#include +#include +#include + +namespace dindb { + using GroupIDType = uint32_t; + using FileIDType = uint64_t; + + constexpr const GroupIDType InvalidGroupID = 0; + constexpr const FileIDType InvalidFileID = 0; + + class Backend { + public: + Backend ( void ) = default; + virtual ~Backend ( void ) noexcept = default; + + virtual void tag_files ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const = 0; + virtual void tag_files ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const = 0; + virtual void delete_tags ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const = 0; + virtual void delete_tags ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const = 0; + virtual void delete_all_tags ( const std::vector& parFiles, GroupIDType parSet ) const = 0; + virtual void delete_all_tags ( const std::vector& parRegexes, GroupIDType parSet ) const = 0; + + }; +} //namespace dindb + +#endif diff --git a/include/backends/exposed_functions.hpp b/include/backends/exposed_functions.hpp new file mode 100644 index 0000000..a1b21e9 --- /dev/null +++ b/include/backends/exposed_functions.hpp @@ -0,0 +1,33 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +#ifndef idA9E47E37E2FA49EE84C2E93FB701C368 +#define idA9E47E37E2FA49EE84C2E93FB701C368 + +namespace YAML { + class Node; +} //namespace YAML + +namespace dindb { + class Backend; +} //namespace dindb + +extern "C" dindb::Backend* dindexer_create_backend ( const YAML::Node* parConfig ); +extern "C" void dindexer_destroy_backend ( dindb::Backend* parDele ); +extern "C" const char* dindexer_backend_name ( void ); + +#endif diff --git a/src/backends/CMakeLists.txt b/src/backends/CMakeLists.txt new file mode 100644 index 0000000..eae379f --- /dev/null +++ b/src/backends/CMakeLists.txt @@ -0,0 +1,28 @@ +project(${bare_name}-backend CXX) + +add_library(${PROJECT_NAME} STATIC + backend_loader.cpp +) + +target_include_directories(${PROJECT_NAME} + PUBLIC ${DINDEXER_PUB_INCLUDE_DIR} +) +target_include_directories(${PROJECT_NAME} SYSTEM + PUBLIC ${YAMLCPP_INCLUDE_DIR} +) + +target_link_libraries(${PROJECT_NAME} + PRIVATE ${bare_name}-if + PUBLIC ${YAMLCPP_LIBRARY} + PUBLIC dl +) + +#install(TARGETS ${PROJECT_NAME} +# LIBRARY DESTINATION lib +# RUNTIME DESTINATION bin +# ARCHIVE DESTINATION lib/static +#) + +add_subdirectory(postgresql) + +add_dependencies(${PROJECT_NAME} ${bare_name}-backend-postgresql) diff --git a/src/backends/backend_loader.cpp b/src/backends/backend_loader.cpp new file mode 100644 index 0000000..a6eba27 --- /dev/null +++ b/src/backends/backend_loader.cpp @@ -0,0 +1,107 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +//See: +// http://stackoverflow.com/questions/496664/c-dynamic-shared-library-on-linux + +#include "backends/backend_loader.hpp" +#include "backends/exposed_functions.hpp" +#include +#include +#include + +namespace dindb { + namespace { + BackendPtr load_backend (void* parSOHandle, const YAML::Node* parConfig) { + typedef decltype(&dindexer_create_backend) CreateBackendFun; + typedef decltype(&dindexer_destroy_backend) DeleteBackendFun; + + assert(parSOHandle); + assert(parConfig); + + auto create = reinterpret_cast(dlsym(parSOHandle, "dindexer_create_backend")); + auto destroy = reinterpret_cast(dlsym(parSOHandle, "dindexer_destroy_backend")); + + return BackendPtr(create(parConfig), destroy); + } + + const char* backend_name (void* parSOHandle) { + typedef decltype(&dindexer_backend_name) GetNameFun; + + assert(parSOHandle); + + auto get_name = reinterpret_cast(dlsym(parSOHandle, "dindexer_backend_name")); + return get_name(); + } + + void nop_destroy (Backend*) { + } + } //unnamed namespace + + std::string backend_name (const std::string& parSOPath) { + assert(not parSOPath.empty()); + using SoHandle = std::unique_ptr; + + auto handle = SoHandle(dlopen(parSOPath.c_str(), RTLD_LAZY), &dlclose); + return backend_name(handle.get()); + } + + BackendPlugin::BackendPlugin() : + m_lib(nullptr, &dlclose), + m_backend(nullptr, &nop_destroy), + m_name() + { + } + + BackendPlugin::BackendPlugin (const std::string& parSOPath, const YAML::Node* parConfig) : + m_lib(dlopen(parSOPath.c_str(), RTLD_LAZY), &dlclose), + m_backend(load_backend(m_lib.get(), parConfig)), + m_name(backend_name(m_lib.get())) + { + } + + BackendPlugin::~BackendPlugin() noexcept { + } + + const boost::string_ref& BackendPlugin::name() const { + return m_name; + } + + Backend& BackendPlugin::backend() { + assert(m_lib); + assert(m_backend); + if (not m_backend) { + throw std::bad_function_call(); + } + + return *m_backend; + } + + const Backend& BackendPlugin::backend() const { + assert(m_lib); + assert(m_backend); + if (not m_backend) { + throw std::bad_function_call(); + } + + return *m_backend; + } + + bool BackendPlugin::is_loaded() const { + return static_cast(m_backend); + } +} //namespace dindb diff --git a/src/backends/postgresql/CMakeLists.txt b/src/backends/postgresql/CMakeLists.txt index 8238350..40eb8e3 100644 --- a/src/backends/postgresql/CMakeLists.txt +++ b/src/backends/postgresql/CMakeLists.txt @@ -6,6 +6,7 @@ add_library(${PROJECT_NAME} STATIC locate.cpp scan.cpp dbsource.cpp + backend_postgresql.cpp ) target_include_directories(${PROJECT_NAME} diff --git a/src/backends/postgresql/backend_postgresql.cpp b/src/backends/postgresql/backend_postgresql.cpp new file mode 100644 index 0000000..7ccf8cc --- /dev/null +++ b/src/backends/postgresql/backend_postgresql.cpp @@ -0,0 +1,102 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +#include "backend_postgresql.hpp" +#include "backends/exposed_functions.hpp" +#include "pq/connection.hpp" +#include +#include +#include +#include + +namespace YAML { + template<> + struct convert { + static Node encode (const dindb::Settings& parSettings) { + Node node; + node["address"] = parSettings.address; + node["username"] = parSettings.username; + node["password"] = parSettings.password; + node["port"] = parSettings.port; + node["dbname"] = parSettings.dbname; + return node; + } + + static bool decode (const Node& parNode, dindb::Settings& parSettings) { + if (not parNode.IsMap() or parNode.size() != 5) { + return false; + } + + parSettings.address = parNode["address"].as(); + parSettings.username = parNode["username"].as(); + parSettings.password = parNode["password"].as(); + parSettings.dbname = parNode["dbname"].as(); + parSettings.port = parNode["port"].as(); + return true; + } + }; +} //namespace YAML + +namespace dindb { + BackendPostgreSql::BackendPostgreSql (std::string&& parUser, std::string&& parPass, std::string&& parDB, std::string&& parAddr, uint16_t parPort) : + m_conn(new pq::Connection(std::move(parUser), std::move(parPass), std::move(parDB), std::move(parAddr), parPort)) + { + assert(m_conn); + m_conn->connect(); + } + + BackendPostgreSql::~BackendPostgreSql() noexcept { + m_conn->disconnect(); + } + + void BackendPostgreSql::tag_files (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) const { + if (InvalidGroupID != parSet) { + const std::string query = + "UPDATE \"files\" SET \"tags\" = ARRAY(SELECT DISTINCT UNNEST(\"tags\" || $1) ORDER BY 1) WHERE \"id\"=ANY($2) AND \"group_id\"=$3;"; + m_conn->query(query, parTags, parFiles, parSet); + } + else { + const std::string query = + "UPDATE \"files\" SET \"tags\" = ARRAY(SELECT DISTINCT UNNEST(\"tags\" || $1) ORDER BY 1) WHERE \"id\"=ANY($2);"; + m_conn->query(query, parTags, parFiles); + } + } + + void BackendPostgreSql::tag_files (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) const { + } + + void BackendPostgreSql::delete_tags (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) const { + } + + void BackendPostgreSql::delete_tags (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) const { + } + + void BackendPostgreSql::delete_all_tags (const std::vector& parFiles, GroupIDType parSet) const { + } + + void BackendPostgreSql::delete_all_tags (const std::vector& parRegexes, GroupIDType parSet) const { + } +} //namespace dindb + +extern "C" dindb::Backend* create_backend (const YAML::Node*) { + return new dindb::BackendPostgreSql("A", "B", "C", "D", 1); +} + +extern "C" void destroy_backend (dindb::Backend* parDele) { + if (parDele) + delete parDele; +} diff --git a/src/backends/postgresql/backend_postgresql.hpp b/src/backends/postgresql/backend_postgresql.hpp new file mode 100644 index 0000000..bce0e7c --- /dev/null +++ b/src/backends/postgresql/backend_postgresql.hpp @@ -0,0 +1,49 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" 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. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT 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 "dindexer". If not, see . + */ + +#ifndef idBE5BBAFEC7334F39AC9338F193703341 +#define idBE5BBAFEC7334F39AC9338F193703341 + +#include "backends/db_backend.hpp" +#include +#include +#include + +namespace pq { + class Connection; +} //namespace pq + +namespace dindb { + class BackendPostgreSql : public Backend { + public: + BackendPostgreSql ( BackendPostgreSql&& ) = default; + BackendPostgreSql ( std::string&& parUser, std::string&& parPass, std::string&& parDB, std::string&& parAddr, uint16_t parPort ); + virtual ~BackendPostgreSql ( void ) noexcept; + + virtual void tag_files ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const override; + virtual void tag_files ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const override; + virtual void delete_tags ( const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet ) const override; + virtual void delete_tags ( const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet ) const override; + virtual void delete_all_tags ( const std::vector& parFiles, GroupIDType parSet ) const override; + virtual void delete_all_tags ( const std::vector& parRegexes, GroupIDType parSet ) const override; + + private: + std::unique_ptr m_conn; + }; +} //namespace dindb + +#endif diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index e41e3b5..724d45f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -19,8 +19,6 @@ target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE ${Readline_INCLUDE_DIR} ) -string(TOLOWER "${DINDEXER_DB_BACKEND}" DINDEXER_DB_BACKEND_LOWERCASE) - target_link_libraries(${PROJECT_NAME} PRIVATE ${bare_name}-if PRIVATE ${YAMLCPP_LIBRARY} diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt index 1b16abb..8f0f1d8 100644 --- a/src/main/CMakeLists.txt +++ b/src/main/CMakeLists.txt @@ -12,7 +12,6 @@ add_executable(${PROJECT_NAME} make_timestamp(${bare_name} timestamp.h.in) target_include_directories(${PROJECT_NAME} - PRIVATE ${CMAKE_SOURCE_DIR}/include PRIVATE ${CMAKE_SOURCE_DIR}/lib/pbl/pbl/src/src PRIVATE ${CMAKE_CURRENT_BINARY_DIR} )