Loading include/daemon/backend/data/pmdk/pool.hpp 0 → 100644 +139 −0 Original line number Diff line number Diff line /* Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany This software was partially supported by the EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). This software was partially supported by the ADA-FS project under the SPPEXA project funded by the DFG. SPDX-License-Identifier: MIT */ #ifndef GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP #define GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP #include <spdlog/spdlog.h> #include <boost/filesystem.hpp> namespace fs = boost::filesystem; namespace pmdk { /** * This class implements a RAII-enabled non-volatile memory pool based on * Intel's PMDK C library. */ class pool { public: /** * Create a pool of non-volatile memory of a fixed `size` under * `parent_dir`. Give it a random name. * * @param[in] parent_dir the parent directory where the memory pool backing * file will be stored * @param[in] size the maximum capacity in bytes of the pool * @returns the newly created pool */ pool(const fs::path& parent_dir, std::size_t size) noexcept; pool(pool&& rhs) = default; pool(const pool& other) = delete; pool& operator=(pool&& rhs) = default; pool& operator=(const pool& other) = delete; /** * Destroy an existing pool. */ ~pool(); /** * Returns the path to a pool's data storage in the file system. * * @returns If the pool was correctly created, the function returns a * `boost::fylesystem::path` with the path to the file backing the * pool in the file system. Otherwise, `boost::filesystem::path{}` * is returned. */ fs::path path() const noexcept; /** * Returns the address to a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns a * void pointer to the non-volatile memory region containing the * pool's data. Otherwise, `nullptr` is returned. */ void* data() const noexcept; /** * Returns the size of a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns the * size of the non-volatile memory region containing * the pool's data. Otherwise, `0` is returned. */ std::size_t size() const noexcept; /** * Returns whether a pool's data is actually stored in non-volatile * memory. * * @returns The function returns `true` if the pool was correctly created, * and the pool's data is stored in NVM. Otherwise, `false` is * returned. */ bool is_persistent() const noexcept; /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ explicit operator bool() const noexcept; /** * * Check whether a pool is invalid. * * @returns `true` if the pool was not correctly created. Otherwise it * returns `false`. */ bool operator!() const noexcept; /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ bool valid() const noexcept; private: /// Logger instance std::shared_ptr<spdlog::logger> log_; /// Path to the pool file in the file system fs::path path_; /// Address of the pool's non-volatile memory region void* data_ = nullptr; /// Size of the pool's non-volatile memory region std::size_t size_ = 0; /// Flag set if the pool file is actually stored in non-volatile memory bool is_persistent_ = false; /// Flag set if the pool was created correctly bool is_valid_ = false; }; } // namespace pmdk #endif // GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP src/daemon/backend/data/CMakeLists.txt +5 −0 Original line number Diff line number Diff line # PMDK backend add_subdirectory(pmdk) add_library(storage STATIC) target_sources(storage Loading @@ -16,9 +19,11 @@ target_link_libraries(storage PRIVATE spdlog Boost::filesystem pmdk_storage -ldl ) #target_include_directories(storage # PRIVATE # ) src/daemon/backend/data/pmdk/CMakeLists.txt 0 → 100644 +29 −0 Original line number Diff line number Diff line ## # Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain # Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany # # This software was partially supported by the # EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # # This software was partially supported by the # ADA-FS project under the SPPEXA project funded by the DFG. # # SPDX-License-Identifier: MIT ## add_library(pmdk_storage STATIC ) target_sources(pmdk_storage PRIVATE pool.cpp PUBLIC ${INCLUDE_DIR}/daemon/backend/data/pmdk/pool.hpp ) target_link_libraries(pmdk_storage PUBLIC PMDK::pmem spdlog ) src/daemon/backend/data/pmdk/pool.cpp 0 → 100644 +217 −0 Original line number Diff line number Diff line /* Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany This software was partially supported by the EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). This software was partially supported by the ADA-FS project under the SPPEXA project funded by the DFG. SPDX-License-Identifier: MIT */ #include <libpmem.h> #include <boost/filesystem.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_generators.hpp> #include <daemon/backend/data/pmdk/pool.hpp> #include <daemon/backend/data/data_module.hpp> namespace fs = boost::filesystem; namespace { /** * Generate a random filename for a non-volatile memory pool using the Mersenne * Twister PRNG. Note that the function does not verify whether the path * returned actually exists or can be created. Neither does it verifies that * `subdir` exists or that the user actually has permissions to create * * @param[in] subdir an optional parent directory to prepend to the generated * path (Default: "") * @returns a randomly generated path */ fs::path generate_pool_path(const fs::path& subdir = "") { static boost::mt19937 rng; using RngType = decltype(rng); const auto uuid = boost::uuids::basic_random_generator<RngType>(rng)(); return subdir / boost::uuids::to_string(uuid); } } // namespace namespace pmdk { /** * Create a pool of non-volatile memory of a fixed `size` under * `parent_dir`. Give it a random name. * * @param[in] parent_dir the parent directory where the memory pool backing * file will be stored * @param[in] size the maximum capacity in bytes of the pool * @returns the newly created pool * * @warning The pool construction may fail for a number of reasons, but * the constructor will not throw (though the error itself will be logged). * Boolean operator overloads are provided so that it is simple to check * if a pool has been correctly constructed: * * .. code-block:: cpp * * pool p{"/foo/bar", 42000}; * * if(!p) { * abort("pool is invalid!") * } */ pool::pool(const fs::path& parent_dir, std::size_t size) noexcept { // get logger instance and set it for data module and chunk storage auto log_ = spdlog::get(GKFS_DATA_MOD->LOGGER_NAME); assert(log_); if(!fs::exists(parent_dir)) { log_->error("Error creating PMDK pool: parent directory {} " "does not exist", parent_dir.string()); return; } if(size <= 0) { log_->error("Error creating PMDK pool: invalid pool size {}", size); return; } fs::path pool_path = ::generate_pool_path(parent_dir); void* pool_address = nullptr; std::size_t pool_length = 0; int is_pmem = 0; // if the pool already exists in the host file system, it might be // a stale file or we might have a collision. Either way, abort the // pool creation. if(fs::exists(pool_path)) { log_->warn("PMDK pool file {} already exists (possible collision or " "stale file)", pool_path.string()); return; } pool_address = ::pmem_map_file(pool_path.c_str(), size, PMEM_FILE_CREATE | PMEM_FILE_EXCL | PMEM_FILE_SPARSE, 0666, &pool_length, &is_pmem); if(pool_address == nullptr) { log_->critical("Error creating PMDK pool file {}: {}", pool_path.string(), ::strerror(errno)); return; } path_ = pool_path; data_ = pool_address; size_ = pool_length; is_persistent_ = is_pmem; is_valid_ = true; } /** * Destroy an existing pool. */ pool::~pool() { if(data_ != nullptr) { ::pmem_unmap(data_, size_); } } /** * Returns the path to a pool's data storage in the file system. * * @returns If the pool was correctly created, the function returns a * `boost::fylesystem::path` with the path to the file backing the * pool in the file system. Otherwise, `boost::filesystem::path{}` * is returned. */ fs::path pool::path() const noexcept { return path_; } /** * Returns the address to a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns a * void pointer to the non-volatile memory region containing the * pool's data. Otherwise, `nullptr` is returned. */ void* pool::data() const noexcept { return data_; } /** * Returns the size of a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns the * size of the non-volatile memory region containing * the pool's data. Otherwise, `0` is returned. */ std::size_t pool::size() const noexcept { return size_; } /** * Returns whether a pool's data is actually stored in non-volatile * memory. * * @returns The function returns `true` if the pool was correctly created, * and the pool's data is stored in NVM. Otherwise, `false` is * returned. */ bool pool::is_persistent() const noexcept { return is_persistent_; } /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ pool::operator bool() const noexcept { return valid(); } /** * * Check whether a pool is invalid. * * @returns `true` if the pool was not correctly created. Otherwise it * returns `false`. */ bool pool::operator!() const noexcept { return !valid(); } /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ bool pool::valid() const noexcept { return is_valid_; } } // namespace pmdk tests/unit/CMakeLists.txt +3 −0 Original line number Diff line number Diff line Loading @@ -34,11 +34,14 @@ target_link_libraries(catch2_main add_executable(tests test_example_00.cpp test_example_01.cpp test_storage_pmdk.cpp ) target_link_libraries(tests catch2_main fmt::fmt pmdk_storage Boost::filesystem ) # Catch2's contrib folder includes some helper functions Loading Loading
include/daemon/backend/data/pmdk/pool.hpp 0 → 100644 +139 −0 Original line number Diff line number Diff line /* Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany This software was partially supported by the EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). This software was partially supported by the ADA-FS project under the SPPEXA project funded by the DFG. SPDX-License-Identifier: MIT */ #ifndef GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP #define GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP #include <spdlog/spdlog.h> #include <boost/filesystem.hpp> namespace fs = boost::filesystem; namespace pmdk { /** * This class implements a RAII-enabled non-volatile memory pool based on * Intel's PMDK C library. */ class pool { public: /** * Create a pool of non-volatile memory of a fixed `size` under * `parent_dir`. Give it a random name. * * @param[in] parent_dir the parent directory where the memory pool backing * file will be stored * @param[in] size the maximum capacity in bytes of the pool * @returns the newly created pool */ pool(const fs::path& parent_dir, std::size_t size) noexcept; pool(pool&& rhs) = default; pool(const pool& other) = delete; pool& operator=(pool&& rhs) = default; pool& operator=(const pool& other) = delete; /** * Destroy an existing pool. */ ~pool(); /** * Returns the path to a pool's data storage in the file system. * * @returns If the pool was correctly created, the function returns a * `boost::fylesystem::path` with the path to the file backing the * pool in the file system. Otherwise, `boost::filesystem::path{}` * is returned. */ fs::path path() const noexcept; /** * Returns the address to a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns a * void pointer to the non-volatile memory region containing the * pool's data. Otherwise, `nullptr` is returned. */ void* data() const noexcept; /** * Returns the size of a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns the * size of the non-volatile memory region containing * the pool's data. Otherwise, `0` is returned. */ std::size_t size() const noexcept; /** * Returns whether a pool's data is actually stored in non-volatile * memory. * * @returns The function returns `true` if the pool was correctly created, * and the pool's data is stored in NVM. Otherwise, `false` is * returned. */ bool is_persistent() const noexcept; /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ explicit operator bool() const noexcept; /** * * Check whether a pool is invalid. * * @returns `true` if the pool was not correctly created. Otherwise it * returns `false`. */ bool operator!() const noexcept; /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ bool valid() const noexcept; private: /// Logger instance std::shared_ptr<spdlog::logger> log_; /// Path to the pool file in the file system fs::path path_; /// Address of the pool's non-volatile memory region void* data_ = nullptr; /// Size of the pool's non-volatile memory region std::size_t size_ = 0; /// Flag set if the pool file is actually stored in non-volatile memory bool is_persistent_ = false; /// Flag set if the pool was created correctly bool is_valid_ = false; }; } // namespace pmdk #endif // GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP
src/daemon/backend/data/CMakeLists.txt +5 −0 Original line number Diff line number Diff line # PMDK backend add_subdirectory(pmdk) add_library(storage STATIC) target_sources(storage Loading @@ -16,9 +19,11 @@ target_link_libraries(storage PRIVATE spdlog Boost::filesystem pmdk_storage -ldl ) #target_include_directories(storage # PRIVATE # )
src/daemon/backend/data/pmdk/CMakeLists.txt 0 → 100644 +29 −0 Original line number Diff line number Diff line ## # Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain # Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany # # This software was partially supported by the # EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). # # This software was partially supported by the # ADA-FS project under the SPPEXA project funded by the DFG. # # SPDX-License-Identifier: MIT ## add_library(pmdk_storage STATIC ) target_sources(pmdk_storage PRIVATE pool.cpp PUBLIC ${INCLUDE_DIR}/daemon/backend/data/pmdk/pool.hpp ) target_link_libraries(pmdk_storage PUBLIC PMDK::pmem spdlog )
src/daemon/backend/data/pmdk/pool.cpp 0 → 100644 +217 −0 Original line number Diff line number Diff line /* Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany This software was partially supported by the EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu). This software was partially supported by the ADA-FS project under the SPPEXA project funded by the DFG. SPDX-License-Identifier: MIT */ #include <libpmem.h> #include <boost/filesystem.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_generators.hpp> #include <daemon/backend/data/pmdk/pool.hpp> #include <daemon/backend/data/data_module.hpp> namespace fs = boost::filesystem; namespace { /** * Generate a random filename for a non-volatile memory pool using the Mersenne * Twister PRNG. Note that the function does not verify whether the path * returned actually exists or can be created. Neither does it verifies that * `subdir` exists or that the user actually has permissions to create * * @param[in] subdir an optional parent directory to prepend to the generated * path (Default: "") * @returns a randomly generated path */ fs::path generate_pool_path(const fs::path& subdir = "") { static boost::mt19937 rng; using RngType = decltype(rng); const auto uuid = boost::uuids::basic_random_generator<RngType>(rng)(); return subdir / boost::uuids::to_string(uuid); } } // namespace namespace pmdk { /** * Create a pool of non-volatile memory of a fixed `size` under * `parent_dir`. Give it a random name. * * @param[in] parent_dir the parent directory where the memory pool backing * file will be stored * @param[in] size the maximum capacity in bytes of the pool * @returns the newly created pool * * @warning The pool construction may fail for a number of reasons, but * the constructor will not throw (though the error itself will be logged). * Boolean operator overloads are provided so that it is simple to check * if a pool has been correctly constructed: * * .. code-block:: cpp * * pool p{"/foo/bar", 42000}; * * if(!p) { * abort("pool is invalid!") * } */ pool::pool(const fs::path& parent_dir, std::size_t size) noexcept { // get logger instance and set it for data module and chunk storage auto log_ = spdlog::get(GKFS_DATA_MOD->LOGGER_NAME); assert(log_); if(!fs::exists(parent_dir)) { log_->error("Error creating PMDK pool: parent directory {} " "does not exist", parent_dir.string()); return; } if(size <= 0) { log_->error("Error creating PMDK pool: invalid pool size {}", size); return; } fs::path pool_path = ::generate_pool_path(parent_dir); void* pool_address = nullptr; std::size_t pool_length = 0; int is_pmem = 0; // if the pool already exists in the host file system, it might be // a stale file or we might have a collision. Either way, abort the // pool creation. if(fs::exists(pool_path)) { log_->warn("PMDK pool file {} already exists (possible collision or " "stale file)", pool_path.string()); return; } pool_address = ::pmem_map_file(pool_path.c_str(), size, PMEM_FILE_CREATE | PMEM_FILE_EXCL | PMEM_FILE_SPARSE, 0666, &pool_length, &is_pmem); if(pool_address == nullptr) { log_->critical("Error creating PMDK pool file {}: {}", pool_path.string(), ::strerror(errno)); return; } path_ = pool_path; data_ = pool_address; size_ = pool_length; is_persistent_ = is_pmem; is_valid_ = true; } /** * Destroy an existing pool. */ pool::~pool() { if(data_ != nullptr) { ::pmem_unmap(data_, size_); } } /** * Returns the path to a pool's data storage in the file system. * * @returns If the pool was correctly created, the function returns a * `boost::fylesystem::path` with the path to the file backing the * pool in the file system. Otherwise, `boost::filesystem::path{}` * is returned. */ fs::path pool::path() const noexcept { return path_; } /** * Returns the address to a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns a * void pointer to the non-volatile memory region containing the * pool's data. Otherwise, `nullptr` is returned. */ void* pool::data() const noexcept { return data_; } /** * Returns the size of a pool's data region in non-volatile memory. * * @returns If the pool was correctly created, the function returns the * size of the non-volatile memory region containing * the pool's data. Otherwise, `0` is returned. */ std::size_t pool::size() const noexcept { return size_; } /** * Returns whether a pool's data is actually stored in non-volatile * memory. * * @returns The function returns `true` if the pool was correctly created, * and the pool's data is stored in NVM. Otherwise, `false` is * returned. */ bool pool::is_persistent() const noexcept { return is_persistent_; } /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ pool::operator bool() const noexcept { return valid(); } /** * * Check whether a pool is invalid. * * @returns `true` if the pool was not correctly created. Otherwise it * returns `false`. */ bool pool::operator!() const noexcept { return !valid(); } /** * * Check whether a pool is valid. * * @returns `true` if the pool was correctly created. Otherwise it * returns `false`. */ bool pool::valid() const noexcept { return is_valid_; } } // namespace pmdk
tests/unit/CMakeLists.txt +3 −0 Original line number Diff line number Diff line Loading @@ -34,11 +34,14 @@ target_link_libraries(catch2_main add_executable(tests test_example_00.cpp test_example_01.cpp test_storage_pmdk.cpp ) target_link_libraries(tests catch2_main fmt::fmt pmdk_storage Boost::filesystem ) # Catch2's contrib folder includes some helper functions Loading