diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a77a63cf038c549f4098f2a845757e2fd89bf347..d154def4e44555798e614c2c61ec66a430c9d23c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,6 +18,7 @@ variables:
PYTEST: "${CI_PROJECT_DIR}/gkfs/install/share/gkfs/tests/integration/pytest-venv/bin/py.test"
LOG_PATH: "${CI_PROJECT_DIR}/logs"
LD_LIBRARY_PATH: "${CI_PROJECT_DIR}/deps/install/lib:${CI_PROJECT_DIR}/deps/install/lib64"
+ PKG_CONFIG_PATH: "${CI_PROJECT_DIR}/deps/install/lib/pkgconfig:${CI_PROJECT_DIR}/deps/install/lib64/pkgconfig"
# Configuration variables
GKFS_LOG_LEVEL: "100"
GKFS_DAEMON_LOG_PATH: "${CI_PROJECT_DIR}/logs/daemon.log"
@@ -25,7 +26,7 @@ variables:
LIBGKFS_LOG_OUTPUT: "${CI_PROJECT_DIR}/logs/gkfs_client.log"
GIT_SUBMODULE_STRATEGY: recursive
-image: gekkofs/gekkofs:build_env-0.8.0
+image: gekkofs/build_env:0.8.0
check format:
stage: check format
diff --git a/CMake/FindPMDK.cmake b/CMake/FindPMDK.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..4101d2cb0aed61adff96e78007d5ce0e52aab38e
--- /dev/null
+++ b/CMake/FindPMDK.cmake
@@ -0,0 +1,1055 @@
+################################################################################
+# Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain #
+# Copyright 2015-2021, 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. #
+# #
+# This file is part of GekkoFS. #
+# #
+# GekkoFS 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. #
+# #
+# GekkoFS is distributed in the hope that it will be useful, #
+# but WITHOUT 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 GekkoFS. If not, see . #
+# #
+# SPDX-License-Identifier: GPL-3.0-or-later #
+################################################################################
+
+#[=======================================================================[.rst:
+
+FindPMDK
+---------
+
+Find PMDK include directories and libraries.
+
+Introduction
+^^^^^^^^^^^^
+
+This module can be used by invoking :command:`find_package` with the form::
+
+ find_package(PMDK
+ [version] [EXACT] # Minimum or EXACT version e.g. 1.9.1
+ [REQUIRED] # Fail with error if PMDK is not found
+ [COMPONENTS ...] # PMDK libraries by their canonical name
+ # e.g. "pmemobj" for "libpmemobj"
+ )
+
+This module finds headers and requested component libraries and reports the
+results in the following variables::
+
+ PMDK_FOUND - True if headers and requested libraries were found
+ PMDK_INCLUDE_DIRS - PMDK include directories
+ PMDK_LIBRARY_DIRS - Link directories for PMDK libraries
+ PMDK_LIBRARIES - PMDK component libraries to be linked
+
+ PMDK__FOUND - True if component was found
+ ( is upper-case, e.g. PMDK_PMEM_FOUND)
+ PMDK__LIBRARY - Libraries to link for component
+ (may include target_link_libraries debug/optimized
+ keywords)
+
+ PMDK_VERSION_STRING - PMDK version number in x.y.z format
+ PMDK_VERSION - Same as PMDK_VERSION_STRING
+ PMDK_VERSION_MAJOR - PMDK major version number (e.g. 1 in 1.9.1-rc1)
+ PMDK_VERSION_MINOR - PMDK minor version number (e.g. 9 in 1.9.1-rc1)
+ PMDK_VERSION_PATCH - PMDK subminor version number (e.g. 1 in 1.9.1-rc1)
+ PMDK_VERSION_TWEAK - PMDK tweak version number (e.g. rc1 in 1.9.1-rc1)
+ PMDK_VERSION_COUNT - Amount of version components (e.g. 2 in 1.9)
+
+.. note::
+ Since PMDK does not yet provide version information in the headers but does
+ install ``pkg-config`` description files, version matching is done using
+ CMake's ``PkgConfig`` module. Thus, ``pkg-config`` needs to be available in
+ the system and the ``PKG_CONFIG_PATH`` environment variable may need to be
+ appropriately set (see ``pkg-config``'s man page for more details).
+
+This module reads hints about search locations from variables::
+
+ PMDK_ROOT - Preferred installation prefix
+ (or PMDKROOT)
+ PMDK_INCLUDEDIR - Preferred include directory e.g. /include
+ PMDK_LIBRARYDIR - Preferred library directory e.g. /lib
+ PMDK_NO_SYSTEM_PATHS - Set to ON to disable searching in locations not
+ specified by these hint variables. Default is OFF.
+ PMDK_ADDITIONAL_VERSIONS - List of PMDK versions not known to this module.
+
+and saves search results persistently in CMake cache entries::
+
+ PMDK_INCLUDE_DIR - Directory containing PMDK headers
+ PMDK_LIBRARY_DIR_RELEASE - Directory containing release PMDK libraries
+ PMDK_LIBRARY_DIR_DEBUG - Directory containing debug PMDK libraries
+ PMDK__LIBRARY_DEBUG - Component library debug variant
+ PMDK__LIBRARY_RELEASE - Component library release variant
+
+Users may set these hints or results as ``CACHE`` entries. Projects should
+not read these entries directly but instead use the above result variables.
+One may specify these as environment variables if they are not specified as
+CMake variables or cache entries.
+
+
+Imported Targets
+^^^^^^^^^^^^^^^^
+
+This module also defines the following :prop_tgt:`IMPORTED` targets, if found::
+
+ PMDK::PMDK - Target for the complete PMDK library
+ PMDK:: - Target for specific component dependencies (shared
+ or static libraries). Note that is lower-case
+
+Implicit dependencies such as ``PMDK::libpmemobj`` requiring ``PMDK::pmem``
+will be automatically detected and satisfied, even if ``pmem`` is not
+specified when using :command:`find_package` and if ``PMDK::pmem`` is not
+added to :command:`target_link_libraries`.
+
+It is important to note that the imported targets behave differently
+than variables created by this module: multiple calls to
+:command:`find_package(PMDK)` in the same directory or sub-directories with
+different options (e.g. static or shared) will not override the
+values of the targets created by the first call.
+
+Lookup Details
+^^^^^^^^^^^^^^
+
+This module first searches for the ``PMDK`` header files using the above
+hint variables (excluding ``PMDK_LIBRARYDIR``) and saves the result in
+``PMDK_INCLUDE_DIR``. Then it searches for requested component libraries
+using the above hints (excluding ``PMDK_INCLUDEDIR`` and
+``PMDK_ADDITIONAL_VERSIONS``) and "lib" directories near ``PMDK_INCLUDE_DIR``.
+It saves the library directories in ``PMDK_LIBRARY_DIR_DEBUG`` and
+``PMDK_LIBRARY_DIR_RELEASE`` and individual library locations in
+``PMDK__LIBRARY_DEBUG`` and ``PMDK__LIBRARY_RELEASE``.
+When one changes settings used by previous searches in the same build
+tree (excluding environment variables) this module discards previous
+search results affected by the changes and searches again.
+
+PMDK libraries come in RELEASE and DEBUG variants which (if installed) are
+stored in separate locations. Users or projects may tell this module which
+variant to find by setting variables::
+
+ PMDK_USE_DEBUG_LIBS - Set to ON or OFF to specify whether to search
+ and use the debug libraries. Default is ON.
+ PMDK_USE_RELEASE_LIBS - Set to ON or OFF to specify whether to search
+ and use the release libraries. Default is ON.
+ PMDK_USE_STATIC_LIBS - Set to ON to force the use of the static
+ libraries. Default is OFF.
+
+Other variables one may set to control this module are::
+
+ PMDK_DEBUG - Set to ON to enable debug output from FindPMDK.
+ Please enable this before filing any bug report.
+ PMDK_LIBRARY_DIR - Default value for PMDK_LIBRARY_DIR_RELEASE and
+ PMDK_LIBRARY_DIR_DEBUG.
+
+Examples
+^^^^^^^^
+
+Example to find PMDK headers only:
+
+.. code-block:: cmake
+
+ find_package(PMDK 1.36.0)
+ if(PMDK_FOUND)
+ include_directories(${PMDK_INCLUDE_DIRS})
+ add_executable(foo foo.cc)
+ endif()
+
+Example to find PMDK libraries and use imported targets:
+
+.. code-block:: cmake
+
+ find_package(PMDK 1.9.1 REQUIRED
+ COMPONENTS
+ pmemobj pmempool rpmem)
+ add_executable(foo foo.cc)
+ target_link_libraries(foo PMDK::pmemobj PMDK::pmempool
+ PMDK::rpmem)
+
+Example to find PMDK headers and some *static* (release only) libraries:
+
+.. code-block:: cmake
+
+ set(PMDK_USE_STATIC_LIBS ON) # only find static libs
+ set(PMDK_USE_DEBUG_LIBS OFF) # ignore debug libs and
+ set(PMDK_USE_RELEASE_LIBS ON) # only find release libs
+ find_package(PMDK 1.9.1
+ COMPONENTS
+ pmemobj pmempool rpmem ...)
+ if(PMDK_FOUND)
+ include_directories(${PMDK_INCLUDE_DIRS})
+ add_executable(foo foo.cc)
+ target_link_libraries(foo ${PMDK_LIBRARIES})
+ endif()
+
+#]=======================================================================]
+
+include(CMakePrintHelpers)
+
+# The FPHSA helper provides standard way of reporting final search results to
+# the user including the version and component checks.
+include(FindPackageHandleStandardArgs)
+
+
+
+#-------------------------------------------------------------------------------
+# FindPMDK functions & macros
+#
+
+#
+# Print debug text if PMDK_DEBUG is set.
+# Call example:
+# _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "debug message")
+#
+function(_PMDK_DEBUG_PRINT file line text)
+ if(PMDK_DEBUG)
+ message(STATUS "[ ${file}:${line} ] ${text}")
+ endif()
+endfunction()
+
+
+#
+# _PMDK_DEBUG_PRINT_VAR(file line variable_name [ENVIRONMENT]
+# [SOURCE "short explanation of origin of var value"])
+#
+# ENVIRONMENT - look up environment variable instead of CMake variable
+#
+# Print variable name and its value if PMDK_DEBUG is set.
+# Call example:
+# _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" PMDK_ROOT)
+#
+function(_PMDK_DEBUG_PRINT_VAR file line name)
+ if(PMDK_DEBUG)
+ cmake_parse_arguments(_args "ENVIRONMENT" "SOURCE" "" ${ARGN})
+
+ unset(source)
+ if(_args_SOURCE)
+ set(source " (${_args_SOURCE})")
+ endif()
+
+ if(_args_ENVIRONMENT)
+ if(DEFINED ENV{${name}})
+ set(value "\"$ENV{${name}}\"")
+ else()
+ set(value "")
+ endif()
+ set(_name "ENV{${name}}")
+ else()
+ if(DEFINED "${name}")
+ set(value "\"${${name}}\"")
+ else()
+ set(value "")
+ endif()
+ set(_name "${name}")
+ endif()
+
+ _PMDK_DEBUG_PRINT("${file}" "${line}" "${_name} = ${value}${source}")
+ endif()
+endfunction()
+
+
+#
+# Get component headers. This is the primary header (or headers) for
+# a given component, and is used to check that the headers are present
+# as well as the library itself as an extra sanity check of the build
+# environment.
+#
+# component - the component to check
+# _hdrs
+#
+function(_PMDK_COMPONENT_HEADERS component _hdrs)
+
+ # Note: new PMDK components will require adding here. The header
+ # must be present in all versions of PMDK providing a library.
+ set(_PMDK_PMEM_HEADERS "libpmem.h")
+ set(_PMDK_PMEMBLK_HEADERS "libpmemblk.h")
+ set(_PMDK_PMEMLOG_HEADERS "libpmemlog.h")
+ set(_PMDK_PMEMOBJ_HEADERS "libpmemobj.h")
+ set(_PMDK_PMEMPOOL_HEADERS "libpmempool.h")
+ set(_PMDK_RPMEM_HEADERS "librpmem.h")
+ set(_PMDK_PMEM2_HEADERS "libpmem2.h")
+
+ string(TOUPPER ${component} uppercomponent)
+ set(${_hdrs} ${_PMDK_${uppercomponent}_HEADERS} PARENT_SCOPE)
+
+ string(REGEX REPLACE ";" " " _pmdk_HDRS_STRING "${_PMDK_${uppercomponent}_HEADERS}")
+ if (NOT _pmdk_HDRS_STRING)
+ set(_pmdk_HDRS_STRING "(none)")
+ endif()
+
+ _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Headers for PMDK::${component}: ${_pmdk_HDRS_STRING}")
+endfunction()
+
+
+#
+# Get component dependencies. Requires the dependencies to have been
+# defined for the PMDK release version.
+#
+# component - the component to check
+# _ret - list of library dependencies
+#
+function(_PMDK_COMPONENT_DEPENDENCIES component _ret)
+
+ set(_PMDK_IMPORTED_TARGETS TRUE)
+ if(PMDK_VERSION_STRING)
+ if(PMDK_VERSION_STRING VERSION_LESS 1.9.1)
+ message(WARNING "Imported targets and dependency information not "
+ "available for PMDK version ${PMDK_VERSION_STRING} "
+ "(all versions older than 1.9.1)")
+ else()
+ set(_PMDK_PMEMBLK_DEPENDENCIES pmem)
+ set(_PMDK_PMEMLOG_DEPENDENCIES pmem)
+ set(_PMDK_PMEMOBJ_DEPENDENCIES pmem)
+ set(_PMDK_PMEMPOOL_DEPENDENCIES pmem)
+ set(_PMDK_RPMEM_DEPENDENCIES pmem)
+ if(PMDK_VERSION_STRING VERSION_GREATER_EQUAL 1.10.0)
+ message(WARNING "New PMDK version ${PMDK_VERSION_STRING} may have "
+ "incorrect or missing dependencies and imported "
+ "targets")
+ endif()
+ endif()
+ endif()
+
+ string(TOUPPER ${component} uppercomponent)
+ set(${_ret} ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ set(_PMDK_IMPORTED_TARGETS ${_PMDK_IMPORTED_TARGETS} PARENT_SCOPE)
+
+ string(REGEX REPLACE ";" " " _pmdk_DEPS_STRING "${_PMDK_${uppercomponent}_DEPENDENCIES}")
+ if (NOT _pmdk_DEPS_STRING)
+ set(_pmdk_DEPS_STRING "(none)")
+ endif()
+
+ message(STATUS "Dependencies for PMDK::${component}: ${_pmdk_DEPS_STRING}")
+
+ _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Dependencies for PMDK::${component}: ${_pmdk_DEPS_STRING}")
+
+endfunction()
+
+
+#
+# Determine if any missing dependencies require adding to the component list.
+#
+# Sets _PMDK_${COMPONENT}_DEPENDENCIES for each required component,
+# plus _PMDK_IMPORTED_TARGETS (TRUE if imported targets should be
+# defined; FALSE if dependency information is unavailable).
+#
+# componentvar - the component list variable name
+# extravar - the indirect dependency list variable name
+#
+#
+function(_PMDK_MISSING_DEPENDENCIES componentvar extravar)
+ # _pmdk_unprocessed_components - list of components requiring processing
+ # _pmdk_processed_components - components already processed (or currently being processed)
+ # _pmdk_new_components - new components discovered for future processing
+ #
+ list(APPEND _pmdk_unprocessed_components ${${componentvar}})
+
+ while(_pmdk_unprocessed_components)
+ list(APPEND _pmdk_processed_components ${_pmdk_unprocessed_components})
+ foreach(component ${_pmdk_unprocessed_components})
+ string(TOUPPER ${component} uppercomponent)
+ set(${_ret} ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ _PMDK_COMPONENT_DEPENDENCIES("${component}" _PMDK_${uppercomponent}_DEPENDENCIES)
+ set(_PMDK_${uppercomponent}_DEPENDENCIES ${_PMDK_${uppercomponent}_DEPENDENCIES} PARENT_SCOPE)
+ set(_PMDK_IMPORTED_TARGETS ${_PMDK_IMPORTED_TARGETS} PARENT_SCOPE)
+ foreach(componentdep ${_PMDK_${uppercomponent}_DEPENDENCIES})
+ if (NOT ("${componentdep}" IN_LIST _pmdk_processed_components OR "${componentdep}" IN_LIST _pmdk_new_components))
+ list(APPEND _pmdk_new_components ${componentdep})
+ endif()
+ endforeach()
+ endforeach()
+ set(_pmdk_unprocessed_components ${_pmdk_new_components})
+ unset(_pmdk_new_components)
+ endwhile()
+ set(_pmdk_extra_components ${_pmdk_processed_components})
+ if(_pmdk_extra_components AND ${componentvar})
+ list(REMOVE_ITEM _pmdk_extra_components ${${componentvar}})
+ endif()
+ set(${componentvar} ${_pmdk_processed_components} PARENT_SCOPE)
+ set(${extravar} ${_pmdk_extra_components} PARENT_SCOPE)
+endfunction()
+
+
+#
+# Find the given library (var).
+# Use 'build_type' to support different lib paths for RELEASE or DEBUG builds
+#
+macro(_PMDK_FIND_LIBRARY var build_type)
+
+ find_library(${var} ${ARGN})
+
+ if(${var})
+ # If this is the first library found then save PMDK_LIBRARY_DIR_[RELEASE,DEBUG].
+ if(NOT PMDK_LIBRARY_DIR_${build_type})
+ get_filename_component(_dir "${${var}}" PATH)
+ set(PMDK_LIBRARY_DIR_${build_type} "${_dir}" CACHE PATH "PMDK library directory ${build_type}" FORCE)
+ endif()
+ endif()
+
+ # If PMDK_LIBRARY_DIR_[RELEASE,DEBUG] is known then search only there.
+ if(PMDK_LIBRARY_DIR_${build_type})
+ set(_PMDK_LIBRARY_SEARCH_DIRS_${build_type} ${PMDK_LIBRARY_DIR_${build_type}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "PMDK_LIBRARY_DIR_${build_type}")
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ # "_PMDK_LIBRARY_SEARCH_DIRS_${build_type}")
+ endif()
+endmacro()
+
+# Detect changes in used variables.
+# Compares the current variable value with the last one.
+# In short form:
+# v != v_LAST -> CHANGED = 1
+# v is defined, v_LAST not -> CHANGED = 1
+# v is not defined, but v_LAST is -> CHANGED = 1
+# otherwise -> CHANGED = 0
+# CHANGED is returned in variable named ${changed_var}
+macro(_PMDK_CHANGE_DETECT changed_var)
+ set(${changed_var} 0)
+ foreach(v ${ARGN})
+ if(DEFINED _PMDK_COMPONENTS_SEARCHED)
+ if(${v})
+ if(_${v}_LAST)
+ string(COMPARE NOTEQUAL "${${v}}" "${_${v}_LAST}" _${v}_CHANGED)
+ else()
+ set(_${v}_CHANGED 1)
+ endif()
+ elseif(_${v}_LAST)
+ set(_${v}_CHANGED 1)
+ endif()
+ if(_${v}_CHANGED)
+ set(${changed_var} 1)
+ endif()
+ else()
+ set(_${v}_CHANGED 0)
+ endif()
+ endforeach()
+endmacro()
+
+#
+# Check the existence of the libraries.
+#
+macro(_PMDK_ADJUST_LIB_VARS basename)
+ if(PMDK_INCLUDE_DIR)
+ if(PMDK_${basename}_LIBRARY_DEBUG AND PMDK_${basename}_LIBRARY_RELEASE)
+ # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for
+ # single-config generators, set optimized and debug libraries
+ get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+ if(_isMultiConfig OR CMAKE_BUILD_TYPE)
+ set(PMDK_${basename}_LIBRARY optimized ${PMDK_${basename}_LIBRARY_RELEASE} debug ${PMDK_${basename}_LIBRARY_DEBUG})
+ else()
+ # For single-config generators where CMAKE_BUILD_TYPE has no value,
+ # just use the release libraries
+ set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE} )
+ endif()
+ # FIXME: This probably should be set for both cases
+ set(PMDK_${basename}_LIBRARIES optimized ${PMDK_${basename}_LIBRARY_RELEASE} debug ${PMDK_${basename}_LIBRARY_DEBUG})
+ endif()
+
+ # if only the release version was found, set the debug variable also to the release version
+ if(PMDK_${basename}_LIBRARY_RELEASE AND NOT PMDK_${basename}_LIBRARY_DEBUG)
+ set(PMDK_${basename}_LIBRARY_DEBUG ${PMDK_${basename}_LIBRARY_RELEASE})
+ set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE})
+ set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_RELEASE})
+ endif()
+
+ # if only the debug version was found, set the release variable also to the debug version
+ if(PMDK_${basename}_LIBRARY_DEBUG AND NOT PMDK_${basename}_LIBRARY_RELEASE)
+ set(PMDK_${basename}_LIBRARY_RELEASE ${PMDK_${basename}_LIBRARY_DEBUG})
+ set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_DEBUG})
+ set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_DEBUG})
+ endif()
+
+ # If the debug & release library ends up being the same, omit the keywords
+ if("${PMDK_${basename}_LIBRARY_RELEASE}" STREQUAL "${PMDK_${basename}_LIBRARY_DEBUG}")
+ set(PMDK_${basename}_LIBRARY ${PMDK_${basename}_LIBRARY_RELEASE} )
+ set(PMDK_${basename}_LIBRARIES ${PMDK_${basename}_LIBRARY_RELEASE} )
+ endif()
+
+ if(PMDK_${basename}_LIBRARY AND PMDK_${basename}_HEADER)
+ set(PMDK_${basename}_FOUND ON)
+ endif()
+ endif()
+
+ # Make variables changeable to the advanced user
+ mark_as_advanced(
+ PMDK_${basename}_LIBRARY_RELEASE
+ PMDK_${basename}_LIBRARY_DEBUG
+ )
+endmacro()
+
+#
+# End functions/macros
+#
+#-------------------------------------------------------------------------------
+
+
+#-------------------------------------------------------------------------------
+# main.
+#-------------------------------------------------------------------------------
+
+# If the user sets PMDK_LIBRARY_DIR, use it as the default for both
+# configurations.
+if(NOT PMDK_LIBRARY_DIR_RELEASE AND PMDK_LIBRARY_DIR)
+ set(PMDK_LIBRARY_DIR_RELEASE "${PMDK_LIBRARY_DIR}")
+endif()
+
+if(NOT PMDK_LIBRARY_DIR_DEBUG AND PMDK_LIBRARY_DIR)
+ set(PMDK_LIBRARY_DIR_DEBUG "${PMDK_LIBRARY_DIR}")
+endif()
+
+if(NOT DEFINED PMDK_USE_DEBUG_LIBS)
+ set(PMDK_USE_DEBUG_LIBS TRUE)
+endif()
+
+if(NOT DEFINED PMDK_USE_RELEASE_LIBS)
+ set(PMDK_USE_RELEASE_LIBS TRUE)
+endif()
+
+# Check the version of PMDK against the requested version.
+if(PMDK_FIND_VERSION AND NOT PMDK_FIND_VERSION_MINOR)
+ message(SEND_ERROR "When requesting a specific version of PMDK, you must "
+ "provide at least the major and minor version numbers, "
+ "e.g., 1.9")
+endif()
+
+if(PMDK_FIND_VERSION_EXACT)
+ # The version may appear in a directory with or without the patch level,
+ # even when the patch level is non-zero
+ set(_PMDK_TESTS_VERSIONS
+ "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}.${PMDK_FIND_VERSION_PATCH}"
+ "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}")
+else()
+ # The user has not requested an exact version. Among known versions, find
+ # those that are acceptable to the user request.
+ #
+ # Note: When adding a new PMDK release, also update the dependency
+ # information in _PMDK_COMPONENT_DEPENDENCIES and
+ # _PMDK_COMPONENT_HEADERS. See the instructions at the top of
+ # _PMDK_COMPONENT_DEPENDENCIES.
+ set(_PMDK_KNOWN_VERSIONS ${PMDK_ADDITIONAL_VERSIONS}
+ "1.9.1" "1.9" "1.9-rc2" "1.9-rc1" "1.8.1" "1.8" "1.8-rc2" "1.8-rc1" "1.7.1"
+ "1.7" "1.7-rc2" "1.7-rc1" "1.6.1" "1.6.1-rc1" "1.6" "1.6-rc3" "1.6-rc2"
+ "1.6-rc1" "1.5.2" "1.5.2-rc1" "1.5.1" "1.5.1-rc3" "1.5.1-rc2" "1.5.1-rc1"
+ "1.5" "1.5-rc2" "1.5-rc1" "1.4.3" "1.4.3-rc1" "1.4.2" "1.4.2-rc1" "1.4.1"
+ "1.4.1-rc4" "1.4.1-rc3" "1.4.1-rc2" "1.4.1-rc1" "1.4" "1.4-rc4" "1.4-rc3"
+ "1.4-rc2" "1.4-rc1" "1.3.3" "1.3.3-rc1" "1.3+b2" "1.3+b1" "1.3" "1.3-rc2"
+ "1.3-rc1" "1.2.4" "1.2.4-rc1" "1.2+wtp1" "1.2+b3" "1.2+b2" "1.2+b1" "1.2"
+ "1.2-rc3" "1.2-rc2" "1.2-rc1" "1.1" "1.1-rc3" "1.1-rc2" "1.1-rc1" "1.0+b2"
+ "1.0+b1" "1.0" "1.0-rc3" "1.0-rc2" "1.0-rc1" "0.4+b3" "0.4+b2" "0.4+b1"
+ "0.4" "0.4-rc2" "0.4-rc1" "0.3+b3" "0.3+b2" "0.3+b1" "0.3" "0.3-rc2"
+ "0.3-rc1" "0.2+b4" "0.2+b3" "0.2+b2" "0.2+b1" "0.2" "0.2-rc3" "0.2-rc2"
+ "0.2-rc1" "0.1+b16" "0.1+b15" "0.1+b14" "0.1+b13" "0.1+b12" "0.1+b11"
+ "0.1+b10" "0.1+b9" "0.1+b8" "0.1+b7" "0.1+b6" "0.1+b5" "0.1+b4" "0.1+b3"
+ "0.1+b2" "0.1+b1" "0.1"
+ )
+
+ set(_PMDK_TESTS_VERSIONS)
+ if(PMDK_FIND_VERSION)
+ set(_PMDK_FIND_VERSION_SHORT "${PMDK_FIND_VERSION_MAJOR}.${PMDK_FIND_VERSION_MINOR}")
+
+ # select acceptable versions
+ foreach(version ${_PMDK_KNOWN_VERSIONS})
+ if(NOT "${version}" VERSION_LESS "${PMDK_FIND_VERSION}")
+ # This version is high enough
+ list(APPEND _PMDK_TESTS_VERSIONS "${version}")
+ elseif("${version}.99" VERSION_EQUAL "${_PMDK_FIND_VERSION_SHORT}.99")
+ # This version is a short-form for the requested version with
+ # the patch level dropped.
+ list(APPEND _PMDK_TESTS_VERSIONS "${version}")
+ endif()
+ endforeach()
+ else()
+ # Any version is acceptable
+ set(_PMDK_TESTS_VERSIONS "${_PMDK_KNOWN_VERSIONS}")
+ endif()
+endif()
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_TEST_VERSIONS")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_USE_STATIC_LIBS")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ADDITIONAL_VERSIONS")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_NO_SYSTEM_PATHS")
+
+# Collect environment variable inputs as hints.
+foreach(v PMDKROOT PMDK_ROOT PMDK_INCLUDEDIR PMDK_LIBRARYDIR)
+ set(_env $ENV{${v}})
+ if(_env)
+ file(TO_CMAKE_PATH "${_env}" _ENV_${v})
+ else()
+ set(_ENV_${v} "")
+ endif()
+endforeach()
+
+if(NOT _ENV_PMDK_ROOT AND _ENV_PMDKROOT)
+ set(_ENV_PMDK_ROOT "${_ENV_PMDKROOT}")
+endif()
+
+# Collect inputs and cached results.
+if(NOT PMDK_ROOT AND PMDKROOT)
+ set(PMDK_ROOT "${PMDKROOT}")
+endif()
+
+set(_PMDK_VARS_DIR
+ PMDK_ROOT
+ PMDK_NO_SYSTEM_PATHS
+ )
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ROOT")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_ROOT" ENVIRONMENT)
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDEDIR")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDEDIR" ENVIRONMENT)
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_LIBRARYDIR")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_LIBRARYDIR" ENVIRONMENT)
+
+
+# ------------------------------------------------------------------------
+# Search for PMDK include DIR
+# ------------------------------------------------------------------------
+
+set(_PMDK_VARS_INC PMDK_INCLUDEDIR PMDK_INCLUDE_DIR PMDK_ADDITIONAL_VERSIONS)
+_PMDK_CHANGE_DETECT(_PMDK_CHANGE_INCDIR ${_PMDK_VARS_DIR} ${_PMDK_VARS_INC})
+
+# Clear PMDK_INCLUDE_DIR if it did not change but other input affecting the
+# location did. We will find a new one based on the new inputs.
+if(_PMDK_CHANGE_INCDIR AND NOT _PMDK_INCLUDE_DIR_CHANGED)
+ unset(PMDK_INCLUDE_DIR CACHE)
+endif()
+
+if(NOT PMDK_INCLUDE_DIR)
+ set(_PMDK_INCLUDE_SEARCH_DIRS "")
+
+ if(PMDK_INCLUDEDIR)
+ list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${PMDK_INCLUDEDIR})
+ elseif(_ENV_PMDK_INCLUDEDIR)
+ list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${_ENV_PMDK_INCLUDEDIR})
+ endif()
+
+ if(PMDK_ROOT)
+ list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${PMDK_ROOT}/include ${PMDK_ROOT})
+ elseif(_ENV_PMDK_ROOT)
+ list(APPEND _PMDK_INCLUDE_SEARCH_DIRS ${_ENV_PMDK_ROOT}/include ${_ENV_PMDK_ROOT})
+ endif()
+
+ if(PMDK_NO_SYSTEM_PATHS)
+ list(APPEND _PMDK_INCLUDE_SEARCH_DIRS NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH)
+ endif()
+
+ _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_INCLUDE_SEARCH_DIRS")
+
+ # Look for a standard PMDK header file
+ find_path(PMDK_INCLUDE_DIR
+ NAMES libpmem.h
+ HINTS ${_PMDK_INCLUDE_SEARCH_DIRS}
+ )
+endif()
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_INCLUDE_DIR")
+
+
+# ------------------------------------------------------------------------
+# Extract version information using pkg-config
+#
+# TODO: This will fail if pkg-config is not available, but version
+# information is unfortunately only contained in the installed .pc
+# files. In the future it would be more portable to extract version
+# information from a installed header, if the developers end up add
+# providing this information.
+# ------------------------------------------------------------------------
+
+find_package(PkgConfig)
+
+if(PMDK_FIND_VERSION)
+
+ if(NOT PKG_CONFIG_FOUND)
+ message(FATAL_ERROR "ERROR: pkg-config is required to determine PMDK's "
+ "installed version. If pkg-config cannot be installed "
+ "and you are certain that PMDK's installed version "
+ "is the correct one, you can disable this check by "
+ "removing the version number in the call to "
+ "find_package(PMDK ...)")
+ endif()
+
+ pkg_get_variable(PMDK_VERSION_STRING libpmem version)
+
+ if(NOT PMDK_VERSION_STRING)
+ message(FATAL_ERROR "ERROR: Failed to determine PMDK version.")
+ endif()
+
+ set(PMDK_VERSION ${PMDK_VERSION_STRING})
+
+ string(REGEX MATCH "([0-9]+).([0-9]+)(.([0-9]+))?([+-](((rc)|b)[0-9]+))?" _ ${PMDK_VERSION_STRING})
+ set(PMDK_VERSION_MAJOR ${CMAKE_MATCH_1})
+ set(PMDK_VERSION_MINOR ${CMAKE_MATCH_2})
+ set(PMDK_VERSION_PATCH ${CMAKE_MATCH_4})
+ set(PMDK_VERSION_TWEAK ${CMAKE_MATCH_6})
+
+ set(PMDK_VERSION_COUNT 2)
+
+ if(PMDK_VERSION_PATCH)
+ math(EXPR PMDK_VERSION_COUNT "${PMDK_VERSION_COUNT} + 1")
+ endif()
+
+ if(PMDK_VERSION_TWEAK)
+ math(EXPR PMDK_VERSION_COUNT "${PMDK_VERSION_COUNT} + 1")
+ endif()
+
+endif()
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_STRING")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_MAJOR")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_MINOR")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_PATCH")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_TWEAK")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_VERSION_COUNT")
+
+
+# ------------------------------------------------------------------------
+# Begin finding PMDK libraries
+# ------------------------------------------------------------------------
+
+set(_PMDK_VARS_NAME
+ PMDK_USE_STATIC_LIBS
+ )
+_PMDK_CHANGE_DETECT(_PMDK_CHANGE_LIBNAME ${_PMDK_VARS_NAME})
+
+set(_PMDK_VARS_LIB "")
+foreach(c DEBUG RELEASE)
+ set(_PMDK_VARS_LIB_${c} PMDK_LIBRARYDIR PMDK_LIBRARY_DIR_${c})
+ list(APPEND _PMDK_VARS_LIB ${_PMDK_VARS_LIB_${c}})
+ _PMDK_CHANGE_DETECT(_PMDK_CHANGE_LIBDIR_${c} ${_PMDK_VARS_DIR} ${_PMDK_VARS_LIB_${c}} PMDK_INCLUDE_DIR)
+
+ # Clear PMDK_LIBRARY_DIR_${c} if it did not change but other input affecting
+ # the location did. We will find a new one based on the new inputs.
+ if(_PMDK_CHANGE_LIBDIR_${c} AND NOT _PMDK_LIBRARY_DIR_${c}_CHANGED)
+ unset(PMDK_LIBRARY_DIR_${c} CACHE)
+ endif()
+
+ # If PMDK_LIBRARY_DIR_[RELEASE,DEBUG] is set, prefer its value.
+ if(PMDK_LIBRARY_DIR_${c})
+ set(_PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_LIBRARY_DIR_${c}} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH)
+ else()
+ set(_PMDK_LIBRARY_SEARCH_DIRS_${c} "")
+ if(PMDK_LIBRARYDIR)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_LIBRARYDIR})
+ elseif(_ENV_PMDK_LIBRARYDIR)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${_ENV_PMDK_LIBRARYDIR})
+ endif()
+
+ if(PMDK_ROOT)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${PMDK_ROOT}/lib ${PMDK_ROOT}/stage/lib)
+ elseif(_ENV_PMDK_ROOT)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} ${_ENV_PMDK_ROOT}/lib ${_ENV_PMDK_ROOT}/stage/lib)
+ endif()
+
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c}
+ ${PMDK_INCLUDE_DIR}/lib
+ ${PMDK_INCLUDE_DIR}/../lib
+ ${PMDK_INCLUDE_DIR}/stage/lib
+ )
+
+ if("${c}" STREQUAL "DEBUG")
+ # PMDK debug libraries are installed in a `pmdk_debug` subdir
+ list(TRANSFORM _PMDK_LIBRARY_SEARCH_DIRS_${c} APPEND "/pmdk_debug")
+ endif()
+
+ if(PMDK_NO_SYSTEM_PATHS)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_${c} NO_CMAKE_SYSTEM_PATH NO_SYSTEM_ENVIRONMENT_PATH)
+ endif()
+
+ endif()
+endforeach()
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE")
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG")
+
+# Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES
+if(PMDK_USE_STATIC_LIBS)
+ set( _PMDK_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
+ if(WIN32)
+ list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
+ else()
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+ endif()
+endif()
+
+_PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_FIND_COMPONENTS")
+
+# If the user didn't ask for a particular component to be searched,
+# assume that they wanted all the components in the library
+if(NOT PMDK_FIND_COMPONENTS)
+ set(PMDK_FIND_COMPONENTS
+ "pmem" "pmemblk" "pmemlog" "pmempool" "rpmem" "pmem2"
+ )
+endif()
+
+# Additional components may be required via component dependencies.
+# Add any missing components to the list.
+_PMDK_MISSING_DEPENDENCIES(PMDK_FIND_COMPONENTS _PMDK_EXTRA_FIND_COMPONENTS)
+
+foreach(COMPONENT ${PMDK_FIND_COMPONENTS})
+
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ set( _pmdk_docstring_release "PMDK ${COMPONENT} library (release)")
+ set( _pmdk_docstring_debug "PMDK ${COMPONENT} library (debug)")
+
+ #
+ # Find headers
+ #
+ _PMDK_COMPONENT_HEADERS("${COMPONENT}" PMDK_${UPPERCOMPONENT}_HEADER_NAME)
+
+ # Look for a standard PMDK header file.
+ if(PMDK_${UPPERCOMPONENT}_HEADER_NAME)
+ if(EXISTS "${PMDK_INCLUDE_DIR}/${PMDK_${UPPERCOMPONENT}_HEADER_NAME}")
+ set(PMDK_${UPPERCOMPONENT}_HEADER ON)
+ else()
+ set(PMDK_${UPPERCOMPONENT}_HEADER OFF)
+ endif()
+ else()
+ set(PMDK_${UPPERCOMPONENT}_HEADER ON)
+ message(WARNING "No header defined for ${COMPONENT}; skipping header check "
+ "(note: header-only libraries have no designated component)")
+ endif()
+
+ #
+ # Find RELEASE libraries
+ #
+ unset(_PMDK_RELEASE_NAMES)
+ foreach(component IN LISTS COMPONENT)
+ list(APPEND _PMDK_RELEASE_NAMES
+ ${component}
+ )
+ endforeach()
+
+ _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_RELEASE: "
+ "${_PMDK_RELEASE_NAMES}")
+
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_RELEASE_NAMES")
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE")
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_pmdk_docstring_release")
+
+ # if PMDK_LIBRARY_DIR_RELEASE is not defined,
+ # but PMDK_LIBRARY_DIR_DEBUG is, also look there for RELEASE libs
+ if(NOT PMDK_LIBRARY_DIR_RELEASE AND PMDK_LIBRARY_DIR_DEBUG)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_RELEASE ${PMDK_LIBRARY_DIR_DEBUG})
+ endif()
+
+ # Avoid passing backslashes to _PMDK_FIND_LIBRARY due to macro re-parsing.
+ unset(_PMDK_LIBRARY_SEARCH_DIRS_tmp)
+ string(REPLACE "\\" "/" _PMDK_LIBRARY_SEARCH_DIRS_tmp "${_PMDK_LIBRARY_SEARCH_DIRS_RELEASE}")
+
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_RELEASE")
+
+ if(PMDK_USE_RELEASE_LIBS)
+ _PMDK_FIND_LIBRARY(PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE RELEASE
+ NAMES ${_PMDK_RELEASE_NAMES}
+ HINTS ${_PMDK_LIBRARY_SEARCH_DIRS_tmp}
+ NAMES_PER_DIR
+ DOC "${_pmdk_docstring_release}"
+ )
+
+ _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE")
+ endif()
+
+ #
+ # Find DEBUG libraries
+ #
+ unset(_PMDK_DEBUG_NAMES)
+ foreach(component IN LISTS COMPONENT)
+ list(APPEND _PMDK_DEBUG_NAMES
+ ${component}
+ )
+ endforeach()
+
+ _PMDK_DEBUG_PRINT("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}"
+ "Searching for ${UPPERCOMPONENT}_LIBRARY_DEBUG: "
+ "${_PMDK_DEBUG_NAMES}")
+
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_DEBUG_NAMES")
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG")
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_pmdk_docstring_debug")
+
+ # if PMDK_LIBRARY_DIR_DEBUG is not defined,
+ # but PMDK_LIBRARY_DIR_RELEASE is, also look there for DEBUG libs
+ if(NOT PMDK_LIBRARY_DIR_DEBUG AND PMDK_LIBRARY_DIR_RELEASE)
+ list(APPEND _PMDK_LIBRARY_SEARCH_DIRS_DEBUG ${PMDK_LIBRARY_DIR_RELEASE})
+ endif()
+
+
+ # Avoid passing backslashes to _PMDK_FIND_LIBRARY due to macro re-parsing.
+ unset(_PMDK_LIBRARY_SEARCH_DIRS_tmp)
+ string(REPLACE "\\" "/" _PMDK_LIBRARY_SEARCH_DIRS_tmp "${_PMDK_LIBRARY_SEARCH_DIRS_DEBUG}")
+
+ # _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "_PMDK_LIBRARY_SEARCH_DIRS_DEBUG")
+
+ if(PMDK_USE_DEBUG_LIBS)
+ _PMDK_FIND_LIBRARY(PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG DEBUG
+ NAMES ${_PMDK_DEBUG_NAMES}
+ HINTS ${_PMDK_LIBRARY_SEARCH_DIRS_tmp}
+ NAMES_PER_DIR
+ NO_DEFAULT_PATH
+ DOC "${_pmdk_docstring_debug}"
+ )
+
+ _PMDK_DEBUG_PRINT_VAR("${CMAKE_CURRENT_LIST_FILE}" "${CMAKE_CURRENT_LIST_LINE}" "PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG")
+ endif()
+
+ _PMDK_ADJUST_LIB_VARS(${UPPERCOMPONENT})
+endforeach()
+
+# Restore the original find library ordering
+if(PMDK_USE_STATIC_LIBS)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES ${_PMDK_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
+
+# ------------------------------------------------------------------------
+# End finding PMDK libraries
+# ------------------------------------------------------------------------
+
+
+set(PMDK_INCLUDE_DIRS ${PMDK_INCLUDE_DIR})
+set(PMDK_LIBRARY_DIRS)
+if(PMDK_LIBRARY_DIR_RELEASE)
+ list(APPEND PMDK_LIBRARY_DIRS ${PMDK_LIBRARY_DIR_RELEASE})
+endif()
+if(PMDK_LIBRARY_DIR_DEBUG)
+ list(APPEND PMDK_LIBRARY_DIRS ${PMDK_LIBRARY_DIR_DEBUG})
+endif()
+if(PMDK_LIBRARY_DIRS)
+ list(REMOVE_DUPLICATES PMDK_LIBRARY_DIRS)
+endif()
+
+
+# ------------------------------------------------------------------------
+# Call FPHSA helper, see https://cmake.org/cmake/help/latest/module/FindPackageHandleStandardArgs.html
+# ------------------------------------------------------------------------
+
+# Define aliases as needed by the component handler in the FPHSA helper below
+foreach(component IN LISTS PMDK_FIND_COMPONENTS)
+ string(TOUPPER ${component} uppercomponent)
+ if(DEFINED PMDK_${uppercomponent}_FOUND)
+ set(PMDK_${component}_FOUND ${PMDK_${uppercomponent}_FOUND})
+ endif()
+endforeach()
+
+find_package_handle_standard_args(PMDK
+ REQUIRED_VARS PMDK_INCLUDE_DIR
+ VERSION_VAR PMDK_VERSION_STRING
+ HANDLE_COMPONENTS)
+
+
+# ------------------------------------------------------------------------
+# Add imported targets
+# ------------------------------------------------------------------------
+if(PMDK_FOUND)
+ foreach(COMPONENT ${PMDK_FIND_COMPONENTS})
+
+ if(_PMDK_IMPORTED_TARGETS AND NOT TARGET PMDK::${COMPONENT})
+ string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
+
+ if(PMDK_${UPPERCOMPONENT}_FOUND)
+ add_library(PMDK::${COMPONENT} UNKNOWN IMPORTED)
+
+ if(PMDK_INCLUDE_DIRS)
+ set_target_properties(PMDK::${COMPONENT} PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${PMDK_INCLUDE_DIRS}")
+ endif()
+
+ if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY}")
+ set_target_properties(PMDK::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES "C"
+ IMPORTED_LOCATION "${PMDK_${UPPERCOMPONENT}_LIBRARY}")
+ endif()
+
+ if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+ set_property(TARGET PMDK::${COMPONENT} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(PMDK::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C"
+ IMPORTED_LOCATION_RELEASE "${PMDK_${UPPERCOMPONENT}_LIBRARY_RELEASE}")
+ endif()
+
+ if(EXISTS "${PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+ set_property(TARGET PMDK::${COMPONENT} APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(PMDK::${COMPONENT} PROPERTIES
+ IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C"
+ IMPORTED_LOCATION_DEBUG "${PMDK_${UPPERCOMPONENT}_LIBRARY_DEBUG}")
+ endif()
+
+ if(_PMDK_${UPPERCOMPONENT}_DEPENDENCIES)
+ unset(_PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES)
+ foreach(dep ${_PMDK_${UPPERCOMPONENT}_DEPENDENCIES})
+ list(APPEND _PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES PMDK::${dep})
+ endforeach()
+ set_target_properties(PMDK::${COMPONENT} PROPERTIES
+ INTERFACE_LINK_LIBRARIES "${_PMDK_${UPPERCOMPONENT}_TARGET_DEPENDENCIES}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+endif()
+
+
+# ------------------------------------------------------------------------
+# Finalize
+# ------------------------------------------------------------------------
+
+# Report PMDK_LIBRARIES
+set(PMDK_LIBRARIES "")
+foreach(component IN LISTS PMDK_FIND_COMPONENTS)
+ string(TOUPPER ${component} uppercomponent)
+ if(PMDK_${uppercomponent}_FOUND)
+ list(APPEND PMDK_LIBRARIES ${PMDK_${uppercomponent}_LIBRARY})
+ endif()
+endforeach()
+
+# Configure display of cache entries in GUI.
+foreach(v PMDKROOT PMDK_ROOT ${_PMDK_VARS_INC} ${_PMDK_VARS_LIB})
+ get_property(_type CACHE ${v} PROPERTY TYPE)
+ if(_type)
+ set_property(CACHE ${v} PROPERTY ADVANCED 1)
+ if("x${_type}" STREQUAL "xUNINITIALIZED")
+ if("x${v}" STREQUAL "xPMDK_ADDITIONAL_VERSIONS")
+ set_property(CACHE ${v} PROPERTY TYPE STRING)
+ else()
+ set_property(CACHE ${v} PROPERTY TYPE PATH)
+ endif()
+ endif()
+ endif()
+endforeach()
+
+# Record last used values of input variables so we can
+# detect on the next run if the user changed them.
+foreach(v
+ ${_PMDK_VARS_INC} ${_PMDK_VARS_LIB}
+ ${_PMDK_VARS_DIR} ${_PMDK_VARS_NAME}
+ )
+ if(DEFINED ${v})
+ set(_${v}_LAST "${${v}}" CACHE INTERNAL "Last used ${v} value.")
+ else()
+ unset(_${v}_LAST CACHE)
+ endif()
+endforeach()
+
+# Maintain a persistent list of components requested anywhere since
+# the last flush.
+set(_PMDK_COMPONENTS_SEARCHED "${_PMDK_COMPONENTS_SEARCHED}")
+list(APPEND _PMDK_COMPONENTS_SEARCHED ${PMDK_FIND_COMPONENTS})
+list(REMOVE_DUPLICATES _PMDK_COMPONENTS_SEARCHED)
+list(SORT _PMDK_COMPONENTS_SEARCHED)
+set(_PMDK_COMPONENTS_SEARCHED "${_PMDK_COMPONENTS_SEARCHED}"
+ CACHE INTERNAL "Components requested for this build tree.")
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3061cc5b217536e339d6b22b41749f8adaed18a4..7c22d124e94b29c18205bd8b56ea4cfa1c0296b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -131,6 +131,7 @@ find_package(Syscall_intercept REQUIRED)
# boost dependencies
find_package(Boost 1.53 REQUIRED
COMPONENTS
+ system
program_options
)
@@ -143,6 +144,10 @@ find_package(Filesystem REQUIRED)
find_package(Date REQUIRED)
+find_package(PMDK 1.9.1 REQUIRED
+ COMPONENTS
+ pmem)
+
option(CREATE_CHECK_PARENTS "Check parent directory existance before creating child node" ON)
message(STATUS "[gekkofs] Create checks parents: ${CREATE_CHECK_PARENTS}")
diff --git a/docker/debian_build_env.docker b/docker/debian_build_env.docker
index b616be8c67b383748751e25c7702e7b35532f1cd..d24eb3a7e9d0e8e4b602e8f579ce8d8a615b7b96 100644
--- a/docker/debian_build_env.docker
+++ b/docker/debian_build_env.docker
@@ -33,6 +33,10 @@ RUN apt-get update && \
zlib1g-dev \
# syscall_intercept dependencies
libcapstone-dev \
+ # pmdk dependencies
+ libndctl-dev \
+ libdaxctl-dev \
+ pandoc \
# GekkoFS
libboost-filesystem-dev \
libboost-program-options-dev \
@@ -48,7 +52,7 @@ RUN apt-get update && \
lsb-release \
wget \
software-properties-common \
- gnupg2 \
+ gnupg2 && \
# add clang-10 repos
wget https://apt.llvm.org/llvm.sh -P /tmp && chmod +x /tmp/llvm.sh && /tmp/llvm.sh 10 && \
# install clang-format
diff --git a/external/hermes b/external/hermes
index 0af45bfa667f7ff9c78167ef94d975bffbd879f0..97820ed81aba9ef7c05891ce80c53a8533b78609 160000
--- a/external/hermes
+++ b/external/hermes
@@ -1 +1 @@
-Subproject commit 0af45bfa667f7ff9c78167ef94d975bffbd879f0
+Subproject commit 97820ed81aba9ef7c05891ce80c53a8533b78609
diff --git a/include/daemon/backend/data/pmdk/pool.hpp b/include/daemon/backend/data/pmdk/pool.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..605202e43334a5f6e39ab4848c30d7275551e858
--- /dev/null
+++ b/include/daemon/backend/data/pmdk/pool.hpp
@@ -0,0 +1,162 @@
+/*
+ Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain
+ Copyright 2015-2021, 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.
+
+ This file is part of GekkoFS.
+
+ GekkoFS 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.
+
+ GekkoFS is distributed in the hope that it will be useful,
+ but WITHOUT 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 GekkoFS. If not, see .
+
+ SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#ifndef GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP
+#define GEKKOFS_DAEMON_DATA_PMDK_POOL_HPP
+
+#include
+#include
+
+namespace fs = std::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 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
\ No newline at end of file
diff --git a/scripts/compile_dep.sh b/scripts/compile_dep.sh
index d187b8115d5e24a7b35a14a424a146a5a51160f5..9c35e026484ce3425c2defe3ad2704bd454592ae 100755
--- a/scripts/compile_dep.sh
+++ b/scripts/compile_dep.sh
@@ -40,30 +40,30 @@ VALID_DEP_OPTIONS="mogon2 mogon1 ngio direct all ci"
MOGON1_DEPS=(
"zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "verbs"
+ "syscall_intercept" "date" "verbs" "pmdk"
)
MOGON2_DEPS=(
"bzip2" "zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "psm2"
+ "syscall_intercept" "date" "psm2" "pmdk"
)
NGIO_DEPS=(
"zstd" "lz4" "snappy" "capstone" "ofi" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "agios" "psm2"
+ "syscall_intercept" "date" "agios" "psm2" "pmdk"
)
DIRECT_DEPS=(
- "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date"
+ "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "pmdk"
)
ALL_DEPS=(
"bzip2" "zstd" "lz4" "snappy" "capstone" "bmi" "ofi" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "agios"
+ "syscall_intercept" "date" "agios" "pmdk"
)
CI_DEPS=(
- "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "agios"
+ "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "agios" "pmdk"
)
usage_short() {
@@ -514,4 +514,13 @@ if check_dependency "date" "${DEP_CONFIG[@]}"; then
make install
fi
+# PMDK
+if check_dependency "pmdk" "${DEP_CONFIG[@]}"; then
+ echo "############################################################ Installing: PMDK"
+ CURR=${SOURCE}/pmdk
+ cd "${CURR}"
+ make -j"${CORES}"
+ make install prefix="${INSTALL}"
+fi
+
echo "Done"
diff --git a/scripts/dl_dep.sh b/scripts/dl_dep.sh
index 9b4e90f34fd083481cd391b7664129893fe22866..63be02f61e2bef4ae2758ae22daa777f1f5c4461 100755
--- a/scripts/dl_dep.sh
+++ b/scripts/dl_dep.sh
@@ -40,30 +40,30 @@ VALID_DEP_OPTIONS="mogon2 mogon1 ngio direct all ci"
MOGON1_DEPS=(
"zstd" "lz4" "snappy" "capstone" "ofi-verbs" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date"
+ "syscall_intercept" "date" "pmdk"
)
MOGON2_DEPS=(
"bzip2" "zstd" "lz4" "snappy" "capstone" "ofi-experimental" "mercury" "argobots" "margo" "rocksdb-experimental"
- "syscall_intercept" "date" "psm2"
+ "syscall_intercept" "date" "psm2" "pmdk"
)
NGIO_DEPS=(
"zstd" "lz4" "snappy" "capstone" "ofi-experimental" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "psm2" "agios"
+ "syscall_intercept" "date" "psm2" "agios" "pmdk"
)
DIRECT_DEPS=(
- "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date"
+ "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "pmdk"
)
ALL_DEPS=(
"bzip2" "zstd" "lz4" "snappy" "capstone" "bmi" "ofi" "mercury" "argobots" "margo" "rocksdb"
- "syscall_intercept" "date" "agios"
+ "syscall_intercept" "date" "agios" "pmdk"
)
CI_DEPS=(
- "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "agios"
+ "ofi" "mercury" "argobots" "margo" "rocksdb" "syscall_intercept" "date" "agios" "pmdk"
)
# Stop all backround jobs on interruption.
@@ -434,6 +434,12 @@ fi
if check_dependency "date" "${DEP_CONFIG[@]}"; then
clonedeps "date" "https://github.com/HowardHinnant/date.git" "e7e1482087f58913b80a20b04d5c58d9d6d90155" &
fi
+
+# get PMDK
+if check_dependency "pmdk" "${DEP_CONFIG[@]}"; then
+ clonedeps "pmdk" "https://github.com/pmem/pmdk.git" "1.9.1" &
+fi
+
# Wait for all download to be completed
wait
echo "Done"
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index 608cff7b8280f54c8230a368ce234090c3fcdafa..c6ed44a18cf573131dd55d5a2ca15987a8c31a11 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -64,6 +64,7 @@ set(DAEMON_LINK_LIBRARIES
distributor
log_util
env_util
+ path_util
spdlog
fmt::fmt
path_util
@@ -71,6 +72,8 @@ set(DAEMON_LINK_LIBRARIES
${ABT_LIBRARIES}
mercury
${MARGO_LIBRARIES}
+ #PMDK
+ PMDK::pmem
# others
Boost::boost
Boost::program_options
diff --git a/src/daemon/backend/data/CMakeLists.txt b/src/daemon/backend/data/CMakeLists.txt
index e7d25c5af06310d6fd19600ae3365c445af34456..f7d3ea1de9c4d873e63e26c807d9cf462671899c 100644
--- a/src/daemon/backend/data/CMakeLists.txt
+++ b/src/daemon/backend/data/CMakeLists.txt
@@ -26,6 +26,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later #
################################################################################
+# import PMDK storage backend
+add_subdirectory(pmdk)
+
add_library(data_module
STATIC
)
@@ -58,6 +61,7 @@ target_link_libraries(storage
spdlog
data_module
path_util
+ pmdk_storage
# open issue for std::filesystem https://gitlab.kitware.com/cmake/cmake/-/issues/17834
stdc++fs
-ldl
diff --git a/src/daemon/backend/data/pmdk/CMakeLists.txt b/src/daemon/backend/data/pmdk/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2814ecb960b10c8e660ff8c307b7f9f5c3b391da
--- /dev/null
+++ b/src/daemon/backend/data/pmdk/CMakeLists.txt
@@ -0,0 +1,47 @@
+################################################################################
+# Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain #
+# Copyright 2015-2021, 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. #
+# #
+# This file is part of GekkoFS. #
+# #
+# GekkoFS 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. #
+# #
+# GekkoFS is distributed in the hope that it will be useful, #
+# but WITHOUT 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 GekkoFS. If not, see . #
+# #
+# SPDX-License-Identifier: GPL-3.0-or-later #
+################################################################################
+
+add_library(pmdk_storage
+ STATIC
+)
+
+target_sources(pmdk_storage
+ PRIVATE
+ ${CMAKE_CURRENT_LIST_DIR}/pool.cpp
+ PUBLIC
+ ${INCLUDE_DIR}/daemon/backend/data/pmdk/pool.hpp
+)
+
+target_link_libraries(pmdk_storage
+ PUBLIC
+ PMDK::pmem
+ data_module
+ Boost::system
+ std::filesystem
+ path_util
+)
diff --git a/src/daemon/backend/data/pmdk/pool.cpp b/src/daemon/backend/data/pmdk/pool.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..670bad2ece95b29a3b394ea05a412ab82925aa0a
--- /dev/null
+++ b/src/daemon/backend/data/pmdk/pool.cpp
@@ -0,0 +1,235 @@
+/*
+ Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain
+ Copyright 2015-2021, 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.
+
+ This file is part of GekkoFS.
+
+ GekkoFS 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.
+
+ GekkoFS is distributed in the hope that it will be useful,
+ but WITHOUT 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 GekkoFS. If not, see .
+
+ SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+namespace fs = std::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(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
\ No newline at end of file
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index dbdbcddb5603b856b9660095e79f9e39989c78e7..9793e97447172b7fe47c01d8d1b4160c054de085 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -67,6 +67,7 @@ add_executable(tests
test_utils_arithmetic.cpp
test_helpers.cpp
test_guided_distributor.cpp
+ test_storage_pmdk.cpp
)
target_link_libraries(tests
@@ -75,6 +76,8 @@ target_link_libraries(tests
helpers
arithmetic
distributor
+ data_module
+ pmdk_storage
)
# Catch2's contrib folder includes some helper functions
diff --git a/tests/unit/test_storage_pmdk.cpp b/tests/unit/test_storage_pmdk.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..69bc18682a92c591136b9ac42f809062ba0b7373
--- /dev/null
+++ b/tests/unit/test_storage_pmdk.cpp
@@ -0,0 +1,176 @@
+/*
+ Copyright 2018-2021, Barcelona Supercomputing Center (BSC), Spain
+ Copyright 2015-2021, 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.
+
+ This file is part of GekkoFS.
+
+ GekkoFS 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.
+
+ GekkoFS is distributed in the hope that it will be useful,
+ but WITHOUT 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 GekkoFS. If not, see .
+
+ SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#include
+#include "helpers/helpers.hpp"
+
+#include
+#include
+#include
+
+namespace fs = std::filesystem;
+
+using namespace std::string_literals;
+using namespace Catch::Matchers;
+
+// FIXME: temporary solution to have correct loggers for tests
+#include
+
+#include
+#include
+
+
+namespace {
+
+void
+patch_gkfs_loggers(const std::vector& loggers_name,
+ spdlog::level::level_enum level, const std::string& path) {
+
+ /* Create common sink */
+ auto file_sink = std::make_shared(path);
+
+ /* Create and configure loggers */
+ auto loggers = std::list>();
+ for(const auto& name : loggers_name) {
+
+ if(spdlog::get(name)) {
+ continue;
+ }
+
+ auto logger = std::make_shared(name, file_sink);
+ logger->flush_on(spdlog::level::trace);
+ loggers.push_back(logger);
+ }
+
+ /* register loggers */
+ for(const auto& logger : loggers) {
+ spdlog::register_logger(logger);
+ }
+
+ // set logger format
+ spdlog::set_pattern("[%C-%m-%d %H:%M:%S.%f] %P [%L][%n] %v");
+
+ spdlog::set_level(level);
+}
+
+} // namespace
+
+// end of temporary solution
+
+SCENARIO("PMDK pools can be created", "[pmdk_storage_pool]") {
+
+
+ auto logger_names = std::vector{
+ "main",
+ "MetadataModule",
+ "DataModule",
+ };
+
+ ::patch_gkfs_loggers(logger_names, spdlog::level::debug, "/dev/stdout");
+
+ GIVEN("A valid parent directory ") {
+
+ WHEN("Size is a positive integer") {
+
+ std::size_t pool_size = 420;
+ helpers::temporary_directory tmpdir;
+
+ pmdk::pool p(tmpdir.dirname(), pool_size);
+
+ THEN("The pool object is valid ") {
+ REQUIRE(p);
+ REQUIRE(p.valid());
+ REQUIRE(p.size() == pool_size);
+ REQUIRE(p.data() != nullptr);
+ }
+
+ AND_THEN("The mapping file exists and has the correct size") {
+ REQUIRE(fs::exists(p.path()));
+ REQUIRE(fs::file_size(p.path()) == pool_size);
+ }
+ }
+
+ WHEN("Size is zero") {
+
+ helpers::temporary_directory tmpdir;
+
+ pmdk::pool p(tmpdir.dirname(), 0);
+
+ THEN("The pool object is invalid ") {
+ REQUIRE(!p);
+ REQUIRE(!p.valid());
+
+ AND_THEN("Internal members are default initialized") {
+ REQUIRE(p.path().empty());
+ REQUIRE(p.data() == nullptr);
+ REQUIRE(p.size() == 0);
+ }
+ }
+ }
+
+ WHEN("Size is negative") {
+
+ helpers::temporary_directory tmpdir;
+
+ pmdk::pool p(tmpdir.dirname(), -1);
+
+ THEN("The pool object is invalid ") {
+ REQUIRE(!p);
+ REQUIRE(!p.valid());
+
+ AND_THEN("Internal members are default initialized") {
+ REQUIRE(p.path().empty());
+ REQUIRE(p.data() == nullptr);
+ REQUIRE(p.size() == 0);
+ }
+ }
+ }
+ }
+
+ GIVEN("An invalid parent directory ") {
+
+ WHEN("Parent directory does not exist") {
+
+ std::size_t pool_size = 420;
+ helpers::temporary_directory tmpdir;
+
+ pmdk::pool p("/foo/bar/", pool_size);
+
+ THEN("The pool object is invalid ") {
+ REQUIRE(!p);
+ REQUIRE(!p.valid());
+
+ AND_THEN("Internal members are default initialized") {
+ REQUIRE(p.path().empty());
+ REQUIRE(p.data() == nullptr);
+ REQUIRE(p.size() == 0);
+ }
+ }
+ }
+ }
+}