Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
code
PMem-based Data Structures
Commits
78bc26c1
Commit
78bc26c1
authored
Apr 23, 2019
by
Philipp Götze
Browse files
Changes during DaMoN experiments
parent
fc4b24c5
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
insertLeaf_benchmark.sh
0 → 100755
View file @
78bc26c1
#!/bin/bash
### LOCATIONS ###
REPO_ROOT
=
$PWD
BUILD_DIR
=
build
DATA
=
/mnt/mem/test/tree_bench.data
OUTPUT_FILE
=
$REPO_ROOT
/results/insert5.csv
### CUSTOMIZABLE PARAMETERS ###
bsize
=
512
depth
=
0
keypos
=(
'first'
'middle'
'last'
)
LEAF_SIZES
=(
256 512 1024 2048 4096
)
TREE
=
"UnsortedPBP"
#FP/PBP/wBP
TREE_BASE
=
"PBP"
# for namespace and numKeys determination
SUFFIX
=
""
# in case of binary vs. linear
### Do not change anything following here!!! ###
### needs manual adaption ###
fillratio
=
1.0
lat
=
75
### adapting Tree usage ###
sed
-i
''
-e
's/\(.*BRANCH_SIZE = \)\([0-9]\+\)\(.*\)/\1'
"
$bsize
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
sed
-i
''
-e
's/\(.*DEPTH = \)\([0-9]\+\)\(.*\)/\1'
"
$depth
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
sed
-i
''
-e
's/\(.*\"\).*\(Tree.hpp\"\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#include
sed
-i
''
-e
's/\(.*dbis::\).*\(tree;\)/\1'
"
${
TREE_BASE
,,
}
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#namespace
sed
-i
''
-e
's/\(.*LEAFKEYS = getLeafKeys\).*\(Tree.*\)/\1'
"
$TREE_BASE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#keys
sed
-i
''
-e
's/\(.*BRANCHKEYS = getBranchKeys\).*\(Tree.*\)/\1'
"
$TREE_BASE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#keys
sed
-i
''
-e
's/\(.*TreeType = \).*\(Tree.*\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#type
echo
-n
"Running benchmarks for
${
Tree
}
Tree..."
for
pos
in
"
${
keypos
[@]
}
"
do
echo
-en
"
\n
Key Position:
$pos
- "
KEYPOS
=
'2'
if
[
$pos
==
"first"
]
;
then
KEYPOS
=
'ELEMENTS'
elif
[
$pos
==
"last"
]
;
then
KEYPOS
=
'1'
fi
sed
-i
''
-e
's/\(.*KEYPOS = ELEMENTS\/\)\(.\+\)\(;.*\)/\1'
"
$KEYPOS
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
for
lsize
in
"
${
LEAF_SIZES
[@]
}
"
do
echo
-n
"
$lsize
"
sed
-i
''
-e
's/\(.*LEAF_SIZE = \)\([0-9]\+\)\(.*\)/\1'
"
$lsize
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
pushd
$BUILD_DIR
>
/dev/null
make tree_insert
>
/dev/null
for
r
in
{
1..5
}
do
rm
-rf
$DATA
OUTPUT
=
"
$(
sh
-c
'bench/tree_insert --benchmark_format=csv --benchmark_min_time=0.005'
2> /dev/null |
tail
-3
)
"
elements
=
"
$(
echo
"
$OUTPUT
"
|
head
-1
|
cut
-d
':'
-f2
)
"
time
=
"
$(
echo
"
$OUTPUT
"
|
tail
-1
|
cut
-d
','
-f4
)
"
echo
"
${
TREE
}
Tree
$SUFFIX
,
$elements
,
$lsize
,
$bsize
,
$depth
,
$fillratio
,
$pos
,
$time
,
$lat
"
>>
$OUTPUT_FILE
done
popd
>
/dev/null
done
done
echo
-e
"
\n
Finished. Results in
$OUTPUT_FILE
"
lookup_benchmark.sh
0 → 100755
View file @
78bc26c1
#!/bin/bash
### LOCATIONS ###
REPO_ROOT
=
$PWD
BUILD_DIR
=
build
DATA
=
/mnt/mem/test/tree_bench.data
OUTPUT_FILE
=
$REPO_ROOT
/results/searchNoOpt.csv
### CUSTOMIZABLE PARAMETERS ###
bsize
=
512
depth
=
1
LEAF_SIZES
=(
256 512 1024 2048 4096
)
TREE
=
"FP"
#FP/PBP/wBP
SUFFIX
=
""
# in case of binary vs. linear
### Do not change anything following here!!! ###
### needs manual adaption ###
fillratio
=
1.0
keypos
=
"last"
#first/middle/last
### adapting Tree usage ###
sed
-i
''
-e
's/\(.*BRANCH_SIZE = \)\([0-9]\+\)\(.*\)/\1'
"
$bsize
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
sed
-i
''
-e
's/\(.*DEPTH = \)\([0-9]\+\)\(.*\)/\1'
"
$depth
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
sed
-i
''
-e
's/\(.*\"\).*\(Tree.hpp\"\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#include
sed
-i
''
-e
's/\(.*dbis::\).*\(tree;\)/\1'
"
${
TREE
,,
}
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#namespace
sed
-i
''
-e
's/\(.*LEAFKEYS = getLeafKeys\).*\(Tree.*\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#keys
sed
-i
''
-e
's/\(.*BRANCHKEYS = getBranchKeys\).*\(Tree.*\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#keys
sed
-i
''
-e
's/\(.*TreeType = \).*\(Tree.*\)/\1'
"
$TREE
"
'\2/'
$REPO_ROOT
/src/bench/trees/common.hpp
#type
echo
-n
"Running benchmarks for
${
Tree
}
Tree..."
for
lsize
in
"
${
LEAF_SIZES
[@]
}
"
do
echo
-en
"
\n
Leaf size:
$lsize
"
sed
-i
''
-e
's/\(.*LEAF_SIZE = \)\([0-9]\+\)\(.*\)/\1'
"
$lsize
"
'\3/'
$REPO_ROOT
/src/bench/trees/common.hpp
rm
-rf
$DATA
pushd
$BUILD_DIR
>
/dev/null
make tree_get
>
/dev/null
for
r
in
{
1..3
}
do
OUTPUT
=
"
$(
sh
-c
'bench/tree_get --benchmark_format=csv'
2> /dev/null |
tail
-3
)
"
elements
=
"
$(
echo
"
$OUTPUT
"
|
head
-1
|
cut
-d
':'
-f2
)
"
time
=
"
$(
echo
"
$OUTPUT
"
|
tail
-1
|
cut
-d
','
-f4
)
"
echo
"
${
TREE
}
Tree
$SUFFIX
,
$elements
,
$lsize
,
$bsize
,
$depth
,
$fillratio
,
$keypos
,
$time
"
>>
$OUTPUT_FILE
done
popd
>
/dev/null
done
echo
-e
"
\n
Finished. Results in
$OUTPUT_FILE
"
src/CMakeLists.txt
View file @
78bc26c1
...
...
@@ -17,7 +17,7 @@ option(ENABLE_LOG "enables log output for e.g. debugging" OFF)
option
(
ENABLE_PROFILING
"enables profiling for some of the structures"
OFF
)
option
(
BUILD_TEST_CASES
"build tests for functionality of structures"
ON
)
option
(
BUILD_GOOGLE_BENCH
"build google benchmark"
OFF
)
option
(
BUILD_BENCHMARKS
"build benchmarks for structures"
O
FF
)
option
(
BUILD_BENCHMARKS
"build benchmarks for structures"
O
N
)
################################################################################
# End of customization section #
...
...
@@ -99,7 +99,7 @@ include_directories(${PROJECT_SOURCE_DIR}
${
THIRD_PARTY_DIR
}
/pmdk/include
)
add_library
(
nvmDS_deps STATIC
${
THIRD_PARTY_DIR
}
/pmdk
)
add_dependencies
(
nvmDS_deps fmt_target catch_target pmdk_target
)
#< executes custom commands
target_link_libraries
(
nvmDS_deps
${
PMDK_LIBRARIES
}
ndctl daxctl
)
target_link_libraries
(
nvmDS_deps
${
PMDK_LIBRARIES
}
stdc++fs
ndctl daxctl
)
set_target_properties
(
nvmDS_deps PROPERTIES LINKER_LANGUAGE CXX
)
#################
...
...
src/bench/CMakeLists.txt
View file @
78bc26c1
...
...
@@ -3,6 +3,7 @@ include(../../cmake/Testing.cmake.in)
if
(
BUILD_BENCHMARKS
)
do_bench
(
trees/tree_get
)
do_bench
(
trees/tree_traverse
)
do_bench
(
trees/tree_insert
)
# PTABLE
do_bench
(
ptable/insert ptable
)
do_bench
(
ptable/scan ptable
)
...
...
src/bench/trees/common.hpp
View file @
78bc26c1
...
...
@@ -27,9 +27,9 @@
#define UNIT_TESTS
#include
"benchmark/benchmark.h"
#include
"
F
PTree.hpp"
#include
"
UnsortedPB
PTree.hpp"
using
namespace
dbis
::
f
ptree
;
using
namespace
dbis
::
pb
ptree
;
using
pmem
::
obj
::
pool
;
...
...
@@ -37,11 +37,11 @@ using pmem::obj::pool;
/* Customization section */
using
MyTuple
=
std
::
tuple
<
int
,
int
,
double
>
;
using
MyKey
=
unsigned
long
long
;
constexpr
auto
TARGET_BRANCH_SIZE
=
2048
;
constexpr
auto
TARGET_LEAF_SIZE
=
512
;
//< 512B best performance
constexpr
auto
TARGET_DEPTH
=
4
;
constexpr
auto
TARGET_BRANCH_SIZE
=
512
;
constexpr
auto
TARGET_LEAF_SIZE
=
4096
;
//< 512B best performance
constexpr
auto
TARGET_DEPTH
=
0
;
const
std
::
string
path
=
dbis
::
gPmemPath
+
"tree_bench.data"
;
constexpr
auto
POOL_SIZE
=
1024
*
1024
*
1024
;
//<
128M
B
constexpr
auto
POOL_SIZE
=
1024
*
1024
*
1024
*
1ull
;
//<
4G
B
constexpr
auto
LAYOUT
=
"Tree"
;
/* wBPTree pre-calculations */
...
...
@@ -104,11 +104,12 @@ constexpr uint64_t ipow(uint64_t base, int exp, uint64_t result = 1) {
}
/* Tree relevant calculated parameters*/
constexpr
auto
LEAFKEYS
=
getLeafKeys
F
PTree
<
5
>
();
//< 5 iterations should be enough
constexpr
auto
BRANCHKEYS
=
getBranchKeys
w
BPTree
<
5
>
();
constexpr
auto
LEAFKEYS
=
getLeafKeys
PB
PTree
<
5
>
();
//< 5 iterations should be enough
constexpr
auto
BRANCHKEYS
=
getBranchKeys
P
BPTree
<
5
>
();
constexpr
auto
ELEMENTS
=
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
TARGET_DEPTH
);
constexpr
auto
KEYPOS
=
ELEMENTS
/
1
;
using
TreeType
=
F
PTree
<
MyKey
,
MyTuple
,
BRANCHKEYS
,
LEAFKEYS
>
;
using
TreeType
=
UnsortedPB
PTree
<
MyKey
,
MyTuple
,
BRANCHKEYS
,
LEAFKEYS
>
;
/*=== Insert Function ===*/
void
insert
(
persistent_ptr
<
TreeType
>
&
tree
)
{
...
...
@@ -145,12 +146,17 @@ void insert(persistent_ptr<TreeType> &tree) {
};
std
::
function
<
void
(
int
)
>
insertLoopOtherHalf
=
[
&
](
int
depth
)
{
//tree->printBranchNode(0, tree->rootNode.branch);
if
(
depth
==
0
)
{
auto
otherHalf
=
(
LEAFKEYS
+
1
)
/
2
;
for
(
auto
i
=
0
;
i
<
ipow
(
BRANCHKEYS
+
1
,
TARGET_DEPTH
-
depth
);
++
i
)
insertLoopLeaf
(
otherHalf
+
i
*
LEAFKEYS
);
}
else
{
auto
otherHalf
=
(
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
depth
)
+
1
)
/
2
+
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
depth
-
1
);
auto
nodeRange
=
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
depth
);
auto
lowerRange
=
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
depth
-
1
);
auto
middle
=
(
nodeRange
+
1
)
/
2
;
auto
seen
=
middle
+
lowerRange
;
auto
otherHalf
=
(
BRANCHKEYS
%
2
==
0
)
?
seen
-
(
lowerRange
+
1
)
/
2
:
seen
;
for
(
auto
i
=
0
;
i
<
ipow
(
BRANCHKEYS
+
1
,
TARGET_DEPTH
-
depth
);
++
i
)
insertLoopBranch
(
otherHalf
+
i
*
LEAFKEYS
*
ipow
(
BRANCHKEYS
+
1
,
depth
),
depth
,
true
);
insertLoopOtherHalf
(
depth
-
1
);
...
...
@@ -159,7 +165,6 @@ void insert(persistent_ptr<TreeType> &tree) {
insertLoopBranch
(
0
,
TARGET_DEPTH
,
false
);
insertLoopOtherHalf
(
TARGET_DEPTH
);
//tree->printBranchNode(0, tree->rootNode.branch);
auto
avg
=
std
::
accumulate
(
measures
.
begin
(),
measures
.
end
(),
0
)
/
measures
.
size
();
auto
minmax
=
std
::
minmax_element
(
std
::
begin
(
measures
),
std
::
end
(
measures
));
...
...
src/bench/trees/tree_get.cpp
View file @
78bc26c1
...
...
@@ -39,37 +39,32 @@ static void BM_TreeGet(benchmark::State &state) {
}
else
{
LOG
(
"Warning: "
<<
path
<<
" already exists"
);
pop
=
pool
<
root
>::
open
(
path
,
LAYOUT
);
pop
.
root
()
->
tree
->
recover
();
//<
FPTree
only
pop
.
root
()
->
tree
->
recover
();
//<
hybrids
only
}
auto
tree
=
pop
.
root
()
->
tree
;
//tree->printBranchNode(0, tree->rootNode.branch);
/* Getting a leaf node */
auto
node
=
tree
->
rootNode
;
/*
FPTree
version */
/*
hybrid
version
s
*/
auto
d
=
tree
->
depth
;
while
(
d
>
1
)
{
node
=
node
.
branch
->
children
[
0
];
--
d
;
}
if
(
d
==
1
)
node
=
node
.
lowest
branch
->
children
[
0
];
while
(
d
--
>
0
)
node
=
node
.
branch
->
children
[
0
];
/* nvm-only trees */
//auto d = tree->depth.get_ro();
//while ( d-- > 0
) node = node.branch->children
.get_ro()
[0];
/* other trees */
/*
auto d = tree->depth.get_ro();
while ( --d > 0) node = node.branch->children.get_ro()[0];
*/
auto
leaf
=
node
.
leaf
;
/* BENCHMARKING */
unsigned
int
p
;
for
(
auto
_
:
state
)
{
//MyTuple tp;
//auto c = 0u;
//auto func = [&](MyKey const &key, MyTuple const &val) { c++; };
//tree->scan(ELEMENTS/2, ELEMENTS/2 + 99, func);
//tree->lookup(ELEMENTS/2, &tp);
auto
p
=
tree
->
lookupPositionInLeafNode
(
leaf
,
1
);
benchmark
::
DoNotOptimize
(
p
=
tree
->
lookupPositionInLeafNode
(
leaf
,
LEAFKEYS
)
);
}
//tree->printBranchNode(0, tree->rootNode.branch);
std
::
cout
<<
"Elements:"
<<
ELEMENTS
<<
'\n'
;
pop
.
close
();
...
...
src/bench/trees/tree_insert.cpp
0 → 100644
View file @
78bc26c1
/*
* Copyright (C) 2017-2019 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/>.
*/
#include
<filesystem>
#include
"common.hpp"
void
prepare
(
const
persistent_ptr
<
TreeType
>
tree
);
/* Get benchmarks on Tree */
static
void
BM_TreeInsert
(
benchmark
::
State
&
state
)
{
std
::
cout
<<
"BRANCHKEYS: "
<<
BRANCHKEYS
<<
"
\n
LEAFKEYS: "
<<
LEAFKEYS
<<
"
\n
"
;
struct
root
{
persistent_ptr
<
TreeType
>
tree
;
};
pool
<
root
>
pop
;
if
(
access
(
path
.
c_str
(),
F_OK
)
!=
0
)
{
pop
=
pool
<
root
>::
create
(
path
,
LAYOUT
,
POOL_SIZE
);
transaction
::
run
(
pop
,
[
&
]
{
pop
.
root
()
->
tree
=
make_persistent
<
TreeType
>
();
});
}
else
{
LOG
(
"Warning: "
<<
path
<<
" already exists"
);
auto
n
=
std
::
filesystem
::
remove_all
(
path
);
pop
=
pool
<
root
>::
create
(
path
,
LAYOUT
);
transaction
::
run
(
pop
,
[
&
]
{
delete_persistent
<
TreeType
>
(
pop
.
root
()
->
tree
);
pop
.
root
()
->
tree
=
make_persistent
<
TreeType
>
();
});
}
auto
tree
=
pop
.
root
()
->
tree
;
/* Getting the leaf node */
auto
leaf
=
tree
->
rootNode
.
leaf
;
//tree->printLeafNode(0, leaf);
const
auto
reqTup
=
MyTuple
(
KEYPOS
,
KEYPOS
*
100
,
KEYPOS
*
1.0
);
TreeType
::
SplitInfo
splitInfo
;
bool
split
;
/* BENCHMARKING */
for
(
auto
_
:
state
)
{
state
.
PauseTiming
();
tree
->
rootNode
=
tree
->
newLeafNode
();
leaf
=
tree
->
rootNode
.
leaf
;
prepare
(
tree
);
//leaf->keys.getWrites();
state
.
ResumeTiming
();
split
=
tree
->
insertInLeafNode
(
leaf
,
KEYPOS
,
reqTup
,
&
splitInfo
);
state
.
PauseTiming
();
assert
(
split
==
false
);
//leaf->keys.getWrites();
tree
->
deleteLeafNode
(
leaf
);
state
.
ResumeTiming
();
}
//tree->printLeafNode(0, leaf);
std
::
cout
<<
"Elements:"
<<
ELEMENTS
<<
'\n'
;
pop
.
close
();
}
BENCHMARK
(
BM_TreeInsert
);
BENCHMARK_MAIN
();
/* preparing inserts */
void
prepare
(
const
persistent_ptr
<
TreeType
>
tree
)
{
auto
insertLoop
=
[
&
tree
](
int
start
,
int
end
)
{
for
(
auto
j
=
start
;
j
<
end
+
1
;
++
j
)
{
auto
tup
=
MyTuple
(
j
,
j
*
100
,
j
*
1.0
);
tree
->
insert
(
j
,
tup
);
}
};
switch
(
KEYPOS
)
{
case
1
/*first*/
:
insertLoop
(
2
,
ELEMENTS
);
break
;
case
ELEMENTS
/*last*/
:
insertLoop
(
1
,
ELEMENTS
-
1
);
break
;
case
ELEMENTS
/
2
/*middle*/
:
{
insertLoop
(
1
,
KEYPOS
-
1
);
insertLoop
(
KEYPOS
+
1
,
ELEMENTS
);}
}
}
src/bench/trees/tree_traverse.cpp
View file @
78bc26c1
...
...
@@ -39,35 +39,33 @@ static void BM_TreeTraverse(benchmark::State &state) {
}
else
{
LOG
(
"Warning: "
<<
path
<<
" already exists"
);
pop
=
pool
<
root
>::
open
(
path
,
LAYOUT
);
pop
.
root
()
->
tree
->
recover
();
//<
FPTree
only
//
pop.root()->tree->recover(); //<
Hybrids
only
}
auto
tree
=
pop
.
root
()
->
tree
;
persistent_ptr
<
TreeType
::
LeafNode
>
leaf
;
/* BENCHMARKING */
for
(
auto
_
:
state
)
{
/* Getting a leaf node */
auto
node
=
tree
->
rootNode
;
/*
FPTree
version */
/*
hybrid
version
s
*/
auto
d
=
tree
->
depth
;
while
(
d
>
1
)
{
node
=
node
.
branch
->
children
[
tree
->
lookupPositionInBranchNode
(
node
.
branch
,
1
)];
--
d
;
}
if
(
d
==
1
)
node
=
node
.
lowestbranch
->
children
[
0
];
while
(
--
d
>
0
)
node
=
node
.
branch
->
children
[
tree
->
lookupPositionInBranchNode
(
node
.
branch
,
KEYPOS
)];
/* NVM-only versions */
//auto d = tree->depth.get_ro();
//while ( --d > 0)
// node = node.branch->children.get_ro()[tree->lookupPositionInBranchNode(node.branch, KEYPOS)];
/* other trees */
/*
auto d = tree->depth.get_ro();
while ( --d > 0)
node = node.branch->children.get_ro()[tree->lookupPositionInBranchNode(node.branch, 1)];
*/
auto
leaf
=
node
.
leaf
;
benchmark
::
DoNotOptimize
(
leaf
=
node
.
leaf
);
//auto p = tree->lookupPositionInLeafNode(leaf, 1);
}
//tree->printBranchNode(0, tree->rootNode.branch);
std
::
cout
<<
"Elements:"
<<
ELEMENTS
<<
"
\n
"
;
std
::
cout
<<
"Size"
<<
sizeof
(
*
tree
)
<<
"
\n
"
;
pop
.
close
();
}
BENCHMARK
(
BM_TreeTraverse
);
...
...
src/fptree/FPTree.hpp
View file @
78bc26c1
This diff is collapsed.
Click to expand it.
src/pbptree/PBPTree.hpp
View file @
78bc26c1
...
...
@@ -796,24 +796,31 @@ class PBPTree {
bool
insertInLeafNode
(
persistent_ptr
<
LeafNode
>
node
,
const
KeyType
&
key
,
const
ValueType
&
val
,
SplitInfo
*
splitInfo
)
{
bool
split
=
false
;
const
auto
&
numKeys
=
node
->
numKeys
.
get_ro
();
auto
pos
=
lookupPositionInLeafNode
(
node
,
key
);
if
(
pos
<
node
->
numKeys
&&
node
->
keys
.
get_ro
()[
pos
]
==
key
)
{
if
(
pos
<
numKeys
&&
node
->
keys
.
get_ro
()[
pos
]
==
key
)
{
// handle insert of duplicates
std
::
cout
<<
"FORBIDDEN"
<<
std
::
endl
;
node
->
values
.
get_rw
()[
pos
]
=
val
;
return
false
;
}
if
(
node
->
numKeys
==
M
)
{
if
(
numKeys
==
M
)
{
// the node is full, so we must split it
// determine the split position
unsigned
int
middle
=
(
M
+
1
)
/
2
;
// move all entries behind this position to a new sibling node
persistent_ptr
<
LeafNode
>
sibling
=
newLeafNode
();
sibling
->
numKeys
=
node
->
numKeys
-
middle
;
for
(
auto
i
=
0u
;
i
<
sibling
->
numKeys
;
i
++
)
{
sibling
->
keys
.
get_rw
()[
i
]
=
node
->
keys
.
get_ro
()[
i
+
middle
];
sibling
->
values
.
get_rw
()[
i
]
=
node
->
values
.
get_ro
()[
i
+
middle
];
sibling
->
numKeys
=
numKeys
-
middle
;
const
auto
&
sNumKeys
=
sibling
->
numKeys
;
const
auto
&
nKeys
=
node
->
keys
.
get_ro
();
const
auto
&
nValues
=
node
->
values
.
get_ro
();
auto
&
sKeys
=
sibling
->
keys
.
get_rw
();
auto
&
sValues
=
sibling
->
values
.
get_rw
();
for
(
auto
i
=
0u
;
i
<
sNumKeys
;
i
++
)
{
sKeys
[
i
]
=
nKeys
[
i
+
middle
];
sValues
[
i
]
=
nValues
[
i
+
middle
];
}
node
->
numKeys
=
middle
;
node
->
numKeys
.
get_rw
()
=
middle
;
// insert the new entry
if
(
pos
<
middle
)
...
...
@@ -831,9 +838,10 @@ class PBPTree {
// and inform the caller about the split
split
=
true
;
splitInfo
->
leftChild
=
node
;
splitInfo
->
rightChild
=
sibling
;
splitInfo
->
key
=
sibling
->
keys
.
get_ro
()[
0
];
auto
&
splitInfoRef
=
*
splitInfo
;
splitInfoRef
.
leftChild
=
node
;
splitInfoRef
.
rightChild
=
sibling
;
splitInfoRef
.
key
=
sibling
->
keys
.
get_ro
()[
0
];
}
else
{
// otherwise, we can simply insert the new entry at the given position
insertInLeafNodeAtPosition
(
node
,
pos
,
key
,
val
);
...
...
@@ -855,18 +863,19 @@ class PBPTree {
*/
void
insertInLeafNodeAtPosition
(
persistent_ptr
<
LeafNode
>
node
,
unsigned
int
pos
,
const
KeyType
&
key
,
const
ValueType
&
val
)
{
const
auto
&
numKeys
=
node
->
numKeys
.
get_ro
();
assert
(
pos
<
M
);
assert
(
pos
<=
node
->
numKeys
);
assert
(
node
->
numKeys
<
M
);
assert
(
pos
<=
numKeys
);
assert
(
numKeys
<
M
);
// we move all entries behind pos by one position
for
(
unsigned
int
i
=
node
->
numKeys
;
i
>
pos
;
i
--
)
{
for
(
unsigned
int
i
=
numKeys
;
i
>
pos
;
i
--
)
{
node
->
keys
.
get_rw
()[
i
]
=
node
->
keys
.
get_ro
()[
i
-
1
];
node
->
values
.
get_rw
()[
i
]
=
node
->
values
.
get_ro
()[
i
-
1
];
}
// and then insert the new entry at the given position
node
->
keys
.
get_rw
()[
pos
]
=
key
;
node
->
values
.
get_rw
()[
pos
]
=
val
;
node
->
numKeys
=
node
->
numKeys
+
1
;
node
->
numKeys
.
get_rw
()
=
numKeys
+
1
;
}
/**
...
...
@@ -997,7 +1006,8 @@ class PBPTree {
const
KeyType
&
key
)
const
{
unsigned
int
pos
=
0
;
const
unsigned
int
num
=
node
->
numKeys
;
//for (; pos < num && node->keys.get_ro()[pos] <= key; pos++);
//const auto &keys = node->keys.get_ro();
//for (; pos < num && keys[pos] <= key; pos++);
//return pos;
return
binarySearch
(
node
,
0
,
num
-
1
,
key
);
}
...
...
@@ -1015,7 +1025,8 @@ class PBPTree {
const
KeyType
&
key
)
const
{
unsigned
int
pos
=
0
;
const
unsigned
int
num
=
node
->
numKeys
.
get_ro
();
//for (; pos < num && node->keys.get_ro()[pos] < key; pos++);
//const auto &keys = node->keys.get_ro();
//for (; pos < num && keys[pos] < key; pos++);
//return pos;
return
binarySearch
(
node
,
0
,
num
-
1
,
key
);
}
...
...
@@ -1023,10 +1034,11 @@ class PBPTree {
unsigned
int
binarySearch
(
persistent_ptr
<
BranchNode
>
node
,
int
l
,
int
r
,
KeyType
const
&
key
)
const
{
auto
pos
=
0u
;
const
auto
&
keys
=
node
->
keys
.
get_ro
();
while
(
l
<=
r
)
{
pos
=
(
l
+
r
)
/
2
;
if
(
node
->
keys
.
get_ro
()
[
pos
]
==
key
)
return
++
pos
;
if
(
node
->
keys
.
get_ro
()
[
pos
]
<
key
)
l
=
++
pos
;
if
(
keys
[
pos
]
==
key
)
return
++
pos
;
if
(
keys
[
pos
]
<
key
)
l
=
++
pos
;
else
r
=
pos
-
1
;
}
return
pos
;
...
...
@@ -1035,10 +1047,11 @@ class PBPTree {
unsigned
int
binarySearch
(
persistent_ptr
<
LeafNode
>
node
,
int
l
,
int
r
,
KeyType
const
&
key
)
const
{
auto
pos
=
0u
;
const
auto
&
keys
=
node
->
keys
.
get_ro
();
while
(
l
<=
r
)
{
pos
=
(
l
+
r
)
/
2
;
if
(
node
->
keys
.
get_ro
()
[
pos
]
==
key
)
return
pos
;
if
(
node
->
keys
.
get_ro
()
[
pos
]
<
key
)
l
=
++
pos
;
if
(
keys
[
pos
]
==
key
)
return
pos
;
if
(
keys
[
pos
]
<
key
)
l
=
++
pos
;
else
r
=
pos
-
1
;
}
return
pos
;
...
...
src/pbptree/UnsortedPBPTree.hpp
View file @
78bc26c1
...
...
@@ -29,6 +29,7 @@
#include
<libpmemobj++/transaction.hpp>
#include
<libpmemobj++/utils.hpp>
#include
"utils/ElementOfRankK.hpp"
#include
"config.h"
#define BRANCH_PADDING 0
#define LEAF_PADDING 0
...
...
@@ -55,8 +56,6 @@ class UnsortedPBPTree {
static_assert
(
N
>
2
,
"number of branch keys has to be >2."
);
// we need at least one key on a leaf node
static_assert
(
M
>
0
,
"number of leaf keys should be >0."
);
// there is a bug that for odd numbers the tree sometimes breaks (TODO)
static_assert
(
M
%
2
==
0
&&
N
%
2
==
0
,
"The number of keys should be even"
);
#ifndef UNIT_TESTS
private:
...
...
@@ -265,10 +264,10 @@ class UnsortedPBPTree {
auto
leafNode
=
findLeafNode
(
key
);
auto
pos
=
lookupPositionInLeafNode
(
leafNode
,
key
);
PROFILE_READ
()
PROFILE_READ
(
1
)
if
(
pos
<
leafNode
->
numKeys
&&
leafNode
->
keys
.
get_ro
()[
pos
]
==
key
)
{
// we found it!
PROFILE_READ
()
PROFILE_READ
(
1
)
*
val
=
leafNode
->
values
.
get_ro
()[
pos
];
result
=
true
;
}
...
...
@@ -325,12 +324,12 @@ class UnsortedPBPTree {
void
scan
(
ScanFunc
func
)
const
{
// we traverse to the leftmost leaf node
auto
node
=
rootNode
;
PROFILE_READ
()
PROFILE_READ
(
1
)
auto
d
=
depth
.
get_ro
();
while
(
d
--
>
0
)
{
// as long as we aren't at the leaf level we follow the path down
auto
n
=
node
.
branch
;
PROFILE_READ
()
PROFILE_READ
(
1
)
node
=
n
->
children
.
get_ro
()[
0
];
}
auto
leaf
=
node
.
leaf
;
...
...
@@ -361,10 +360,10 @@ class UnsortedPBPTree {
while
(
leaf
!=
nullptr
)
{
// for each key-value pair within the range call func
for
(
auto
i
=
0u
;
i
<
leaf
->
numKeys
;
i
++
)
{
PROFILE_READ
()
PROFILE_READ
(
1
)
auto
&
key
=
leaf
->
keys
.
get_ro
()[
i
];
if
(
key
>
maxKey
)
return
;
PROFILE_READ
()
PROFILE_READ
(
1
)
auto
&
val
=
leaf
->
values
.
get_ro
()[
i
];
func
(
key
,
val
);
}
...
...
@@ -425,13 +424,13 @@ class UnsortedPBPTree {
if
(
pos
>
0
&&
leaf
->
prevLeaf
->
numKeys
>
middle
)
{
// we have a sibling at the left for rebalancing the keys
balanceLeafNodes
(
leaf
->
prevLeaf
,
leaf
);
PROFILE_READ
()
PROFILE_READ
(
1
)
PROFILE_WRITE
()
node
->
keys
.
get_rw
()[
pos
-
1
]
=
leaf
->
keys
.
get_ro
()[
findMinKeyAtLeafNode
(
leaf
)];