From db0d96ca005fd05e9a948ef1b995fce93401c795 Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Fri, 19 Mar 2021 17:56:12 +0800 Subject: [PATCH 1/9] add new experimental storage engine PSKIPLIST contributed by 4Paradigm --- .gitmodules | 3 + CMakeLists.txt | 24 +- src/engines-experimental/pskiplist | 1 + src/engines-experimental/pskiplist.cc | 490 ++++++++++++++++++++++++++ src/engines-experimental/pskiplist.h | 145 ++++++++ 5 files changed, 659 insertions(+), 4 deletions(-) create mode 100644 .gitmodules create mode 160000 src/engines-experimental/pskiplist create mode 100644 src/engines-experimental/pskiplist.cc create mode 100644 src/engines-experimental/pskiplist.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..92f652b44 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/engines-experimental/pskiplist"] + path = src/engines-experimental/pskiplist + url = https://github.com/4paradigm/pskiplist.git diff --git a/CMakeLists.txt b/CMakeLists.txt index bc67a72a3..7979b952d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,13 @@ set_version(VERSION) ## CMake build options # ----------------------------------------------------------------- # option(BUILD_DOC "build documentation" ON) -option(BUILD_EXAMPLES "build examples" ON) +option(BUILD_EXAMPLES "build examples" OFF) option(BUILD_TESTS "build tests" ON) option(BUILD_JSON_CONFIG "build the 'libpmemkv_json_config' library" ON) option(TESTS_LONG "enable long running tests" OFF) option(TESTS_USE_FORCED_PMEM "run tests with PMEM_IS_PMEM_FORCE=1 - it speeds up tests execution on emulated pmem" OFF) -option(TESTS_USE_VALGRIND "enable tests with valgrind (if found)" ON) +option(TESTS_USE_VALGRIND "enable tests with valgrind (if found)" OFF) option(TESTS_PMEMOBJ_DRD_HELGRIND "enable test of pmemobj engines under drd and helgrind (they should only be run on PMEM)" OFF) option(TESTS_JSON "enable tests which require libpmemkv_json_config library (BUILD_JSON_CONFIG has to be ON)" ON) @@ -30,13 +30,15 @@ option(USE_CCACHE "use ccache if it is available in the system" ON) # Each engine can be enabled separately. option(ENGINE_CMAP "enable cmap engine" ON) -option(ENGINE_VCMAP "enable vcmap engine" ON) -option(ENGINE_VSMAP "enable vsmap engine" ON) +option(ENGINE_VCMAP "enable vcmap engine" OFF) +option(ENGINE_VSMAP "enable vsmap engine" OFF) option(ENGINE_CSMAP "enable experimental csmap engine (requires CXX_STANDARD to be set to value >= 14)" OFF) option(ENGINE_STREE "enable experimental stree engine" ON) option(ENGINE_TREE3 "enable experimental tree3 engine" OFF) option(ENGINE_RADIX "enable experimental radix engine" OFF) +option(ENGINE_PSKIPLIST "enable experimental pskiplist engine" ON) + # ----------------------------------------------------------------- # ## Set required and useful variables # ----------------------------------------------------------------- # @@ -141,6 +143,14 @@ if(ENGINE_RADIX) src/engines-experimental/radix.cc ) endif() +if(ENGINE_PSKIPLIST) + list(APPEND SOURCE_FILES + src/engines-experimental/pskiplist.h + src/engines-experimental/pskiplist.cc + src/engines-experimental/pskiplist/persistent_skiplist.h + src/engines-experimental/pskiplist/smartpptr.h + ) +endif() # ----------------------------------------------------------------- # ## Setup defines and check status of each engine @@ -191,6 +201,12 @@ if(ENGINE_RADIX) else() message(STATUS "RADIX engine is OFF") endif() +if(ENGINE_PSKIPLIST) + add_definitions(-DENGINE_PSKIPLIST) + message(STATUS "PSKIPLIST engine is ON") +else() + message(STATUS "PSKIPLIST engine is OFF") +endif() # ----------------------------------------------------------------- # ## Set compiler's flags diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist new file mode 160000 index 000000000..2bc1ab05c --- /dev/null +++ b/src/engines-experimental/pskiplist @@ -0,0 +1 @@ +Subproject commit 2bc1ab05c3460adb298947392aa888db4144889d diff --git a/src/engines-experimental/pskiplist.cc b/src/engines-experimental/pskiplist.cc new file mode 100644 index 000000000..d7dfa3479 --- /dev/null +++ b/src/engines-experimental/pskiplist.cc @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2017-2021, 4Paradigm Inc. */ + +#include +#include + +#include +#include + +#include "../out.h" +#include "pskiplist.h" + +using pmem::detail::conditional_add_to_tx; +using pmem::obj::make_persistent_atomic; +using pmem::obj::transaction; + +namespace pmem +{ +namespace kv +{ + +pskiplist::pskiplist(std::unique_ptr cfg) + : pmemobj_engine_base(cfg, "pmemkv_pskiplist"), config(std::move(cfg)) +{ + Recover(); + LOG("Started ok"); +} + +pskiplist::~pskiplist() +{ + LOG("Stopped ok"); +} + +std::string pskiplist::name() +{ + return "pskiplist"; +} + +status pskiplist::count_all(std::size_t &cnt) +{ + LOG("count_all"); + check_outside_tx(); + + cnt = my_skiplist->size(); + + return status::OK; +} + +template +static std::size_t size(It first, It last) +{ + auto dist = std::distance(first, last); + assert(dist >= 0); + + return static_cast(dist); +} + +/* above key, key exclusive */ +status pskiplist::count_above(string_view key, std::size_t &cnt) +{ + LOG("count_above key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->upper_bound(key); + auto last = my_skiplist->end(); + + cnt = size(first, last); + + return status::OK; +} + +/* above or equal to key, key inclusive */ +status pskiplist::count_equal_above(string_view key, std::size_t &cnt) +{ + LOG("count_equal_above key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->lower_bound(key); + auto last = my_skiplist->end(); + + cnt = size(first, last); + + return status::OK; +} + +/* below key, key exclusive */ +status pskiplist::count_below(string_view key, std::size_t &cnt) +{ + LOG("count_below key<" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->begin(); + auto last = my_skiplist->lower_bound(key); + + cnt = size(first, last); + + return status::OK; +} + +/* below or equal to key, key inclusive */ +status pskiplist::count_equal_below(string_view key, std::size_t &cnt) +{ + LOG("count_equal_below key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->begin(); + auto last = my_skiplist->upper_bound(key); + + cnt = size(first, last); + + return status::OK; +} + +status pskiplist::count_between(string_view key1, string_view key2, std::size_t &cnt) +{ + LOG("count_between key range=[" << std::string(key1.data(), key1.size()) << "," + << std::string(key2.data(), key2.size()) << ")"); + check_outside_tx(); + + if (my_skiplist->key_comp()(key1, key2)) { + auto first = my_skiplist->upper_bound(key1); + auto last = my_skiplist->lower_bound(key2); + + cnt = size(first, last); + } else { + cnt = 0; + } + + return status::OK; +} + +status pskiplist::iterate(container_iterator first, container_iterator last, + get_kv_callback *callback, void *arg) +{ + for (auto it = first; it != last; ++it) { + auto ret = callback(it->first.c_str(), it->first.size(), + it->second.c_str(), it->second.size(), arg); + + if (ret != 0) + return status::STOPPED_BY_CB; + } + + return status::OK; +} + +status pskiplist::get_all(get_kv_callback *callback, void *arg) +{ + LOG("get_all"); + check_outside_tx(); + + auto first = my_skiplist->begin(); + auto last = my_skiplist->end(); + + return iterate(first, last, callback, arg); +} + +/* (key, end), above key */ +status pskiplist::get_above(string_view key, get_kv_callback *callback, void *arg) +{ + LOG("get_above start key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->upper_bound(key); + auto last = my_skiplist->end(); + + return iterate(first, last, callback, arg); +} + +/* [key, end), above or equal to key */ +status pskiplist::get_equal_above(string_view key, get_kv_callback *callback, void *arg) +{ + LOG("get_equal_above start key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->lower_bound(key); + auto last = my_skiplist->end(); + + return iterate(first, last, callback, arg); +} + +/* [start, key], below or equal to key */ +status pskiplist::get_equal_below(string_view key, get_kv_callback *callback, void *arg) +{ + LOG("get_equal_below start key>=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->begin(); + auto last = my_skiplist->upper_bound(key); + + return iterate(first, last, callback, arg); +} + +/* [start, key), less than key, key exclusive */ +status pskiplist::get_below(string_view key, get_kv_callback *callback, void *arg) +{ + LOG("get_below key<" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto first = my_skiplist->begin(); + auto last = my_skiplist->lower_bound(key); + + return iterate(first, last, callback, arg); +} + +/* get between (key1, key2), key1 exclusive, key2 exclusive */ +status pskiplist::get_between(string_view key1, string_view key2, get_kv_callback *callback, + void *arg) +{ + LOG("get_between key range=[" << std::string(key1.data(), key1.size()) << "," + << std::string(key2.data(), key2.size()) << ")"); + check_outside_tx(); + + if (my_skiplist->key_comp()(key1, key2)) { + auto first = my_skiplist->upper_bound(key1); + auto last = my_skiplist->lower_bound(key2); + + return iterate(first, last, callback, arg); + } + + return status::OK; +} + +status pskiplist::exists(string_view key) +{ + LOG("exists for key=" << std::string(key.data(), key.size())); + check_outside_tx(); + + internal::pskiplist::skiplist_type::iterator it = my_skiplist->find(key); + if (it == my_skiplist->end()) { + LOG(" key not found"); + return status::NOT_FOUND; + } + return status::OK; +} + +status pskiplist::get(string_view key, get_v_callback *callback, void *arg) +{ + LOG("get using callback for key=" << std::string(key.data(), key.size())); + check_outside_tx(); + + internal::pskiplist::skiplist_type::iterator it = my_skiplist->find(key); + if (it == my_skiplist->end()) { + LOG(" key not found"); + return status::NOT_FOUND; + } + + callback(it->second.c_str(), it->second.size(), arg); + return status::OK; +} + +status pskiplist::put(string_view key, string_view value) +{ + LOG("put key=" << std::string(key.data(), key.size()) + << ", value.size=" << std::to_string(value.size())); + check_outside_tx(); + + auto result = my_skiplist->try_emplace(key, value); + if (!result.second) { // key already exists, so update + typename internal::pskiplist::skiplist_type::value_type &entry = *result.first; + transaction::manual tx(pmpool); + entry.second = value; + transaction::commit(); + } + return status::OK; +} + +status pskiplist::remove(string_view key) +{ + LOG("remove key=" << std::string(key.data(), key.size())); + check_outside_tx(); + + auto result = my_skiplist->erase(key); + return (result == 1) ? status::OK : status::NOT_FOUND; +} + +void pskiplist::Recover() +{ + if (!OID_IS_NULL(*root_oid)) { + my_skiplist = (internal::pskiplist::skiplist_type *)pmemobj_direct(*root_oid); + my_skiplist->key_comp().runtime_initialize( + internal::extract_comparator(*config)); + } else { + pmem::obj::transaction::run(pmpool, [&] { + pmem::obj::transaction::snapshot(root_oid); + *root_oid = + pmem::obj::make_persistent() + .raw(); + my_skiplist = + (internal::pskiplist::skiplist_type *)pmemobj_direct(*root_oid); + my_skiplist->key_comp().initialize( + internal::extract_comparator(*config)); + }); + } +} + +internal::iterator_base *pskiplist::new_iterator() +{ + return new pskiplist_iterator{my_skiplist}; +} + +internal::iterator_base *pskiplist::new_const_iterator() +{ + return new pskiplist_iterator{my_skiplist}; +} + +pskiplist::pskiplist_iterator::pskiplist_iterator(container_type *c) + : container(c), it_(nullptr), pop(pmem::obj::pool_by_vptr(c)) +{ +} + +pskiplist::pskiplist_iterator::pskiplist_iterator(container_type *c) + : pskiplist::pskiplist_iterator(c) +{ +} + +status pskiplist::pskiplist_iterator::seek(string_view key) +{ + init_seek(); + + it_ = container->find(key); + if (it_ != container->end()) + return status::OK; + + return status::NOT_FOUND; +} + +status pskiplist::pskiplist_iterator::seek_lower(string_view key) +{ + init_seek(); + + it_ = container->lower_bound(key); + if (it_ == container->begin()) { + it_ = container->end(); + return status::NOT_FOUND; + } + + // --it_; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::seek_lower_eq(string_view key) +{ + init_seek(); + + it_ = container->upper_bound(key); + if (it_ == container->begin()) { + it_ = container->end(); + return status::NOT_FOUND; + } + + // --it_; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::seek_higher(string_view key) +{ + init_seek(); + + it_ = container->upper_bound(key); + if (it_ == container->end()) + return status::NOT_FOUND; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::seek_higher_eq(string_view key) +{ + init_seek(); + + it_ = container->lower_bound(key); + if (it_ == container->end()) + return status::NOT_FOUND; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::seek_to_first() +{ + init_seek(); + + if (container->size() == 0) + return status::NOT_FOUND; + + it_ = container->begin(); + + return status::OK; +} + +status pskiplist::pskiplist_iterator::seek_to_last() +{ + // init_seek(); + + // if (container->size() == 0) + // return status::NOT_FOUND; + + // it_ = container->end(); + // --it_; + + // return status::OK; + + return status::NOT_SUPPORTED; +} + +status pskiplist::pskiplist_iterator::is_next() +{ + auto tmp = it_; + if (tmp == container->end() || ++tmp == container->end()) + return status::NOT_FOUND; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::next() +{ + init_seek(); + + if (it_ == container->end() || ++it_ == container->end()) + return status::NOT_FOUND; + + return status::OK; +} + +status pskiplist::pskiplist_iterator::prev() +{ + // init_seek(); + + // if (it_ == container->begin()) + // return status::NOT_FOUND; + + // --it_; + + // return status::OK; + + return status::NOT_SUPPORTED; +} + +result pskiplist::pskiplist_iterator::key() +{ + assert(it_ != container->end()); + + return {it_->first.cdata()}; +} + +result> pskiplist::pskiplist_iterator::read_range(size_t pos, + size_t n) +{ + assert(it_ != container->end()); + + if (pos + n > it_->second.size() || pos + n < pos) + n = it_->second.size() - pos; + + return {it_->second.crange(pos, n)}; +} + +result> pskiplist::pskiplist_iterator::write_range(size_t pos, + size_t n) +{ + assert(it_ != container->end()); + + if (pos + n > it_->second.size() || pos + n < pos) + n = it_->second.size() - pos; + + log.push_back({{it_->second.cdata() + pos, n}, pos}); + auto &val = log.back().first; + + return {{&val[0], &val[0] + n}}; +} + +status pskiplist::pskiplist_iterator::commit() +{ + pmem::obj::transaction::run(pop, [&] { + for (auto &p : log) { + auto dest = it_->second.range(p.second, p.first.size()); + std::copy(p.first.begin(), p.first.end(), dest.begin()); + } + }); + log.clear(); + + return status::OK; +} + +void pskiplist::pskiplist_iterator::abort() +{ + log.clear(); +} + +} // namespace kv +} // namespace pmem diff --git a/src/engines-experimental/pskiplist.h b/src/engines-experimental/pskiplist.h new file mode 100644 index 000000000..b18a62827 --- /dev/null +++ b/src/engines-experimental/pskiplist.h @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* Copyright 2017-2021, 4Paradigm Inc. */ + +#pragma once + +#include +#include +#include + +#include "../comparator/pmemobj_comparator.h" +#include "../iterator.h" +#include "../pmemobj_engine.h" +#include "pskiplist/persistent_skiplist.h" + +using pmem::obj::persistent_ptr; +using pmem::obj::pool; + +using namespace pmem::obj; +using namespace pmem::obj::experimental; + +#define DEFAULT_HEIGHT 8 +#define DEFAULT_BRANCH 4 + +namespace pmem +{ +namespace kv +{ +namespace internal +{ +namespace pskiplist +{ + +/** + * Indicates the maximum number of descendants a single node can have. + * DEGREE - 1 is the maximum number of entries a node can have. + */ +const size_t HEIGHT = 8; +const size_t BRANCH = 4; + +using string_t = pmem::obj::string; + +using key_type = string_t; +using value_type = string_t; +using skiplist_type = persistent_skiplist; + +} /* namespace pskiplist */ +} /* namespace internal */ + +class pskiplist : public pmemobj_engine_base { +private: + using container_type = internal::pskiplist::skiplist_type; + using container_iterator = typename container_type::iterator; + + template + class pskiplist_iterator; + +public: + pskiplist(std::unique_ptr cfg); + ~pskiplist(); + + std::string name() final; + + status count_all(std::size_t &cnt) final; + status count_above(string_view key, std::size_t &cnt) final; + status count_equal_above(string_view key, std::size_t &cnt) final; + status count_equal_below(string_view key, std::size_t &cnt) final; + status count_below(string_view key, std::size_t &cnt) final; + status count_between(string_view key1, string_view key2, std::size_t &cnt) final; + + status get_all(get_kv_callback *callback, void *arg) final; + status get_above(string_view key, get_kv_callback *callback, void *arg) final; + status get_equal_above(string_view key, get_kv_callback *callback, + void *arg) final; + status get_equal_below(string_view key, get_kv_callback *callback, + void *arg) final; + status get_below(string_view key, get_kv_callback *callback, void *arg) final; + status get_between(string_view key1, string_view key2, get_kv_callback *callback, + void *arg) final; + status exists(string_view key) final; + status get(string_view key, get_v_callback *callback, void *arg) final; + status put(string_view key, string_view value) final; + status remove(string_view key) final; + + internal::iterator_base *new_iterator() final; + internal::iterator_base *new_const_iterator() final; + +private: + pskiplist(const pskiplist &); + void operator=(const pskiplist &); + status iterate(container_iterator first, container_iterator last, + get_kv_callback *callback, void *arg); + void Recover(); + + internal::pskiplist::skiplist_type *my_skiplist; + std::unique_ptr config; +}; + +template <> +class pskiplist::pskiplist_iterator : virtual public internal::iterator_base { + using container_type = pskiplist::container_type; + +public: + pskiplist_iterator(container_type *container); + + status seek(string_view key) final; + status seek_lower(string_view key) final; + status seek_lower_eq(string_view key) final; + status seek_higher(string_view key) final; + status seek_higher_eq(string_view key) final; + + status seek_to_first() final; + status seek_to_last() final; + + status is_next() final; + status next() final; + status prev() final; + + result key() final; + + result> read_range(size_t pos, size_t n) final; + +protected: + container_type *container; + container_type::iterator it_; + pmem::obj::pool_base pop; +}; + +template <> +class pskiplist::pskiplist_iterator : public pskiplist::pskiplist_iterator { + using container_type = pskiplist::container_type; + +public: + pskiplist_iterator(container_type *container); + + result> write_range(size_t pos, size_t n) final; + + status commit() final; + void abort() final; + +private: + std::vector> log; +}; + +} /* namespace kv */ +} /* namespace pmem */ From 4929622a197488e48d531add1c8d0be15408c7af Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Tue, 23 Mar 2021 16:56:14 +0800 Subject: [PATCH 2/9] update engine readme and cmakelists --- CMakeLists.txt | 14 ++++++++++++++ doc/ENGINES-experimental.md | 23 +++++++++++++++++++++++ src/engine.cc | 4 ++++ src/engines-experimental/pskiplist | 2 +- src/pmemobj_engine.h | 4 ++-- 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80fe9f6bb..1546196b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,11 +143,24 @@ if(ENGINE_RADIX) ) endif() if(ENGINE_PSKIPLIST) + find_package(Git QUIET) + if(GIT_SUBMODULE) + message(STATUS "Submodule update for ENGINE_PSKIPLIST") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT) + if(NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() + endif() list(APPEND SOURCE_FILES src/engines-experimental/pskiplist.h src/engines-experimental/pskiplist.cc src/engines-experimental/pskiplist/persistent_skiplist.h src/engines-experimental/pskiplist/smartpptr.h + ) + +endif() if(ENGINE_ROBINHOOD) list(APPEND SOURCE_FILES src/engines-experimental/robinhood.h @@ -218,6 +231,7 @@ if(ENGINE_PSKIPLIST) message(STATUS "PSKIPLIST engine is ON") else() message(STATUS "PSKIPLIST engine is OFF") +endif() if(ENGINE_ROBINHOOD) add_definitions(-DENGINE_ROBINHOOD) message(STATUS "ROBINHOOD engine is ON") diff --git a/doc/ENGINES-experimental.md b/doc/ENGINES-experimental.md index 6ad6ba254..1b9c65773 100644 --- a/doc/ENGINES-experimental.md +++ b/doc/ENGINES-experimental.md @@ -5,6 +5,7 @@ - [radix](#radix) - [stree](#stree) - [robinhood](#robinhood) +- [pskiplist](#pskiplist) # tree3 @@ -133,6 +134,28 @@ There are two parameters to be optionally modified by env variables: No additional packages are required. +# pskiplist + +A persistent and concurrent engine, backed by a skiplist implemented using Persistent Compare and Swap (PCAS), contributed by [4Paradigm Inc.](http://www.4paradigm.com/). The skiplist data structure is firstly introduced in a [VLDB paper](http://vldb.org/pvldb/vol14/p799-chen.pdf)). It can be enabled in CMakeLists.txt using the `ENGINE_PSKIPLIST` option. + +### Configuration + +* **path** -- Path to the database file (layout "pmemkv_stree") + + type: string +* **force_create** -- If 0, pmemkv opens file specified by 'path', otherwise it creates it + + type: uint64_t + + default value: 0 +* **size** -- Only needed when force_create is not 0, specifies size of the database [in bytes] + + type: uint64_t + +### Internals + +(TBD) + +### Prerequisites + +No additional packages are required. + # Related Work --------- diff --git a/src/engine.cc b/src/engine.cc index deff18254..aaedd1808 100644 --- a/src/engine.cc +++ b/src/engine.cc @@ -41,6 +41,10 @@ #include "engines-testing/dram_vcmap.h" #endif +#ifdef ENGINE_PSKIPLIST +#include "engines-experimental/pskiplist.h" +#endif + namespace pmem { namespace kv diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist index 2bc1ab05c..f5fcafde0 160000 --- a/src/engines-experimental/pskiplist +++ b/src/engines-experimental/pskiplist @@ -1 +1 @@ -Subproject commit 2bc1ab05c3460adb298947392aa888db4144889d +Subproject commit f5fcafde08f41f7e6c59fa4251bc61aa93546c89 diff --git a/src/pmemobj_engine.h b/src/pmemobj_engine.h index 464fc616b..ce4686036 100644 --- a/src/pmemobj_engine.h +++ b/src/pmemobj_engine.h @@ -62,13 +62,13 @@ class pmemobj_engine_base : public engine_base { try { pop = pmem::obj::pool::create( path, layout, size, S_IRWXU); - } catch (pmem::pool_invalid_argument &e) { + } catch (pmem::pool_error &e) { throw internal::invalid_argument(e.what()); } } else { try { pop = pmem::obj::pool::open(path, layout); - } catch (pmem::pool_invalid_argument &e) { + } catch (pmem::pool_error &e) { throw internal::invalid_argument(e.what()); } } From d58ffbfdb81769a6fd3c0b3188ca587263c38b23 Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Tue, 23 Mar 2021 17:27:14 +0800 Subject: [PATCH 3/9] fix license for ENGINE_PSKIPLIST --- src/engines-experimental/pskiplist | 2 +- src/engines-experimental/pskiplist.cc | 2 +- src/engines-experimental/pskiplist.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist index f5fcafde0..8af6cb709 160000 --- a/src/engines-experimental/pskiplist +++ b/src/engines-experimental/pskiplist @@ -1 +1 @@ -Subproject commit f5fcafde08f41f7e6c59fa4251bc61aa93546c89 +Subproject commit 8af6cb7090774afcac48d2955dc83d50b87d1145 diff --git a/src/engines-experimental/pskiplist.cc b/src/engines-experimental/pskiplist.cc index d7dfa3479..29da6c069 100644 --- a/src/engines-experimental/pskiplist.cc +++ b/src/engines-experimental/pskiplist.cc @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2017-2021, 4Paradigm Inc. */ +/* Copyright 2021, 4Paradigm Inc. */ #include #include diff --git a/src/engines-experimental/pskiplist.h b/src/engines-experimental/pskiplist.h index b18a62827..c58b032e3 100644 --- a/src/engines-experimental/pskiplist.h +++ b/src/engines-experimental/pskiplist.h @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BSD-3-Clause -/* Copyright 2017-2021, 4Paradigm Inc. */ +/* Copyright 2021, 4Paradigm Inc. */ #pragma once From 7e879b11e97836d61ce5a8128c943b73e1136263 Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Wed, 24 Mar 2021 11:26:54 +0800 Subject: [PATCH 4/9] add submodule update in CMakeLists for ENGINE_PSKIPLIST --- CMakeLists.txt | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1546196b7..33201b5c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,13 @@ set_version(VERSION) ## CMake build options # ----------------------------------------------------------------- # option(BUILD_DOC "build documentation" ON) -option(BUILD_EXAMPLES "build examples" OFF) +option(BUILD_EXAMPLES "build examples" ON) option(BUILD_TESTS "build tests" ON) option(BUILD_JSON_CONFIG "build the 'libpmemkv_json_config' library" ON) option(TESTS_LONG "enable long running tests" OFF) option(TESTS_USE_FORCED_PMEM "run tests with PMEM_IS_PMEM_FORCE=1 - it speeds up tests execution on emulated pmem" OFF) -option(TESTS_USE_VALGRIND "enable tests with valgrind (if found)" OFF) +option(TESTS_USE_VALGRIND "enable tests with valgrind (if found)" ON) option(TESTS_PMEMOBJ_DRD_HELGRIND "enable test of pmemobj engines under drd and helgrind (they should only be run on PMEM)" OFF) option(TESTS_JSON "enable tests which require libpmemkv_json_config library (BUILD_JSON_CONFIG has to be ON)" ON) @@ -30,8 +30,8 @@ option(USE_CCACHE "use ccache if it is available in the system" ON) # Each engine can be enabled separately. option(ENGINE_CMAP "enable cmap engine" ON) -option(ENGINE_VCMAP "enable vcmap engine" OFF) -option(ENGINE_VSMAP "enable vsmap engine" OFF) +option(ENGINE_VCMAP "enable vcmap engine" ON) +option(ENGINE_VSMAP "enable vsmap engine" ON) option(ENGINE_CSMAP "enable experimental csmap engine (requires CXX_STANDARD to be set to value >= 14)" OFF) option(ENGINE_STREE "enable experimental stree engine" ON) option(ENGINE_TREE3 "enable experimental tree3 engine" OFF) @@ -142,24 +142,25 @@ if(ENGINE_RADIX) src/engines-experimental/radix.cc ) endif() +# checkout submodule for ENGINE_PSKIPLIST +find_package(Git QUIET) +option(GIT_SUBMODULE "Check submodules during build" ON) +if(GIT_SUBMODULE) + message(STATUS "Submodule update for ENGINE_PSKIPLIST") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_PSKIPLIST) +endif() if(ENGINE_PSKIPLIST) - find_package(Git QUIET) - if(GIT_SUBMODULE) - message(STATUS "Submodule update for ENGINE_PSKIPLIST") - execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - RESULT_VARIABLE GIT_SUBMOD_RESULT) - if(NOT GIT_SUBMOD_RESULT EQUAL "0") - message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") - endif() - endif() + if(NOT GIT_SUBMOD_PSKIPLIST EQUAL "0") + message(FATAL_ERROR "git submodule update for ENGINE_PSKIPLIST failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() list(APPEND SOURCE_FILES src/engines-experimental/pskiplist.h src/engines-experimental/pskiplist.cc src/engines-experimental/pskiplist/persistent_skiplist.h src/engines-experimental/pskiplist/smartpptr.h ) - endif() if(ENGINE_ROBINHOOD) list(APPEND SOURCE_FILES From fa2cbcdb15ffac966b909a00c0d8ba7a05100d6b Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Mon, 29 Mar 2021 10:30:08 +0800 Subject: [PATCH 5/9] update pskiplist --- src/engines-experimental/pskiplist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist index 8af6cb709..2dfe8bba8 160000 --- a/src/engines-experimental/pskiplist +++ b/src/engines-experimental/pskiplist @@ -1 +1 @@ -Subproject commit 8af6cb7090774afcac48d2955dc83d50b87d1145 +Subproject commit 2dfe8bba8db213c8177b680d7397761052d4d4e5 From 3fb516e6d63b44a261ac389e768bc7b0fc8d452b Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Tue, 30 Mar 2021 10:48:02 +0800 Subject: [PATCH 6/9] add some tests --- CMakeLists.txt | 1 + src/engine.cc | 10 +++++++ src/engines-experimental/pskiplist | 2 +- tests/CMakeLists.txt | 39 +++++++++++++++++++++++++++ tests/engines/pskiplist/default.cmake | 20 ++++++++++++++ tests/engines/pskiplist/helpers.cmake | 11 ++++++++ tests/wrong_engine_name_test.cc | 3 +++ 7 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/engines/pskiplist/default.cmake create mode 100644 tests/engines/pskiplist/helpers.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 33201b5c8..ab75b7df1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,7 @@ if(ENGINE_PSKIPLIST) src/engines-experimental/pskiplist.cc src/engines-experimental/pskiplist/persistent_skiplist.h src/engines-experimental/pskiplist/smartpptr.h + src/engines-experimental/pskiplist/log4p.h ) endif() if(ENGINE_ROBINHOOD) diff --git a/src/engine.cc b/src/engine.cc index aaedd1808..a5b7b2cfc 100644 --- a/src/engine.cc +++ b/src/engine.cc @@ -85,6 +85,9 @@ static constexpr const char *available_engines = "blackhole" #endif #ifdef ENGINE_DRAM_VCMAP ", dram_vcmap" +#endif +#ifdef ENGINE_PSKIPLIST + ", pskiplist" #endif ; @@ -171,6 +174,13 @@ engine_base::create_engine(const std::string &engine, } #endif +#ifdef ENGINE_PSKIPLIST + if (engine == "pskiplist") { + engine_base::check_config_null(engine, cfg); + return std::unique_ptr(new pmem::kv::pskiplist(std::move(cfg))); + } +#endif + throw internal::wrong_engine_name("Unknown engine name \"" + engine + "\". Available engines: " + available_engines); } diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist index 2dfe8bba8..457bdf944 160000 --- a/src/engines-experimental/pskiplist +++ b/src/engines-experimental/pskiplist @@ -1 +1 @@ -Subproject commit 2dfe8bba8db213c8177b680d7397761052d4d4e5 +Subproject commit 457bdf9443f881608d97b7c8189e601fc6b813bd diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 64d2edb58..21ee1bd8a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -224,6 +224,45 @@ add_engine_test(ENGINE blackhole TRACERS none memcheck SCRIPT blackhole/default.cmake) ################################################################################ + +###################################### PSKIPLIST ############################## +if(ENGINE_PSKIPLIST) + add_engine_test(ENGINE pskiplist + BINARY c_api_null_db_config + TRACERS none memcheck + SCRIPT pskiplist/default.cmake) + + add_engine_test(ENGINE pskiplist + BINARY put_get_remove + TRACERS none memcheck pmemcheck + SCRIPT pskiplist/default.cmake) + + add_engine_test(ENGINE pskiplist + BINARY put_get_remove_not_aligned + TRACERS none #memcheck pmemcheck + SCRIPT pskiplist/default.cmake) + + + add_engine_test(ENGINE pskiplist + BINARY put_get_remove_charset_params + TRACERS none #memcheck pmemcheck + SCRIPT pskiplist/default.cmake + PARAMS 16 8) + + add_engine_test(ENGINE pskiplist + BINARY put_get_remove_long_key + TRACERS none #memcheck pmemcheck + SCRIPT pskiplist/default.cmake) + + add_engine_test(ENGINE pskiplist + BINARY put_get_remove_params + TRACERS none + SCRIPT pskiplist/default.cmake + DB_SIZE 4G PARAMS 400000) + +endif(ENGINE_PSKIPLIST) +################################################################################ + ##################################### CMAP #################################### if(ENGINE_CMAP) add_engine_test(ENGINE cmap diff --git a/tests/engines/pskiplist/default.cmake b/tests/engines/pskiplist/default.cmake new file mode 100644 index 000000000..9492efca9 --- /dev/null +++ b/tests/engines/pskiplist/default.cmake @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation + +include(${PARENT_SRC_DIR}/helpers.cmake) +include(${PARENT_SRC_DIR}/engines/pmemobj_based/helpers.cmake) + +setup() + +if ((${TRACER} STREQUAL "drd") OR (${TRACER} STREQUAL "helgrind")) + check_is_pmem(${DIR}/testfile) +endif() + +execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory /mnt/pmem0/${TEST_NAME}) +execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory /mnt/pmem0/${TEST_NAME}) +pmempool_execute(create -l ${LAYOUT} -s ${DB_SIZE} obj /mnt/pmem0/${TEST_NAME}/testfile) + +make_config({"path":"/mnt/pmem0/${TEST_NAME}/testfile"}) +execute(${TEST_EXECUTABLE} ${ENGINE} ${CONFIG} ${PARAMS}) + +finish() diff --git a/tests/engines/pskiplist/helpers.cmake b/tests/engines/pskiplist/helpers.cmake new file mode 100644 index 000000000..88a09a46a --- /dev/null +++ b/tests/engines/pskiplist/helpers.cmake @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright 2020, Intel Corporation + +# +# helpers.cmake - helper functions for tests' (cmake) scripts (pmemobj_based engines only) +# + +set(LAYOUT "pmemkv") +if (NOT ${ENGINE} STREQUAL "cmap") + string(CONCAT LAYOUT "pmemkv_" ${ENGINE}) +endif() diff --git a/tests/wrong_engine_name_test.cc b/tests/wrong_engine_name_test.cc index 4d8e3a549..44dfc0d0f 100644 --- a/tests/wrong_engine_name_test.cc +++ b/tests/wrong_engine_name_test.cc @@ -82,6 +82,9 @@ int main() #ifndef ENGINE_DRAM_VCMAP UT_ASSERT(wrong_engine_name_test("dram_vcmap")); #endif +#ifndef ENGINE_PSKIPLIST + UT_ASSERT(wrong_engine_name_test("pskiplist")); +#endif errormsg_test(); From 8ac30b95f864dc3bee5529eb16501dafb640e5eb Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Tue, 6 Apr 2021 11:19:47 +0800 Subject: [PATCH 7/9] fix tests --- tests/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fa5944899..0e05d96e2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -245,7 +245,7 @@ if(ENGINE_PSKIPLIST) add_engine_test(ENGINE pskiplist BINARY put_get_remove - TRACERS none memcheck pmemcheck + TRACERS none #memcheck pmemcheck SCRIPT pskiplist/default.cmake) add_engine_test(ENGINE pskiplist From 622c2ea8b705a5cd80c449e85cebce686660de85 Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Tue, 6 Apr 2021 11:39:09 +0800 Subject: [PATCH 8/9] Update README --- CMakeLists.txt | 2 +- README.md | 1 + doc/ENGINES-experimental.md | 2 +- src/engines-experimental/pskiplist | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ebf348a08..328302e73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ option(ENGINE_RADIX "enable experimental radix engine" OFF) option(ENGINE_ROBINHOOD "enable experimental robinhood engine (requires CXX_STANDARD to be set to value >= 14)" OFF) option(ENGINE_DRAM_VCMAP "enable testing dram_vcmap engine" OFF) -option(ENGINE_PSKIPLIST "enable experimental pskiplist engine" ON) +option(ENGINE_PSKIPLIST "enable experimental pskiplist engine" OFF) # ----------------------------------------------------------------- # ## Set required and useful variables diff --git a/README.md b/README.md index d23e468ec..e7c6169ac 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ all language bindings and utilities. Engines are loaded by name at runtime. | [tree3](doc/ENGINES-experimental.md#tree3) | Persistent B+ tree | Yes | No | No | | [stree](doc/ENGINES-experimental.md#stree) | Sorted persistent B+ tree | Yes | No | Yes | | [robinhood](doc/ENGINES-experimental.md#robinhood) | Persistent hash map with Robin Hood hashing | Yes | Yes | No | +| [pskiplist](doc/ENGINES-experimental.md#pskiplist) | Sorted persistent skiplist (contributed by [4Paradigm](https://github.com/4paradigm/pskiplist))| Yes | Yes | Yes | | [dram_vcmap](doc/ENGINES-testing.md#dram_vcmap) | Volatile concurrent hash map placed entirely on DRAM | Yes | Yes | No | The production quality engines are described in the [libpmemkv(7)](doc/libpmemkv.7.md#engines) manual diff --git a/doc/ENGINES-experimental.md b/doc/ENGINES-experimental.md index 9fe674b4f..06549c489 100644 --- a/doc/ENGINES-experimental.md +++ b/doc/ENGINES-experimental.md @@ -181,7 +181,7 @@ No additional packages are required. # pskiplist -A persistent and concurrent engine, backed by a skiplist implemented using Persistent Compare and Swap (PCAS), contributed by [4Paradigm Inc.](http://www.4paradigm.com/). The skiplist data structure is firstly introduced in a [VLDB paper](http://vldb.org/pvldb/vol14/p799-chen.pdf)). It can be enabled in CMakeLists.txt using the `ENGINE_PSKIPLIST` option. +A persistent and concurrent engine, backed by a skiplist implemented using Persistent Compare and Swap (PCAS), contributed by [4Paradigm Inc.](http://www.4paradigm.com/). The skiplist data structure is firstly introduced in a [VLDB paper](http://vldb.org/pvldb/vol14/p799-chen.pdf) **("Optimizing In-memory Database Engine for AI-powered On-line Decision Augmentation Using Persistent Memory". Cheng Chen, Jun Yang, Mian Lu, Taize Wang, Zhao Zheng, Yuqiang Chen, Wenyuan Dai, Bingsheng He, Weng-Fai Wong, Guoan Wu, Yuping Zhao, Andy Rudoff)**. It can be enabled in CMakeLists.txt using the `ENGINE_PSKIPLIST` option. ### Configuration diff --git a/src/engines-experimental/pskiplist b/src/engines-experimental/pskiplist index 457bdf944..52471fa35 160000 --- a/src/engines-experimental/pskiplist +++ b/src/engines-experimental/pskiplist @@ -1 +1 @@ -Subproject commit 457bdf9443f881608d97b7c8189e601fc6b813bd +Subproject commit 52471fa355b77aef44c83a4e7e6b5f6c10f13253 From 09549a2050111866dabb15efba6b46a58c1f3d4e Mon Sep 17 00:00:00 2001 From: Yang Jun01 Date: Thu, 8 Apr 2021 10:35:13 +0800 Subject: [PATCH 9/9] fix code style --- src/engines-experimental/pskiplist.cc | 38 ++++++++++++++------------- src/engines-experimental/pskiplist.h | 3 ++- tests/CMakeLists.txt | 1 - 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/engines-experimental/pskiplist.cc b/src/engines-experimental/pskiplist.cc index 7fd953af5..02c613714 100644 --- a/src/engines-experimental/pskiplist.cc +++ b/src/engines-experimental/pskiplist.cc @@ -130,7 +130,7 @@ status pskiplist::count_between(string_view key1, string_view key2, std::size_t } status pskiplist::iterate(container_iterator first, container_iterator last, - get_kv_callback *callback, void *arg) + get_kv_callback *callback, void *arg) { for (auto it = first; it != last; ++it) { auto ret = callback(it->first.c_str(), it->first.size(), @@ -203,8 +203,8 @@ status pskiplist::get_below(string_view key, get_kv_callback *callback, void *ar } /* get between (key1, key2), key1 exclusive, key2 exclusive */ -status pskiplist::get_between(string_view key1, string_view key2, get_kv_callback *callback, - void *arg) +status pskiplist::get_between(string_view key1, string_view key2, + get_kv_callback *callback, void *arg) { LOG("get_between key range=[" << std::string(key1.data(), key1.size()) << "," << std::string(key2.data(), key2.size()) << ")"); @@ -256,7 +256,8 @@ status pskiplist::put(string_view key, string_view value) auto result = my_skiplist->try_emplace(key, value); if (!result.second) { // key already exists, so update - typename internal::pskiplist::skiplist_type::value_type &entry = *result.first; + typename internal::pskiplist::skiplist_type::value_type &entry = + *result.first; transaction::manual tx(pmpool); entry.second = value; transaction::commit(); @@ -276,17 +277,19 @@ status pskiplist::remove(string_view key) void pskiplist::Recover() { if (!OID_IS_NULL(*root_oid)) { - my_skiplist = (internal::pskiplist::skiplist_type *)pmemobj_direct(*root_oid); + my_skiplist = + (internal::pskiplist::skiplist_type *)pmemobj_direct(*root_oid); my_skiplist->key_comp().runtime_initialize( internal::extract_comparator(*config)); } else { pmem::obj::transaction::run(pmpool, [&] { pmem::obj::transaction::snapshot(root_oid); - *root_oid = - pmem::obj::make_persistent() - .raw(); + *root_oid = pmem::obj::make_persistent< + internal::pskiplist::skiplist_type>() + .raw(); my_skiplist = - (internal::pskiplist::skiplist_type *)pmemobj_direct(*root_oid); + (internal::pskiplist::skiplist_type *)pmemobj_direct( + *root_oid); my_skiplist->key_comp().initialize( internal::extract_comparator(*config)); }); @@ -393,7 +396,7 @@ status pskiplist::pskiplist_iterator::seek_to_last() // init_seek(); // if (container->size() == 0) - // return status::NOT_FOUND; + // return status::NOT_FOUND; // it_ = container->end(); // --it_; @@ -427,12 +430,11 @@ status pskiplist::pskiplist_iterator::prev() // init_seek(); // if (it_ == container->begin()) - // return status::NOT_FOUND; + // return status::NOT_FOUND; // --it_; // return status::OK; - return status::NOT_SUPPORTED; } @@ -443,8 +445,8 @@ result pskiplist::pskiplist_iterator::key() return {it_->first.cdata()}; } -result> pskiplist::pskiplist_iterator::read_range(size_t pos, - size_t n) +result> +pskiplist::pskiplist_iterator::read_range(size_t pos, size_t n) { assert(it_ != container->end()); @@ -454,8 +456,8 @@ result> pskiplist::pskiplist_iterator::read return {it_->second.crange(pos, n)}; } -result> pskiplist::pskiplist_iterator::write_range(size_t pos, - size_t n) +result> +pskiplist::pskiplist_iterator::write_range(size_t pos, size_t n) { assert(it_ != container->end()); @@ -486,8 +488,8 @@ void pskiplist::pskiplist_iterator::abort() log.clear(); } -static factory_registerer - register_pskiplist(std::unique_ptr(new pskiplist_factory)); +static factory_registerer register_pskiplist( + std::unique_ptr(new pskiplist_factory)); } // namespace kv } // namespace pmem diff --git a/src/engines-experimental/pskiplist.h b/src/engines-experimental/pskiplist.h index 7031608f1..70ee82d0c 100644 --- a/src/engines-experimental/pskiplist.h +++ b/src/engines-experimental/pskiplist.h @@ -41,7 +41,8 @@ using string_t = pmem::obj::string; using key_type = string_t; using value_type = string_t; -using skiplist_type = persistent_skiplist; +using skiplist_type = persistent_skiplist; } /* namespace pskiplist */ } /* namespace internal */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0e05d96e2..6779f97fa 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -247,7 +247,6 @@ if(ENGINE_PSKIPLIST) BINARY put_get_remove TRACERS none #memcheck pmemcheck SCRIPT pskiplist/default.cmake) - add_engine_test(ENGINE pskiplist BINARY put_get_remove_not_aligned TRACERS none #memcheck pmemcheck