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

🔀 Merged Steffen Kläbe's Index structure implementations

parent 462a1e9c
NVM-based Data Strucutres
=========================
This is a repository for persistent data structures based on non-volatile memory (NVM).
## TODOs: ##
- [x] PBPTree (B⁺-Tree for NVM)
- [x] PTable (BDCC + NVM)
- [x] Steffen's implementations
- [ ] Alexander's implementations
- [ ] Arun's implementations
- [ ] Link this repo to PFabric
- [ ] Data structure installation
- [ ] Data structure common benchmark
- [ ] Documentation
## License ##
The structures are licensed under GPLv3.
......
......@@ -10,28 +10,37 @@ set(CMAKE_MACOSX_RPATH 1)
# Set the mount path of your pmem device where the structures should be stored
set(PMEM_MNT_PATH "/mnt/pmem/test")
option(ENABLE_LOG "enables log output for e.g. debugging" OFF)
option(BUILD_TEST_CASES "build tests for functionality of structures" ON )
option(BUILD_GOOGLE_BENCH "build google benchmark" ON )
option(BUILD_BENCHMARKS "build benchmarks for structures" ON )
option(ENABLE_LOG "enables log output for e.g. debugging" OFF)
option(ENABLE_PROFILING "enables profiling for some of the structures" ON )
option(BUILD_TEST_CASES "build tests for functionality of structures" ON )
option(BUILD_GOOGLE_BENCH "build google benchmark" ON )
option(BUILD_BENCHMARKS "build benchmarks for structures" ON )
################################################################################
# End of customization section #
################################################################################
if(ENABLE_LOG)
add_definitions("-DENABLE_LOG")
set(LOG 1)
else()
set(LOG 0)
endif()
if(ENABLE_PROFILING)
add_definitions("-DENABLE_PROFILING")
set(PROFILING 1)
else()
set(PROFILING 0)
endif()
# Benchmark test requires benchmark library
if (BUILD_BENCHMARKS)
set(BUILD_GOOGLE_BENCH ON)
endif()
# C++ compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -g -O3 -Wsign-compare")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -g -O0 -Wsign-compare")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs -Wno-#pragma-messages")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
......@@ -98,7 +107,8 @@ set(dep_sources
configure_file(config.h.in ${CMAKE_BINARY_DIR}/generated/config.h)
include_directories(${CMAKE_BINARY_DIR}/generated
include_directories(${PROJECT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/generated
${THIRD_PARTY_DIR}
${THIRD_PARTY_DIR}/pmdk/include)
add_library(dependencies SHARED ${dep_sources}) # triggers building of dependencies
......@@ -110,6 +120,7 @@ set_target_properties(dependencies PROPERTIES LINKER_LANGUAGE CXX)
#############################
#
add_subdirectory(pbptree) # Persistent version of B⁺-Tree
add_subdirectory(fptree) # Remake of the FPTree
add_subdirectory(ptable) # BDCC-based analytical table structure
#########################
......
/*
* Copyright (C) 2017-2018 DBIS Group - TU Ilmenau, All Rights Reserved.
*
* This file is part of our NVM-based Data Structure 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 DBIS_IDXPROFILE_HPP
#define DBIS_IDXPROFILE_HPP
#include <iostream>
namespace dbis {
class IdxProfile {
int read_count;
int write_count;
int split_count;
int underflow_count;
public:
IdxProfile() {
read_count = 0;
write_count = 0;
split_count = 0;
underflow_count = 0;
}
void read() { read_count++; }
void read(int x) { read_count+=x; }
void write() { write_count++; }
void write(int x) { write_count+=x; }
void split() { split_count++; }
void underflow() { underflow_count++; }
void diff(IdxProfile prof) {
this->read_count -= prof.read_count;
this->write_count -= prof.write_count;
this->split_count -= prof.split_count;
this->underflow_count -= prof.underflow_count;
}
void print() {
std::cout << "\nIndex Profile" << std::endl;
std::cout << "\tReads:\t" << read_count << std::endl;
std::cout << "\tWrites:\t" << write_count << std::endl;
std::cout << "\tSplits:\t" << split_count << std::endl;
std::cout << "\tUnderflows:\t" << underflow_count << std::endl;
}
};//end class
} /* end namespace dbis */
#endif /* DBIS_IDXPROFILE_HPP */
//
// Created by Steffen on 27.11.17.
//
#include "pfabric.hpp"
#include <stdlib.h>
#include <time.h>
#include <math.h>
using namespace pfabric::nvm;
using nvml::obj::make_persistent;
using nvml::obj::p;
using nvml::obj::persistent_ptr;
using nvml::obj::pool;
using nvml::obj::transaction;
using MyTuple = pfabric::Tuple<int, int, string, double>;
using PTableType = PTable<MyTuple, int>;
int main(){
const int TEST_SIZE=100;
srand(time(NULL));
std::chrono::high_resolution_clock::time_point start, end;
std::vector<typename std::chrono::duration<int64_t, micro>::rep> insert_measures, lookup_measures, delete_measures;
struct root {
persistent_ptr<PTableType> pTable;
};
pool<root> pop;
const std::string path = "/mnt/mem/tests/testdb.db";
bool recover=false;
std::remove(path.c_str());
if (access(path.c_str(), F_OK) != 0) {
pop = pool<root>::create(path, LAYOUT, 16 * 1024 * 1024);
transaction::exec_tx(pop, [&] {
using namespace pfabric;
auto tInfo = TableInfo("MyTable", {
ColumnInfo("a", ColumnInfo::Int_Type),
ColumnInfo("b", ColumnInfo::Int_Type),
ColumnInfo("c", ColumnInfo::String_Type),
ColumnInfo("d", ColumnInfo::Double_Type)
});
pop.get_root()->pTable = make_persistent<PTableType>(tInfo, BDCCInfo::ColumnBitsMap({{0, 4},
{3, 6}}));
});
} else {
std::cerr << "WARNING: Table already exists" << std::endl;
pop = pool<root>::open(path, LAYOUT);
recover=true;
}
auto pTable = pop.get_root()->pTable;
if(recover){pTable->recoverIndex();};
//pTable->print(false);
std::cout << "\nTESTSIZE=" << TEST_SIZE << std::endl;
std::cout << "\nINDEXKEYS=" << INDEXKEYS << std::endl;
//Generate array of keys to stay unique while choose random keys to insert
std::array<unsigned int, TEST_SIZE> keys;
for (auto i = 0u; i < TEST_SIZE; i++) { keys[i] = i + 1; }
//Randomly choose a key out of the array, generate the tuple and insert it into the table
auto curr_test_size = TEST_SIZE;
for (unsigned int i = 0; i < TEST_SIZE; i++) {
auto choosen_key = rand() % curr_test_size;
auto key = keys[choosen_key];
auto tup = MyTuple(key,
key * 100,
fmt::format("String #{0}", key),
key * 12.345);
start = std::chrono::high_resolution_clock::now();
pTable->insert(key, tup);
end = std::chrono::high_resolution_clock::now();
if(i==TEST_SIZE/4){std::cout<<"Fortschritt: 25%"<<std::endl;}
if(i==TEST_SIZE/2){std::cout<<"Fortschritt: 50%"<<std::endl;}
if(i==3*TEST_SIZE/4){std::cout<<"Fortschritt: 75%"<<std::endl;}
auto diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
insert_measures.push_back(diff);
curr_test_size--;
keys[choosen_key] = keys[curr_test_size];
}
auto avg = std::accumulate(insert_measures.begin(), insert_measures.end(), 0) / insert_measures.size();
auto minmax = std::minmax_element(std::begin(insert_measures), std::end(insert_measures));
std::cout << "\nInsert Statistics in µs: "
<< "\n\tAverage: \t" << avg
<< "\n\tMin: \t" << *minmax.first
<< "\n\tMax: \t" << *minmax.second << '\n';
#ifdef IDXPROFILE
pTable->printIdxProfile();
#endif
std::cout << "\n####################################\n";
//Lookup measures
for (unsigned int i = 0; i < TEST_SIZE; i++) {
auto key = i + 1;
start = std::chrono::high_resolution_clock::now();
try {
auto tuple = pTable->getByKey(key);
} catch (pfabric::TableException e) {
std::cout << "Didn't find " << key << std::endl;
}
end = std::chrono::high_resolution_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
lookup_measures.push_back(diff);
}
avg = std::accumulate(lookup_measures.begin(), lookup_measures.end(), 0) / lookup_measures.size();
minmax = std::minmax_element(std::begin(lookup_measures), std::end(lookup_measures));
std::cout << "\nLookup Statistics in µs: "
<< "\n\tAverage: \t" << avg
<< "\n\tMin: \t" << *minmax.first
<< "\n\tMax: \t" << *minmax.second << '\n';
#ifdef IDXPROFILE
pTable->printIdxProfile();
#endif
std::cout << "\n####################################\n";
//Delete measures
for (auto i = 0u; i < TEST_SIZE; i++) { keys[i] = i + 1; }
curr_test_size = TEST_SIZE;
for (unsigned int i = 0; i < TEST_SIZE -1; i++) {
auto choosen_key = rand() % curr_test_size;
auto key = keys[choosen_key];
start = std::chrono::high_resolution_clock::now();
pTable->deleteByKey(key);
end = std::chrono::high_resolution_clock::now();
auto diff = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
delete_measures.push_back(diff);
if(i==TEST_SIZE/4){std::cout<<"Fortschritt: 25%"<<std::endl;}
if(i==TEST_SIZE/2){std::cout<<"Fortschritt: 50%"<<std::endl;}
if(i==3*TEST_SIZE/4){std::cout<<"Fortschritt: 75%"<<std::endl;}
curr_test_size--;
keys[choosen_key] = keys[curr_test_size];
}
avg = std::accumulate(delete_measures.begin(), delete_measures.end(), 0) / delete_measures.size();
minmax = std::minmax_element(std::begin(delete_measures), std::end(delete_measures));
std::cout << "\nDelete Statistics in µs: "
<< "\n\tAverage: \t" << avg
<< "\n\tMin: \t" << *minmax.first
<< "\n\tMax: \t" << *minmax.second << '\n';
#ifdef IDXPROFILE
pTable->printIdxProfile();
#endif
pop.close();
}
#ifndef NVM_DS_CONFIG_H
#define NVM_DS_CONFIG_H
#ifndef DBIS_CONFIG_H
#define DBIS_CONFIG_H
#ifdef ENABLE_LOG
#include <iostream>
#define LOG(msg) std::cout << "[DBIS:NVM_DS] " << msg << '\n';
#else
#define LOG(msg)
#endif
#define LOG(msg) if(@LOG@) std::cout << "[DBIS:NVM_DS] " << msg << '\n';
#ifdef ENABLE_PROFILING
#include <memory>
#include <IdxProfile.hpp>
#define PROFILE_DECL std::unique_ptr<IdxProfile> profile;
#define PROFILE_INIT profile = std::make_unique<IdxProfile>();
#define PROFILE_READ(n) profile->read(n);
#define PROFILE_WRITE(n) profile->write(n);
#define PROFILE_SPLIT profile->split();
#define PROFILE_UNDERFLOW profile->underflow();
#define PROFILE_PRINT void printIdxProfile() { profile->print(); }
#else
#define PROFILE_DECL
#define PROFILE_INIT
#define PROFILE_READ(n)
#define PROFILE_WRITE(n)
#define PROFILE_SPLIT
#define PROFILE_UNDERFLOW
#define PROFILE_PRINT
#endif
namespace dbis {
const std::string gPmemPath("@PMEM_MNT_PATH@/");
}
#endif /* NVM_DS_CONFIG_H */
#endif /* DBIS_CONFIG_H */
project (fptree)
include_directories(${PROJECT_SOURCE_DIR}
${THIRD_PARTY_DIR})
get_property(I_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
set(TEST_INCLUDE_DIRS ${TEST_INCLUDE_DIRS}
${I_DIRS}
CACHE INTERNAL "TESTING: Include Directories" FORCE
)
set(FPTREE_INCLUDE_DIRS ${PROJECT_SOURCE_DIR})
This diff is collapsed.
/*
* Copyright (C) 2017-2018 DBIS Group - TU Ilmenau, All Rights Reserved.
*
* This file is part of our NVM-based Data Structure 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 DBIS_ELEMENTOFRANKK_HPP
#define DBIS_ELEMENTOFRANKK_HPP
namespace dbis::pbptree {
class ElementOfRank {
private:
template <typename KeyType>
static void swap(KeyType *data, int p, int q) {
if (p == q) return;
KeyType merke = data[p];
data[p] = data[q];
data[q] = merke;
}
template <typename KeyType>
static KeyType elementOfRankBySorting(int m, KeyType *data, int length, int start) {
int k = m - 1;
bool swapped = true;
while (swapped == true) {
swapped = false;
for (int i = start; i < start + length-1; i++) {
if (data[i] > data[i + 1]) {
swap(data, i, i + 1);
swapped = true;
}
}
}
return data[k];
}
template <typename KeyType>
static KeyType findPivot(KeyType *data, int length, int start) {
int parts = length / 5;
KeyType medians[parts];
if (parts <= 1) { return elementOfRankBySorting(start + (length + 1) / 2, data, length, start); }
for (int i = 0; i < parts; i++) {
medians[i] = elementOfRankBySorting(3, data, 5, start + i * 5);
}
return findPivot(medians, parts, 0);
}
public:
template <typename KeyType>
static KeyType elementOfRank(int m, KeyType *data, int length, int start) {
int k = m - 1;
if (length <= 15) {
return elementOfRankBySorting(m, data, length, start);
}
int p = start, q = start;
KeyType pivot = findPivot(data, length, start);
for (int i = start; i < start + length; i++) {
if (data[i] < pivot) {
swap(data, i, q);
swap(data, p, q);
q++;
p++;
}
if (data[i] == pivot) {
swap(data, i, q);
q++;
}
}
if (k < p) {return elementOfRank(m, data, p - start, start); }
if (k >= q) {return elementOfRank(m, data, length + start - q - 1, q); }
return pivot;
}
}; /* end class */
} /* end namespace dbis::pbptree */
#endif /* DBIS_ELEMENTOFRANKK_HPP */
This diff is collapsed.
......@@ -16,11 +16,6 @@ endif()
# End of customization section #
################################################################################
if(ENABLE_LOG)
set(LOG 1)
else()
set(LOG 0)
endif()
###########################
# Building PTable library #
......
......@@ -8,6 +8,9 @@ if (BUILD_TEST_CASES)
add_library(MainTest OBJECT MainTest.cpp)
# PBPTree
do_test(PBPTreeTest)
do_test(UnsortedPBPTreeTest)
# FPTree
do_test(FPTreeTest)
# PTable
do_test(VTableInfoTest ptable)
do_test(BDCCInfoTest ptable)
......
This diff is collapsed.
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment