Commit c44518af authored by Philipp Götze's avatar Philipp Götze
Browse files

🔨 Started refactorization of trie and skip list code

parent 09a8e6d4
Pipeline #675 failed with stages
in 2 minutes and 14 seconds
......@@ -105,8 +105,8 @@ add_subdirectory(src/pbptrees) # Persistent versions of B⁺-Tree, contains also
# - Remake of the FPTree
# - Remake of the wB+Tree
add_subdirectory(src/ptable) # BDCC-based analytical table structure
add_subdirectory(src/pskiplists)
add_subdirectory(src/ptries)
#########################
# Unit test using Catch #
#########################
......
/*
* Copyright (C) 2017-2020 DBIS Group - TU Ilmenau, All Rights Reserved.
*
* This file is part of our NVM-based Data Structures repository.
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SIMPLE_PSKIPLIST_HPP
#define SIMPLE_PSKIPLIST_HPP
......@@ -6,7 +23,7 @@
#include <iostream>
#include <libpmemobj++/utils.hpp>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/experimental/array.hpp>
#include <libpmemobj++/container/array.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/transaction.hpp>
......@@ -18,191 +35,193 @@ using pmem::obj::persistent_ptr;
using pmem::obj::transaction;
class Random {
uint32_t seed;
public:
explicit Random(uint32_t s) : seed(s & 0x7fffffffu) {
if (seed == 0 || seed == 2147483647L) {
seed = 1;
}
}
uint32_t Next() {
static const uint32_t M = 2147483647L; // 2^31-1
static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
uint64_t product = seed * A;
seed = static_cast<uint32_t>((product >> 31) + (product & M));
if(seed>M) {
seed -= M;
}
return seed;
}
uint32_t Uniform(int n) { return (Next() % n); }
bool OneIn(int n) { return (Next() % n) == 0; }
uint32_t Skewed(int max_log) {
return Uniform(1 << Uniform(max_log + 1));
}
uint32_t seed;
public:
explicit Random(uint32_t s) : seed(s & 0x7fffffffu) {
if (seed == 0 || seed == 2147483647L) {
seed = 1;
}
}
uint32_t Next() {
static const uint32_t M = 2147483647L; // 2^31-1
static const uint64_t A = 16807; // bits 14, 8, 7, 5, 2, 1, 0
uint64_t product = seed * A;
seed = static_cast<uint32_t>((product >> 31) + (product & M));
if(seed>M) {
seed -= M;
}
return seed;
}
uint32_t Uniform(int n) { return (Next() % n); }
bool OneIn(int n) { return (Next() % n) == 0; }
uint32_t Skewed(int max_log) {
return Uniform(1 << Uniform(max_log + 1));
}
};
template<typename KeyType, typename ValueType, int MAX_LEVEL>
class simplePSkiplist {
struct SkipNode {
p<KeyType> key;
p<ValueType> value;
persistent_ptr<persistent_ptr<SkipNode>> forward;
p<int> nodeLevel;
struct SkipNode {
p<KeyType> key;
p<ValueType> value;
persistent_ptr<persistent_ptr<SkipNode>> forward;
p<int> nodeLevel;
SkipNode() {}
SkipNode() {}
SkipNode(const KeyType key, const ValueType value) {
this->key = key;
this->value = value;
}
};
persistent_ptr<SkipNode> head;
persistent_ptr<SkipNode> tail;
p<int> level;
p<size_t> nodeCount;
Random rnd;
void createNode(int level, persistent_ptr<SkipNode> &node) {
auto pop = pmem::obj::pool_by_vptr(this);
transaction::run(pop, [&] {node = make_persistent<SkipNode>();
node->forward = make_persistent<persistent_ptr<SkipNode>>();
for(int i=0; i<level+1;i++) {
node->forward[i] = make_persistent<SkipNode>();
}
//node->forward = new SkipNode*[level+1];
node->nodeLevel = level;
});
SkipNode(const KeyType key, const ValueType value) {
this->key = key;
this->value = value;
}
};
void createNode(int level, persistent_ptr<SkipNode> &node, KeyType key, ValueType value) {
auto pop = pmem::obj::pool_by_vptr(this);
transaction::run(pop, [&] {
node = make_persistent<SkipNode>(key, value);
if(level > 0) {
//node->forward = new SkipNode*[level +1];
node->forward = make_persistent<persistent_ptr<SkipNode>>();
for(int i=0; i<level+1; i++) {
node->forward[i] = make_persistent<SkipNode>();
}
}
node->nodeLevel = level;
});
}
persistent_ptr<SkipNode> head;
persistent_ptr<SkipNode> tail;
p<int> level;
void createList(KeyType tailKey) {
createNode(0, tail);
tail->key = tailKey;
this->level = 0;
createNode(MAX_LEVEL, head);
for(int i=0; i < MAX_LEVEL; ++i) {
head->forward[i] = tail;
}
nodeCount = 0;
}
p<size_t> nodeCount;
Random rnd;
int getRandomLevel() {
int level = static_cast<int>(rnd.Uniform(MAX_LEVEL));
if (level == 0) {
level = 1;
void createNode(int level, persistent_ptr<SkipNode> &node) {
auto pop = pmem::obj::pool_by_vptr(this);
transaction::run(pop, [&] {node = make_persistent<SkipNode>();
node->forward = make_persistent<persistent_ptr<SkipNode>>();
for(int i=0; i<level+1;i++) {
node->forward[i] = make_persistent<SkipNode>();
}
//node->forward = new SkipNode*[level+1];
node->nodeLevel = level;
});
}
void createNode(int level, persistent_ptr<SkipNode> &node, KeyType key, ValueType value) {
auto pop = pmem::obj::pool_by_vptr(this);
transaction::run(pop, [&] {
node = make_persistent<SkipNode>(key, value);
if(level > 0) {
//node->forward = new SkipNode*[level +1];
node->forward = make_persistent<persistent_ptr<SkipNode>>();
for(int i=0; i<level+1; i++) {
node->forward[i] = make_persistent<SkipNode>();
}
}
return level;
node->nodeLevel = level;
});
}
void createList(KeyType tailKey) {
createNode(0, tail);
tail->key = tailKey;
this->level = 0;
createNode(MAX_LEVEL, head);
for(int i=0; i < MAX_LEVEL; ++i) {
head->forward[i] = tail;
}
nodeCount = 0;
}
public:
simplePSkiplist(KeyType tailKey) : rnd(0x12345678) {
createList(tailKey);
int getRandomLevel() {
int level = static_cast<int>(rnd.Uniform(MAX_LEVEL));
if (level == 0) {
level = 1;
}
return level;
}
public:
bool insert(KeyType key, ValueType value) {
auto pop = pmem::obj::pool_by_vptr(this);
bool ret = true;
transaction::run(pop, [&] {
persistent_ptr<SkipNode> update[MAX_LEVEL];
simplePSkiplist() : head(nullptr), tail(nullptr), level(0), nodeCount(0), rnd(0x12345678) {}
auto node = head;
simplePSkiplist(KeyType tailKey) : rnd(0x12345678) {
createList(tailKey);
}
for(int i = level; i>= 0; --i) {
while(node->forward[i]->key < key) {
node = node->forward[i];
}
update[i] = node;
}
node = node->forward[0];
bool insert(KeyType key, ValueType value) {
auto pop = pmem::obj::pool_by_vptr(this);
bool ret = true;
transaction::run(pop, [&] {
persistent_ptr<SkipNode> update[MAX_LEVEL];
if(node->key == key) {
ret = false;
}
auto node = head;
auto nodeLevel = getRandomLevel();
for(int i = level; i>= 0; --i) {
while(node->forward[i]->key < key) {
node = node->forward[i];
}
update[i] = node;
}
if(nodeLevel > level) {
nodeLevel = ++level;
update[nodeLevel] = head;
}
node = node->forward[0];
persistent_ptr<SkipNode> newNode;
createNode(nodeLevel, newNode, key, value);
if(node->key == key) {
ret = false;
}
for(int i = nodeLevel; i >= 0; --i) {
node = update[i];
newNode->forward[i] = node->forward[i];
node->forward[i] = newNode;
}
++nodeCount;
});
return ret;
}
auto nodeLevel = getRandomLevel();
persistent_ptr<SkipNode> search(const KeyType key) {
auto node = head;
for(int i = level; i >= 0; --i) {
while(node->forward[i]->key < key) {
node = *(node->forward + i);
}
}
node = node->forward[0];
if(node->key == key) {
return node;
} else {
return nullptr;
if(nodeLevel > level) {
nodeLevel = ++level;
update[nodeLevel] = head;
}
}
void printNodes() {
auto tmp = head;
while (tmp->forward[0] != tail) {
tmp = tmp->forward[0];
dumpNodeDetail(tmp, tmp->nodeLevel);
std::cout << "----------------------------" << std::endl;
persistent_ptr<SkipNode> newNode;
createNode(nodeLevel, newNode, key, value);
for(int i = nodeLevel; i >= 0; --i) {
node = update[i];
newNode->forward[i] = node->forward[i];
node->forward[i] = newNode;
}
std::cout << std::endl;
++nodeCount;
});
return ret;
}
persistent_ptr<SkipNode> search(const KeyType key) {
auto node = head;
for(int i = level; i >= 0; --i) {
while(node->forward[i]->key < key) {
node = *(node->forward + i);
}
}
node = node->forward[0];
if(node->key == key) {
return node;
} else {
return nullptr;
}
}
void printNodes() {
auto tmp = head;
while (tmp->forward[0] != tail) {
tmp = tmp->forward[0];
dumpNodeDetail(tmp, tmp->nodeLevel);
std::cout << "----------------------------" << std::endl;
}
std::cout << std::endl;
}
void dumpNodeDetail(persistent_ptr<SkipNode> node, int nodeLevel) {
if (node == nullptr) {
return;
}
std::cout << "node->key:" << node->key << ",node->value:" << node->value << std::endl;
for (int i = 0; i <= nodeLevel; ++i) {
std::cout << "forward[" << i << "]:" << "key:" << node->forward[i]->key << ",value:" << node->forward[i]->value
<< std::endl;
}
void dumpNodeDetail(persistent_ptr<SkipNode> node, int nodeLevel) {
if (node == nullptr) {
return;
}
std::cout << "node->key:" << node->key << ",node->value:" << node->value << std::endl;
for (int i = 0; i <= nodeLevel; ++i) {
std::cout << "forward[" << i << "]:" << "key:" << node->forward[i]->key << ",value:" << node->forward[i]->value
<< std::endl;
}
}
};
#endif //SKIPLIST_SKIPLIST_HPP
#endif //SIMPLE_PSKIPLIST_HPP
/*
* Copyright (C) 2017-2020 DBIS Group - TU Ilmenau, All Rights Reserved.
*
* This file is part of our NVM-based Data Structures repository.
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WOP_SKIPLIST_HPP
#define WOP_SKIPLIST_HPP
......@@ -13,350 +30,370 @@
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/transaction.hpp>
namespace dbis::pskiplists {
using pmem::obj::delete_persistent;
using pmem::obj::make_persistent;
using pmem::obj::p;
using pmem::obj::persistent_ptr;
using pmem::obj::transaction;
template <typename Object>
using pptr = persistent_ptr<Object>;
class Random {
public:
public:
explicit Random(uint32_t s) : seed(s & 0x7fffffffu) {
if (seed == 0 || seed == 2147483647L) {
seed = 1;
}
if (seed == 0 || seed == 2147483647L) {
seed = 1;
}
}
uint32_t Next() {
static const uint32_t M = 2147483647L;
static const uint64_t A = 16807;
uint64_t product = seed * A;
seed = static_cast<uint32_t>((product >> 31) + (product & M));
if (seed > M) {
seed -= M;
}
return seed;
static const uint32_t M = 2147483647L;
static const uint64_t A = 16807;
uint64_t product = seed * A;
seed = static_cast<uint32_t>((product >> 31) + (product & M));
if (seed > M) {
seed -= M;
}
return seed;
}
uint32_t Uniform(int n) { return (Next() % n); }
bool OneIn(int n) { return (Next() % n) == 0; }
uint32_t Skewed(int max_log) {
return Uniform(1 << Uniform(max_log + 1));
return Uniform(1 << Uniform(max_log + 1));
}
private:
private:
uint32_t seed;
};
//N = Bucket size
//M = Max Level
/**
* A persistent memory implementation of a write-optimized Skip List.
*
* @tparam KeyType the data type of the key
* @tparam ValueType the data type of the values associated with the key
* @tparam N the bucket size
* @tparam M the maximum level
*/
template<typename KeyType, typename ValueType, int N, int M>
class woPSkiplist {
struct SkipNode {
p<std::array<KeyType, N>> key;
p<std::array<ValueType, N>> value;
p<std::bitset<N>> bitset;
p<KeyType> minKey;
p<KeyType> maxKey;
p<int> nodeLevel;
persistent_ptr<std::array<persistent_ptr<SkipNode>, M>> forward;
SkipNode() {
this->maxKey = -100000000;
this->minKey = 100000000;
nodeLevel = 0;
}
SkipNode(const KeyType key, const ValueType value) {
this->key = key;
this->value = value;
}
KeyType getAvg() const {
KeyType sum = 0;
auto btCount = 0;
for(int i=0; i < N; i++) {
if(bitset.get_ro().test(i)) {
auto k = key.get_ro()[i];
if(k != minKey && k != maxKey) {
sum += k;
btCount++;
}
}
}
return sum / btCount;
}
bool isFull() {
return bitset.get_ro().all();
static constexpr auto MAX_KEY = std::numeric_limits<KeyType>::max();
static constexpr auto MIN_KEY = std::numeric_limits<KeyType>::min();
/**
* A structure for representing a node of a skip list.
*/
struct alignas(64) SkipNode {
p<std::bitset<N>> bitset; ///< a bitmap indicating empty/used slots
p<KeyType> minKey; ///< SMA min
p<KeyType> maxKey; ///< SMA max
p<size_t> nodeLevel; ///< the level of this node
/// TODO: padding to 64 bytes?
p<std::array<KeyType, N>> keys; ///< the actual keys
p<std::array<ValueType, N>> values; ///< the actual values
pptr<std::array<pptr<SkipNode>, M>> forward; ///< the forward pointers to the following nodes
/**
* Constructor for creating a new empty node.
*/
SkipNode() : maxKey(MIN_KEY), minKey(MAX_KEY), nodeLevel(0) {}
/**
* Constructor for creating a new node with an initial key and value.
*/
SkipNode(const KeyType _key, const ValueType _value) : keys(_key), values(_value) {}
/**
* Calculate the average key value of this node.
*
* @return the average
*/
KeyType getAvg() const {
KeyType sum = 0;
auto btCount = 0u;
const auto &bs = bitset.get_ro();
const auto &ks = keys.get_ro();
for (auto i = 0u; i < N; ++i) {
if (bs.test(i)) {
const auto &k = ks[i];
if (k != minKey && k != maxKey) {
sum += k;
btCount++;
}
}
}
return sum / btCount;
}
bool keyBetween(KeyType newKey) {
if(minKey == - 1 ||
maxKey == -1)
return true;
bool isFull() {
return bitset.get_ro().all();
}
return newKey >= minKey && newKey <= maxKey;
}
bool keyBetween(KeyType newKey) {
if(minKey == - 1 ||
maxKey == -1)
return true;
ValueType* searchKey(const KeyType searchKey) {
for(int i=0; i<N; i++) {
if(bitset.get_ro().test(i)) {
if(key.get_ro()[i] == searchKey) {
return &value.get_rw().at(i);
}
}
}
return nullptr;
}