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
c44518af
Commit
c44518af
authored
Jun 15, 2020
by
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
Changes
12
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
c44518af
...
...
@@ -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 #
#########################
...
...
src/pskiplists/simplePSkiplist.hpp
View file @
c44518af
/*
* 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 //S
KIPLIST_
SKIPLIST_HPP
#endif //S
IMPLE_P
SKIPLIST_HPP
src/pskiplists/woPSkiplist.hpp
View file @
c44518af
/*
* 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
;
}
return
newKey
>=
minKey
&&
newKey
<=
maxKey
;
}