Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
PMem-based Data Structures
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
code
PMem-based Data Structures
Commits
6a415514
Commit
6a415514
authored
Feb 10, 2020
by
Alexander Baumstark
Committed by
Administrator
Feb 10, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added persistent skiplist implementations
parent
6fcc2d9c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
588 additions
and
0 deletions
+588
-0
CMakeLists.txt
CMakeLists.txt
+1
-0
src/pskiplists/CMakeLists.txt
src/pskiplists/CMakeLists.txt
+17
-0
src/pskiplists/simplePSkiplist.hpp
src/pskiplists/simplePSkiplist.hpp
+208
-0
src/pskiplists/woPSkiplist.hpp
src/pskiplists/woPSkiplist.hpp
+362
-0
No files found.
CMakeLists.txt
View file @
6a415514
...
...
@@ -102,6 +102,7 @@ add_subdirectory(src/pbptrees) # Persistent versions of B⁺-Tree, contains also
# - Remake of the wB+Tree
add_subdirectory
(
src/ptable
)
# BDCC-based analytical table structure
add_subdirectory
(
src/pskiplists
)
#########################
# Unit test using Catch #
#########################
...
...
src/pskiplists/CMakeLists.txt
0 → 100644
View file @
6a415514
project
(
pskiplists
)
include_directories
(
${
PROJECT_SOURCE_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
)
################
# Installation #
################
#
set
(
PROJECT_INCLUDES_F
${
PROJECT_INCLUDES_F
}
${
CMAKE_CURRENT_SOURCE_DIR
}
/simplePSkiplist.hpp
${
CMAKE_CURRENT_SOURCE_DIR
}
/woPSkiplist.hpp
PARENT_SCOPE
)
src/pskiplists/simplePSkiplist.hpp
0 → 100644
View file @
6a415514
#ifndef SIMPLE_PSKIPLIST_HPP
#define SIMPLE_PSKIPLIST_HPP
#include <cstdlib>
#include <cstdint>
#include <iostream>
#include <libpmemobj++/utils.hpp>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/experimental/array.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/transaction.hpp>
namespace
pmemobj_exp
=
pmem
::
obj
::
experimental
;
using
pmem
::
obj
::
delete_persistent
;
using
pmem
::
obj
::
make_persistent
;
using
pmem
::
obj
::
p
;
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
));
}
};
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
;
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
;
});
}
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
;
});
}
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
;
}
int
getRandomLevel
()
{
int
level
=
static_cast
<
int
>
(
rnd
.
Uniform
(
MAX_LEVEL
));
if
(
level
==
0
)
{
level
=
1
;
}
return
level
;
}
public:
simplePSkiplist
(
KeyType
tailKey
)
:
rnd
(
0x12345678
)
{
createList
(
tailKey
);
}
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
];
auto
node
=
head
;
for
(
int
i
=
level
;
i
>=
0
;
--
i
)
{
while
(
node
->
forward
[
i
]
->
key
<
key
)
{
node
=
node
->
forward
[
i
];
}
update
[
i
]
=
node
;
}
node
=
node
->
forward
[
0
];
if
(
node
->
key
==
key
)
{
ret
=
false
;
}
auto
nodeLevel
=
getRandomLevel
();
if
(
nodeLevel
>
level
)
{
nodeLevel
=
++
level
;
update
[
nodeLevel
]
=
head
;
}
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
;
}
++
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
;
}
}
};
#endif //SKIPLIST_SKIPLIST_HPP
src/pskiplists/woPSkiplist.hpp
0 → 100644
View file @
6a415514
#ifndef WOP_SKIPLIST_HPP
#define WOP_SKIPLIST_HPP
#include <cstdlib>
#include <cstdint>
#include <iostream>
#include <array>
#include <bitset>
#include <libpmemobj++/utils.hpp>
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/transaction.hpp>
using
pmem
::
obj
::
delete_persistent
;
using
pmem
::
obj
::
make_persistent
;
using
pmem
::
obj
::
p
;
using
pmem
::
obj
::
persistent_ptr
;
using
pmem
::
obj
::
transaction
;
class
Random
{
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
;
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
));
}
private:
uint32_t
seed
;
};
//N = Bucket size
//M = Max 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
();
}
bool
keyBetween
(
KeyType
newKey
)
{
if
(
minKey
==
-
1
||
maxKey
==
-
1
)
return
true
;
return
newKey
>=
minKey
&&
newKey
<=
maxKey
;
}
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
;
}
void
splitNode
(
persistent_ptr
<
SkipNode
>
prevNode
,
persistent_ptr
<
SkipNode
>
nextNode
,
int
listLevel
)
{
auto
pop
=
pmem
::
obj
::
pool_by_vptr
(
this
);
transaction
::
run
(
pop
,
[
&
]
{
auto
newNode
=
make_persistent
<
SkipNode
>
();
newNode
->
forward
=
make_persistent
<
std
::
array
<
persistent_ptr
<
SkipNode
>
,
M
>>
();
newNode
->
forward
.
get
()
->
at
(
0
)
=
nextNode
;
newNode
->
maxKey
=
this
->
minKey
;
newNode
->
minKey
=
this
->
maxKey
;
this
->
forward
.
get
()
->
at
(
0
)
=
newNode
;
int
leftPos
=
0
;
auto
avg
=
getAvg
();
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
if
(
bitset
.
get_ro
().
test
(
i
))
{
if
(
key
.
get_ro
()[
i
]
>=
avg
)
{
newNode
->
key
.
get_rw
()[
leftPos
]
=
key
.
get_ro
()[
i
];
newNode
->
value
.
get_rw
()[
leftPos
]
=
value
.
get_ro
()[
i
];
newNode
->
bitset
.
get_rw
().
set
(
leftPos
);
bitset
.
get_rw
().
reset
(
i
);
leftPos
++
;
if
(
key
.
get_ro
()[
i
]
<
newNode
->
minKey
)
newNode
->
minKey
=
key
.
get_ro
()[
i
];
if
(
key
.
get_ro
()[
i
]
>
newNode
->
maxKey
)
newNode
->
maxKey
=
key
.
get_ro
()[
i
];
}
}
}
refreshBounds
();
});
}
void
refreshBounds
()
{
KeyType
tmpMax
=
-
1
;
KeyType
tmpMin
=
-
1
;
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
if
(
bitset
.
get_ro
().
test
(
i
))
{
if
(
tmpMax
==
-
1
||
key
.
get_ro
()[
i
]
>
tmpMax
)
tmpMax
=
key
.
get_ro
()[
i
];
if
(
tmpMin
==
-
1
||
key
.
get_ro
()[
i
]
<
tmpMin
)
tmpMin
=
key
.
get_ro
()[
i
];
}
}
maxKey
.
get_rw
()
=
tmpMax
;
minKey
.
get_rw
()
=
tmpMin
;
}
void
insertInNode
(
persistent_ptr
<
SkipNode
>
prevNode
,
KeyType
k
,
ValueType
v
,
bool
&
splitInfo
,
int
level
)
{
if
(
isFull
())
{
splitNode
(
prevNode
,
forward
.
get
()
->
at
(
0
),
level
);
//prevNode->forward[0]->key[3] = k;
//prevNode->forward[0]->bitset.set(3);
splitInfo
=
true
;
return
;
}
int
freeSlot
=
0
;
while
(
bitset
.
get_ro
().
test
(
freeSlot
))
{
freeSlot
++
;
}
key
.
get_rw
().
at
(
freeSlot
)
=
k
;
value
.
get_rw
().
at
(
freeSlot
)
=
v
;
bitset
.
get_rw
().
set
(
freeSlot
);
if
(
this
->
minKey
==
-
1
||
k
<
this
->
minKey
)
{
this
->
minKey
=
k
;
}
else
if
(
this
->
maxKey
==
-
1
||
k
>
this
->
maxKey
)
{
this
->
maxKey
=
k
;
}
}
void
printNode
()
{
std
::
cout
<<
"{"
<<
minKey
<<
"|"
<<
maxKey
<<
"}["
;
for
(
int
i
=
0
;
i
<
N
;
i
++
)
{
if
(
bitset
.
get_ro
().
test
(
i
))
std
::
cout
<<
key
.
get_ro
()[
i
]
<<
","
;
}
std
::
cout
<<
"]->"
;
}
};
persistent_ptr
<
SkipNode
>
head
;
persistent_ptr
<
SkipNode
>
tail
;
p
<
int
>
level
;
bool
nl
;
p
<
size_t
>
nodeCount
;
static
const
int
MAX_LEVEL
=
M
;
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
<
std
::
array
<
persistent_ptr
<
SkipNode
>
,
M
>>
();
node
->
nodeLevel
=
level
;
node
->
maxKey
=
-
1
;
node
->
minKey
=
-
1
;
});
}
void
createList
(
KeyType
tailKey
)
{
auto
pop
=
pmem
::
obj
::
pool_by_vptr
(
this
);
transaction
::
run
(
pop
,
[
&
]
{
createNode
(
0
,
tail
);
tail
->
maxKey
=
-
tailKey
;
tail
->
minKey
=
tailKey
;
this
->
level
=
0
;
createNode
(
MAX_LEVEL
,
head
);
for
(
int
i
=
0
;
i
<
MAX_LEVEL
;
++
i
)
{
head
->
forward
.
get
()
->
at
(
i
)
=
tail
.
get
();
}
nodeCount
=
0
;
});
}
int
getRandomLevel
()
{
int
level
=
static_cast
<
int
>
(
rnd
.
Uniform
(
MAX_LEVEL
));
if
(
level
==
0
)
{
level
=
1
;
}
return
level
;
}
public:
woPSkiplist
(
KeyType
tailKey
)
:
rnd
(
0x12378
)
{
createList
(
tailKey
);
nl
=
false
;
}
bool
insert
(
KeyType
key
,
ValueType
value
)
{
reInsert:
auto
update
=
new
SkipNode
[
MAX_LEVEL
]();
auto
node
=
head
;
auto
prev
=
head
;
auto
last
=
head
;
for
(
int
i
=
level
;
i
>=
0
;
--
i
)
{
while
((
node
->
maxKey
<=
key
))
{
if
(
node
->
forward
.
get
()
->
at
(
i
)
==
nullptr
)
break
;
last
=
prev
;
prev
=
node
;
node
=
node
->
forward
.
get
()
->
at
(
i
);
}
if
(
node
->
maxKey
>
key
)
{
node
=
prev
;
prev
=
last
;
}
update
[
i
]
=
*
prev
;
}
auto
nodeLevel
=
getRandomLevel
();
bool
splitInfo
=
false
;
if
(
node
->
forward
.
get
()
->
at
(
0
))
{
prev
=
node
;
node
=
node
->
forward
.
get
()
->
at
(
0
);
}
node
->
insertInNode
(
prev
,
key
,
value
,
*&
splitInfo
,
level
);
if
(
splitInfo
)
{
nl
=
true
;
nodeCount
.
get_rw
()
++
;
goto
reInsert
;
}
if
(
nl
)
{
if
(
nodeLevel
>
level
.
get_ro
())
{
nodeLevel
=
++
level
.
get_rw
();
update
[
nodeLevel
]
=
*
head
;
}
auto
n
=
&
update
[
nodeLevel
];
for
(
int
i
=
nodeLevel
;
i
>=
1
;
--
i
)
{
update
[
i
].
forward
.
get
()
->
at
(
i
)
=
node
;
prev
->
forward
[
i
]
=
update
[
i
].
forward
[
i
];
}
nl
=
false
;
}
return
true
;
}
persistent_ptr
<
SkipNode
>
searchNode
(
const
KeyType
key
)
{
auto
pred
=
head
;
for
(
int
i
=
level
;
i
>=
0
;
i
--
)
{
auto
item
=
pred
->
forward
.
get
()
->
at
(
i
);
while
(
item
!=
nullptr
)
{
if
(
key
>
item
->
maxKey
)
{
pred
=
item
;
item
=
item
->
forward
.
get
()
->
at
(
i
);
}
else
if
(
key
<
item
->
minKey
)
{
break
;
}
else
{
return
item
;
}
}
}
}
ValueType
*
search
(
const
KeyType
key
)
{
auto
node
=
searchNode
(
key
);
if
(
node
)
{
return
node
->
searchKey
(
key
);
}
else
{
return
nullptr
;
}
}
void
printElementNode
()
{
std
::
cout
<<
"
\n
Level: "
<<
level
<<
std
::
endl
;
auto
tmp
=
head
;
for
(
int
i
=
level
;
i
>=
0
;
i
--
)
{
while
(
tmp
!=
nullptr
&&
tmp
->
forward
)
{
tmp
->
printNode
();
tmp
=
tmp
->
forward
.
get
()
->
at
(
i
);
}
tmp
=
head
;
std
::
cout
<<
std
::
endl
;
}
}
void
printLastLevel
()
{
auto
tmp
=
head
;
while
(
tmp
!=
nullptr
&&
tmp
->
forward
)
{
tmp
->
printNode
();
tmp
=
tmp
->
forward
[
0
];
}
}
};
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment