Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
FORMUS3IC_LAS3
/
embb
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
34f6e4f3
authored
9 years ago
by
Danila Klimenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
chromatic_tree: lock-free implementation without rebalancing
parent
e518a31d
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
623 additions
and
169 deletions
+623
-169
containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h
+1
-1
containers_cpp/include/embb/containers/internal/hazard_pointer.h
+1
-1
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
+251
-133
containers_cpp/include/embb/containers/internal/object_pool-inl.h
+14
-0
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
+345
-29
containers_cpp/include/embb/containers/object_pool.h
+6
-0
containers_cpp/test/tree_test-inl.h
+5
-5
No files found.
containers_cpp/include/embb/containers/internal/hazard_pointer-inl.h
View file @
34f6e4f3
...
...
@@ -478,7 +478,7 @@ Type& UniqueHazardPointer<Type>::operator*() const {
}
template
<
typename
Type
>
void
UniqueHazardPointer
<
Type
>::
Adopt
Gu
ard
(
const
UniqueHazardPointer
&
other
)
{
void
UniqueHazardPointer
<
Type
>::
Adopt
Haz
ard
(
const
UniqueHazardPointer
&
other
)
{
assert
(
OwnsHazardGuard
());
StoreGuardedPointer
(
other
.
LoadGuardedPointer
());
SetActive
(
other
.
active_
);
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/internal/hazard_pointer.h
View file @
34f6e4f3
...
...
@@ -620,7 +620,7 @@ class UniqueHazardPointer {
* \param other Another wrapper those protected pointer is to be protected by
* the calling wrapper
*/
void
Adopt
Gu
ard
(
const
UniqueHazardPointer
&
other
);
void
Adopt
Haz
ard
(
const
UniqueHazardPointer
&
other
);
/**
* Swaps the guard ownership with another wrapper. Swaps not just the
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
View file @
34f6e4f3
...
...
@@ -45,23 +45,26 @@ namespace internal {
template
<
typename
Key
,
typename
Value
>
ChromaticTreeNode
<
Key
,
Value
>::
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Node
*
left
,
Node
*
right
)
Node
*
left
,
Node
*
right
,
Operation
*
operation
)
:
key_
(
key
),
value_
(
value
),
weight_
(
weight
),
left_
(
left
),
right_
(
right
),
retired_
(
false
)
{}
retired_
(
false
),
operation_
(
operation
)
{}
template
<
typename
Key
,
typename
Value
>
ChromaticTreeNode
<
Key
,
Value
>::
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
)
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Operation
*
operation
)
:
key_
(
key
),
value_
(
value
),
weight_
(
weight
),
left_
(
NULL
),
right_
(
NULL
),
retired_
(
false
)
{}
retired_
(
false
),
operation_
(
operation
)
{}
template
<
typename
Key
,
typename
Value
>
const
Key
&
ChromaticTreeNode
<
Key
,
Value
>::
GetKey
()
const
{
...
...
@@ -126,11 +129,6 @@ bool ChromaticTreeNode<Key, Value>::IsRetired() const {
return
retired_
;
}
template
<
typename
Key
,
typename
Value
>
embb
::
base
::
Mutex
&
ChromaticTreeNode
<
Key
,
Value
>::
GetMutex
()
{
return
mutex_
;
}
}
// namespace internal
...
...
@@ -144,7 +142,11 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value,
#endif
:
node_hazard_manager_
(
embb
::
base
::
Function
<
void
,
Node
*>
(
*
this
,
&
ChromaticTree
::
FreeNode
),
NULL
,
10
),
NULL
,
HIDX_MAX
),
operation_hazard_manager_
(
embb
::
base
::
Function
<
void
,
Operation
*>
(
*
this
,
&
ChromaticTree
::
FreeOperation
),
NULL
,
HIDX_MAX
),
#ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop)
#endif
...
...
@@ -155,10 +157,16 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value,
node_pool_
(
2
+
5
+
2
*
capacity_
+
node_hazard_manager_
.
GetRetiredListMaxSize
()
*
embb
::
base
::
Thread
::
GetThreadsMaxCount
()),
operation_pool_
(
2
+
5
+
2
*
capacity_
+
operation_hazard_manager_
.
GetRetiredListMaxSize
()
*
embb
::
base
::
Thread
::
GetThreadsMaxCount
()),
entry_
(
node_pool_
.
Allocate
(
undefined_key_
,
undefined_value_
,
1
,
node_pool_
.
Allocate
(
undefined_key_
,
undefined_value_
),
static_cast
<
Node
*>
(
NULL
)))
{
undefined_value_
,
1
,
Operation
::
INITIAL_DUMMY
),
static_cast
<
Node
*>
(
NULL
),
Operation
::
INITIAL_DUMMY
))
{
assert
(
entry_
!=
NULL
);
assert
(
entry_
->
GetLeft
()
!=
NULL
);
}
...
...
@@ -173,9 +181,10 @@ ChromaticTree<Key, Value, Compare, ValuePool>::
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
Get
(
const
Key
&
key
,
Value
&
value
)
{
HazardNodePtr
parent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
leaf
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
Search
(
key
,
leaf
,
parent
);
HazardNodePtr
grandparent
(
GetNodeGuard
(
HIDX_GRANDPARENT
));
HazardNodePtr
parent
(
GetNodeGuard
(
HIDX_PARENT
));
HazardNodePtr
leaf
(
GetNodeGuard
(
HIDX_LEAF
));
Search
(
key
,
leaf
,
parent
,
grandparent
);
bool
keys_are_equal
=
!
IsSentinel
(
leaf
)
&&
!
(
compare_
(
key
,
leaf
->
GetKey
())
||
...
...
@@ -205,52 +214,87 @@ TryInsert(const Key& key, const Value& value, Value& old_value) {
bool
added_violation
=
false
;
while
(
!
insertion_succeeded
)
{
HazardNodePtr
parent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
leaf
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
Search
(
key
,
leaf
,
parent
);
HazardNodePtr
grandparent
(
GetNodeGuard
(
HIDX_GRANDPARENT
));
HazardNodePtr
parent
(
GetNodeGuard
(
HIDX_PARENT
));
HazardNodePtr
leaf
(
GetNodeGuard
(
HIDX_LEAF
));
Search
(
key
,
leaf
,
parent
,
grandparent
);
//
Try to lock
the parent
UniqueLock
parent_lock
(
parent
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
parent_lock
.
OwnsLock
()
||
parent
->
IsRetired
(
))
continue
;
//
Protect
the parent
HazardOperationPtr
parent_op
(
GetOperationGuard
(
HIDX_PARENT
)
);
if
(
!
WeakLLX
(
parent
,
parent_op
))
continue
;
// Verify that the leaf is still the parent's child
if
(
!
HasChild
(
parent
,
leaf
))
continue
;
//
Try to lock
the leaf
UniqueLock
leaf_lock
(
leaf
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
leaf_lock
.
OwnsLock
()
||
leaf
->
IsRetired
(
))
continue
;
//
Protect
the leaf
HazardOperationPtr
leaf_op
(
GetOperationGuard
(
HIDX_LEAF
)
);
if
(
!
WeakLLX
(
leaf
,
leaf_op
))
continue
;
bool
keys_are_equal
=
!
IsSentinel
(
leaf
)
&&
!
(
compare_
(
key
,
leaf
->
GetKey
())
||
compare_
(
leaf
->
GetKey
(),
key
));
if
(
keys_are_equal
)
{
// Reached leaf has a matching key: replace it with a new copy
if
(
!
IsSentinel
(
leaf
)
&&
!
(
compare_
(
key
,
leaf
->
GetKey
())
||
compare_
(
leaf
->
GetKey
(),
key
)))
{
old_value
=
leaf
->
GetValue
();
new_parent
=
node_pool_
.
Allocate
(
key
,
value
,
leaf
->
GetWeight
());
new_parent
=
node_pool_
.
Allocate
(
key
,
value
,
leaf
->
GetWeight
(),
Operation
::
INITIAL_DUMMY
);
if
(
new_parent
==
NULL
)
break
;
// Reached leaf has a different key: add a new leaf
}
else
{
old_value
=
undefined_value_
;
new_leaf
=
node_pool_
.
Allocate
(
key
,
value
);
new_leaf
=
node_pool_
.
Allocate
(
key
,
value
,
1
,
Operation
::
INITIAL_DUMMY
);
if
(
new_leaf
==
NULL
)
break
;
new_sibling
=
node_pool_
.
Allocate
(
leaf
->
GetKey
(),
leaf
->
GetValue
());
new_sibling
=
node_pool_
.
Allocate
(
leaf
->
GetKey
(),
leaf
->
GetValue
(),
1
,
Operation
::
INITIAL_DUMMY
);
if
(
new_sibling
==
NULL
)
break
;
int
new_weight
=
(
IsSentinel
(
parent
))
?
1
:
(
leaf
->
GetWeight
()
-
1
);
if
(
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
{
new_parent
=
node_pool_
.
Allocate
(
leaf
->
GetKey
(),
undefined_value_
,
new_weight
,
new_leaf
,
new_sibling
);
new_weight
,
new_leaf
,
new_sibling
,
Operation
::
INITIAL_DUMMY
);
}
else
{
new_parent
=
node_pool_
.
Allocate
(
key
,
undefined_value_
,
new_weight
,
new_sibling
,
new_leaf
);
new_weight
,
new_sibling
,
new_leaf
,
Operation
::
INITIAL_DUMMY
);
}
if
(
new_parent
==
NULL
)
break
;
}
insertion_succeeded
=
parent
->
ReplaceChild
(
leaf
,
new_parent
);
assert
(
insertion_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
insertion_succeeded
)
continue
;
// Create and fill the operation object
HazardOperationPtr
insert_op
(
GetOperationGuard
(
HIDX_CURRENT_OP
));
insert_op
.
ProtectSafe
(
operation_pool_
.
Allocate
());
if
(
insert_op
==
NULL
)
break
;
insert_op
->
SetRoot
(
parent
,
parent_op
);
insert_op
->
SetOldNodes
(
leaf
,
leaf_op
);
insert_op
->
SetNewChild
(
new_parent
);
// Execute operation
insertion_succeeded
=
insert_op
->
Help
(
GetNodeGuard
(
HIDX_HELPING
),
GetOperationGuard
(
HIDX_HELPING
));
insert_op
->
CleanUp
();
// If operation failed
if
(
!
insertion_succeeded
)
{
// Retire failed operation
RetireOperation
(
insert_op
);
// Delete new nodes
FreeNode
(
new_parent
);
new_parent
=
NULL
;
if
(
!
keys_are_equal
)
{
FreeNode
(
new_leaf
);
new_leaf
=
NULL
;
FreeNode
(
new_sibling
);
new_sibling
=
NULL
;
}
// Restart from scratch
continue
;
}
RetireHazardousNode
(
leaf
,
leaf_lock
);
// Retire old operation objects
RetireOperation
(
parent_op
);
RetireOperation
(
leaf_op
);
// Retire old nodes
RetireNode
(
leaf
);
added_violation
=
(
parent
->
GetWeight
()
==
0
&&
new_parent
->
GetWeight
()
==
0
);
...
...
@@ -282,9 +326,9 @@ TryDelete(const Key& key, Value& old_value) {
bool
added_violation
=
false
;
while
(
!
deletion_succeeded
)
{
HazardNodePtr
grandparent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
parent
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
HazardNodePtr
leaf
(
node_hazard_manager_
.
GetGuardedPointer
(
2
));
HazardNodePtr
grandparent
(
GetNodeGuard
(
HIDX_GRANDPARENT
));
HazardNodePtr
parent
(
GetNodeGuard
(
HIDX_PARENT
));
HazardNodePtr
leaf
(
GetNodeGuard
(
HIDX_LEAF
));
Search
(
key
,
leaf
,
parent
,
grandparent
);
// Reached leaf has a different key - nothing to delete
...
...
@@ -295,18 +339,18 @@ TryDelete(const Key& key, Value& old_value) {
break
;
}
//
Try to lock
the grandparent
UniqueLock
grandparent_lock
(
grandparent
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
grandparent_lock
.
OwnsLock
()
||
grandparent
->
IsRetired
(
))
continue
;
// Verify that the parent is still the
grandparent's child
//
Protect
the grandparent
HazardOperationPtr
grandparent_op
(
GetOperationGuard
(
HIDX_GRANDPARENT
)
);
if
(
!
WeakLLX
(
grandparent
,
grandparent_op
))
continue
;
// Verify that the parent is still the
child of grandparent
if
(
!
HasChild
(
grandparent
,
parent
))
continue
;
//
Try to lock
the parent
UniqueLock
parent_lock
(
parent
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
parent_lock
.
OwnsLock
()
||
parent
->
IsRetired
(
))
continue
;
//
Protect
the parent
HazardOperationPtr
parent_op
(
GetOperationGuard
(
HIDX_PARENT
)
);
if
(
!
WeakLLX
(
parent
,
parent_op
))
continue
;
// Get the sibling (and protect it with hazard pointer)
HazardNodePtr
sibling
(
node_hazard_manager_
.
GetGuardedPointer
(
3
));
HazardNodePtr
sibling
(
GetNodeGuard
(
HIDX_SIBLING
));
sibling
.
ProtectHazard
((
parent
->
GetLeft
()
==
leaf
)
?
parent
->
GetRight
()
:
parent
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
sibling
.
IsActive
())
continue
;
...
...
@@ -315,31 +359,56 @@ TryDelete(const Key& key, Value& old_value) {
// Verify that the leaf is still the parent's child
if
(
!
HasChild
(
parent
,
leaf
))
continue
;
//
Try to lock
the sibling
UniqueLock
sibling_lock
(
sibling
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
sibling_lock
.
OwnsLock
()
||
sibling
->
IsRetired
(
))
continue
;
//
Protect
the sibling
HazardOperationPtr
sibling_op
(
GetOperationGuard
(
HIDX_SIBLING
)
);
if
(
!
WeakLLX
(
sibling
,
sibling_op
))
continue
;
//
Try to lock
the leaf
UniqueLock
leaf_lock
(
leaf
->
GetMutex
(),
embb
::
base
::
try_lock
);
if
(
!
leaf_lock
.
OwnsLock
()
||
leaf
->
IsRetired
(
))
continue
;
//
Protect
the leaf
HazardOperationPtr
leaf_op
(
GetOperationGuard
(
HIDX_LEAF
)
);
if
(
!
WeakLLX
(
leaf
,
leaf_op
))
continue
;
int
new_weight
=
(
IsSentinel
(
grandparent
))
?
1
:
(
parent
->
GetWeight
()
+
sibling
->
GetWeight
());
new_leaf
=
node_pool_
.
Allocate
(
sibling
->
GetKey
(),
sibling
->
GetValue
(),
new_weight
,
sibling
->
GetLeft
(),
sibling
->
GetRight
());
sibling
->
GetLeft
(),
sibling
->
GetRight
()
,
Operation
::
INITIAL_DUMMY
);
if
(
new_leaf
==
NULL
)
break
;
old_value
=
leaf
->
GetValue
();
deletion_succeeded
=
grandparent
->
ReplaceChild
(
parent
,
new_leaf
);
assert
(
deletion_succeeded
);
// For now (FGL tree) this CAS may not fail
if
(
!
deletion_succeeded
)
continue
;
// Create and fill the operation object
HazardOperationPtr
delete_op
(
GetOperationGuard
(
HIDX_CURRENT_OP
));
delete_op
.
ProtectSafe
(
operation_pool_
.
Allocate
());
if
(
delete_op
==
NULL
)
break
;
delete_op
->
SetRoot
(
grandparent
,
grandparent_op
);
delete_op
->
SetOldNodes
(
parent
,
parent_op
,
leaf
,
leaf_op
,
sibling
,
sibling_op
);
delete_op
->
SetNewChild
(
new_leaf
);
// Execute operation
deletion_succeeded
=
delete_op
->
Help
(
GetNodeGuard
(
HIDX_HELPING
),
GetOperationGuard
(
HIDX_HELPING
));
delete_op
->
CleanUp
();
// If operation failed
if
(
!
deletion_succeeded
)
{
// Retire failed operation
RetireOperation
(
delete_op
);
// Delete new nodes
FreeNode
(
new_leaf
);
// Restart from scratch
continue
;
}
RetireHazardousNode
(
parent
,
parent_lock
);
RetireHazardousNode
(
leaf
,
leaf_lock
);
RetireHazardousNode
(
sibling
,
sibling_lock
);
// Retire old operation objects
RetireOperation
(
grandparent_op
);
RetireOperation
(
parent_op
);
RetireOperation
(
leaf_op
);
RetireOperation
(
sibling_op
);
// Retire old nodes
RetireNode
(
parent
);
RetireNode
(
leaf
);
RetireNode
(
sibling
);
added_violation
=
(
new_weight
>
1
);
}
...
...
@@ -373,46 +442,37 @@ IsEmpty() const {
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
)
{
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
,
HazardNodePtr
&
grandparent
)
{
bool
reached_leaf
=
false
;
while
(
!
reached_leaf
)
{
grandparent
.
ProtectSafe
(
entry_
);
parent
.
ProtectSafe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
leaf
.
ProtectSafe
(
entry_
);
reached_leaf
=
IsLeaf
(
leaf
);
while
(
!
reached_leaf
)
{
parent
.
AdoptGuard
(
leaf
);
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
*>
(
leaf
));
grandparent
.
AdoptHazard
(
parent
);
parent
.
AdoptHazard
(
leaf
);
reached_leaf
=
IsLeaf
(
leaf
);
}
}
}
AtomicNodePtr
&
next_leaf
=
(
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
();
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
,
HazardNodePtr
&
grandparent
)
{
bool
reached_leaf
=
false
;
// Parent is protected, so we can tolerate a changing child pointer
while
(
!
leaf
.
ProtectHazard
(
next_leaf
));
while
(
!
reached_leaf
)
{
grandparent
.
ProtectSafe
(
entry_
);
parent
.
ProtectSafe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
// Parent is retired - make sure it is actually removed from the tree
if
(
parent
->
IsRetired
())
{
HazardOperationPtr
op
(
GetOperationGuard
(
HIDX_HELPING
));
if
(
op
.
ProtectHazard
(
parent
->
GetOperation
()))
{
op
->
HelpCommit
(
GetNodeGuard
(
HIDX_HELPING
));
}
// Can't follow a child pointer in a retired node - restart from root
break
;
}
reached_leaf
=
IsLeaf
(
leaf
);
while
(
!
reached_leaf
)
{
grandparent
.
AdoptGuard
(
parent
);
parent
.
AdoptGuard
(
leaf
);
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
*>
(
leaf
));
reached_leaf
=
IsLeaf
(
leaf
);
...
...
@@ -490,69 +550,127 @@ IsBalanced(const Node* node) const {
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
)
{
node
->
Retire
();
node_lock
.
Unlock
();
Node
*
node_to_delete
=
node
.
ReleaseHazard
();
node_hazard_manager_
.
EnqueuePointerForDeletion
(
node_to_delete
);
RetireNode
(
HazardNodePtr
&
node
)
{
node_hazard_manager_
.
EnqueuePointerForDeletion
(
node
.
ReleaseHazard
());
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
FreeNode
(
Node
*
node
)
{
#ifdef EMBB_DEBUG
node
->
GetLeft
()
=
reinterpret_cast
<
Node
*>
(
INVALID_POINTER
);
node
->
GetRight
()
=
reinterpret_cast
<
Node
*>
(
INVALID_POINTER
);
#endif
node_pool_
.
Free
(
node
);
RetireOperation
(
HazardOperationPtr
&
operation
)
{
Operation
*
op
=
operation
.
ReleaseHazard
();
if
(
op
!=
Operation
::
INITIAL_DUMMY
&&
op
!=
Operation
::
RETIRED_DUMMY
)
{
operation_hazard_manager_
.
EnqueuePointerForDeletion
(
op
);
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
CleanUp
(
const
Key
&
key
)
{
HazardNodePtr
grandgrandparent
(
node_hazard_manager_
.
GetGuardedPointer
(
0
));
HazardNodePtr
grandparent
(
node_hazard_manager_
.
GetGuardedPointer
(
1
));
HazardNodePtr
parent
(
node_hazard_manager_
.
GetGuardedPointer
(
2
));
HazardNodePtr
leaf
(
node_hazard_manager_
.
GetGuardedPointer
(
3
));
bool
reached_leaf
=
false
;
typename
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
AtomicNodePtr
&
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
GetNodeGuard
(
HazardIndex
index
)
{
return
node_hazard_manager_
.
GetGuardedPointer
(
static_cast
<
int
>
(
index
));
}
while
(
!
reached_leaf
)
{
bool
found_violation
=
false
;
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
typename
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
AtomicOperationPtr
&
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
GetOperationGuard
(
HazardIndex
index
)
{
return
operation_hazard_manager_
.
GetGuardedPointer
(
static_cast
<
int
>
(
index
));
}
grandgrandparent
.
ProtectSafe
(
entry_
);
grandparent
.
ProtectSafe
(
entry_
);
parent
.
ProtectSafe
(
entry_
);
leaf
.
ProtectHazard
(
entry_
->
GetLeft
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
continue
;
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
WeakLLX
(
HazardNodePtr
&
node
,
HazardOperationPtr
&
operation
)
{
// Make sure we have a protected operation pointer
while
(
!
operation
.
ProtectHazard
(
node
->
GetOperation
()))
;
reached_leaf
=
IsLeaf
(
leaf
);
while
(
!
reached_leaf
&&
!
found_violation
)
{
grandgrandparent
.
AdoptGuard
(
grandparent
);
grandparent
.
AdoptGuard
(
parent
);
parent
.
AdoptGuard
(
leaf
);
leaf
.
ProtectHazard
((
IsSentinel
(
leaf
)
||
compare_
(
key
,
leaf
->
GetKey
()))
?
leaf
->
GetLeft
()
:
leaf
->
GetRight
());
if
(
parent
->
IsRetired
()
||
!
leaf
.
IsActive
())
break
;
VERIFY_ADDRESS
(
static_cast
<
Node
*>
(
leaf
));
// Node is not retired and operation is committed - node is available
if
(
!
node
->
IsRetired
()
&&
operation
->
IsCommitted
())
{
return
true
;
}
found_violation
=
(
leaf
->
GetWeight
()
>
1
)
||
(
leaf
->
GetWeight
()
==
0
&&
parent
->
GetWeight
()
==
0
);
if
(
operation
->
IsAborted
())
{
// Operation is aborted, but the node is still frozen - unfreeze it
operation
->
HelpAbort
(
node
);
reached_leaf
=
IsLeaf
(
leaf
);
}
else
if
(
operation
->
IsInProgress
())
{
// Operation is still in progress - help it
operation
->
Help
(
GetNodeGuard
(
HIDX_HELPING
),
GetOperationGuard
(
HIDX_HELPING
));
}
if
(
found_violation
)
{
reached_leaf
=
false
;
// LLX failed - operation pointer should not be exposed
operation
.
ReleaseHazard
()
;
if
(
Rebalance
(
grandgrandparent
,
grandparent
,
parent
,
leaf
)
==
EMBB_NOMEM
)
{
assert
(
false
&&
"No memory for rebalancing!"
);
return
false
;
}
}
}
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
FreeNode
(
Node
*
node
)
{
#ifdef EMBB_DEBUG
node
->
GetLeft
()
=
reinterpret_cast
<
Node
*>
(
INVALID_POINTER
);
node
->
GetRight
()
=
reinterpret_cast
<
Node
*>
(
INVALID_POINTER
);
#endif
node_pool_
.
Free
(
node
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
FreeOperation
(
Operation
*
operation
)
{
#ifdef EMBB_DEBUG
operation
->
SetDeleted
();
#endif
operation_pool_
.
Free
(
operation
);
}
template
<
typename
Key
,
typename
Value
,
typename
Compare
,
typename
ValuePool
>
bool
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
CleanUp
(
const
Key
&
key
)
{
(
void
)(
key
);
return
true
;
// HazardNodePtr grandgrandparent(node_hazard_manager_.GetGuardedPointer(0));
// HazardNodePtr grandparent (node_hazard_manager_.GetGuardedPointer(1));
// HazardNodePtr parent (node_hazard_manager_.GetGuardedPointer(2));
// HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(3));
// bool reached_leaf = false;
//
// while (!reached_leaf) {
// bool found_violation = false;
//
// grandgrandparent.ProtectSafe(entry_);
// grandparent.ProtectSafe(entry_);
// parent.ProtectSafe(entry_);
// leaf.ProtectHazard(entry_->GetLeft());
// if (parent->IsRetired() || !leaf.IsActive()) continue;
//
// reached_leaf = IsLeaf(leaf);
// while (!reached_leaf && !found_violation) {
// grandgrandparent.AdoptGuard(grandparent);
// grandparent.AdoptGuard(parent);
// parent.AdoptGuard(leaf);
// leaf.ProtectHazard((IsSentinel(leaf) || compare_(key, leaf->GetKey())) ?
// leaf->GetLeft() : leaf->GetRight());
// if (parent->IsRetired() || !leaf.IsActive()) break;
// VERIFY_ADDRESS(static_cast<Node*>(leaf));
//
// found_violation = (leaf->GetWeight() > 1) ||
// (leaf->GetWeight() == 0 && parent->GetWeight() == 0);
//
// reached_leaf = IsLeaf(leaf);
// }
//
// if (found_violation) {
// reached_leaf = false;
//
// if (Rebalance(grandgrandparent, grandparent, parent, leaf) ==
// EMBB_NOMEM) {
// assert(false && "No memory for rebalancing!");
// return false;
// }
// }
// }
//
// return true;
}
#define PROTECT_NODE_WITH_LOCK(node, lock_name) \
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/internal/object_pool-inl.h
View file @
34f6e4f3
...
...
@@ -201,6 +201,20 @@ Type* ObjectPool<Type, ValuePool, ObjectAllocator>::Allocate(
}
template
<
class
Type
,
typename
ValuePool
,
class
ObjectAllocator
>
template
<
typename
Param1
,
typename
Param2
,
typename
Param3
,
typename
Param4
,
typename
Param5
,
typename
Param6
>
Type
*
ObjectPool
<
Type
,
ValuePool
,
ObjectAllocator
>::
Allocate
(
Param1
const
&
param1
,
Param2
const
&
param2
,
Param3
const
&
param3
,
Param4
const
&
param4
,
Param5
const
&
param5
,
Param6
const
&
param6
)
{
Type
*
rawObject
=
AllocateRaw
();
if
(
rawObject
!=
NULL
)
new
(
rawObject
)
Type
(
param1
,
param2
,
param3
,
param4
,
param5
,
param6
);
return
rawObject
;
}
template
<
class
Type
,
typename
ValuePool
,
class
ObjectAllocator
>
ObjectPool
<
Type
,
ValuePool
,
ObjectAllocator
>::~
ObjectPool
()
{
// Deallocate the objects
objectAllocator
.
deallocate
(
objects
,
capacity
);
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
View file @
34f6e4f3
...
...
@@ -38,6 +38,9 @@ namespace embb {
namespace
containers
{
namespace
internal
{
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeOperation
;
/**
* Tree node
*
...
...
@@ -50,8 +53,10 @@ namespace internal {
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeNode
{
public
:
typedef
ChromaticTreeNode
<
Key
,
Value
>
Node
;
typedef
ChromaticTreeNode
Node
;
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
typedef
ChromaticTreeOperation
<
Key
,
Value
>
Operation
;
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
/**
* Creates a node with given parameters.
...
...
@@ -63,17 +68,17 @@ class ChromaticTreeNode {
* \param[IN] right Pointer to the right child node
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Node
*
left
,
Node
*
right
);
Node
*
left
,
Node
*
right
,
Operation
*
operation
);
/**
* Creates a node given only a key-value pair. Node will have no child nodes
* and a default weight (1).
* Creates a node with given parameters and no child nodes.
*
* \param[IN] key Key of the new node
* \param[IN] value Value of the new node
* \param[IN] weight Weight of the new node
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
=
1
);
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Operation
*
operation
);
/**
* Accessor for the stored key.
...
...
@@ -139,13 +144,17 @@ class ChromaticTreeNode {
bool
IsRetired
()
const
;
/**
* Accessor for the
FGL mutex
* Accessor for the
operation pointer of the node
*
* \return Reference to this node's
mutex
* \return Reference to this node's
operation pointer
*/
embb
::
base
::
Mutex
&
GetMutex
();
AtomicOperationPtr
&
GetOperation
()
{
return
operation_
;
}
private
:
typedef
embb
::
base
::
Atomic
<
bool
>
AtomicFlag
;
/**
* Disable copy construction and assignment.
*/
...
...
@@ -157,11 +166,306 @@ class ChromaticTreeNode {
const
int
weight_
;
/**< Weight of the node */
AtomicNodePtr
left_
;
/**< Pointer to left child node */
AtomicNodePtr
right_
;
/**< Pointer to right child node */
embb
::
base
::
Atomic
<
bool
>
retired_
;
/**< Retired (marked for deletion) flag */
AtomicFlag
retired_
;
/**< Retired (marked for deletion) flag */
AtomicOperationPtr
operation_
;
/**< Pointer to a tree operation object */
};
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeOperation
{
public
:
typedef
ChromaticTreeNode
<
Key
,
Value
>
Node
;
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
typedef
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
typedef
ChromaticTreeOperation
Operation
;
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
typedef
UniqueHazardPointer
<
Operation
>
HazardOperationPtr
;
static
Operation
*
const
INITIAL_DUMMY
;
static
Operation
*
const
RETIRED_DUMMY
;
ChromaticTreeOperation
()
:
state_
(
STATE_FREEZING
),
root_
(
NULL
),
root_operation_
(
NULL
),
num_old_nodes_
(
0
),
old_nodes_
(),
old_operations_
(),
new_child_
(
NULL
)
#ifdef EMBB_DEBUG
,
deleted_
(
false
)
#endif
{}
void
SetRoot
(
Node
*
root
,
Operation
*
root_operation
)
{
root_
=
root
;
root_operation_
=
root_operation
;
}
void
SetOldNodes
(
Node
*
node
,
Operation
*
operation
)
{
num_old_nodes_
=
1
;
old_nodes_
[
0
]
=
node
;
old_operations_
[
0
]
=
operation
;
}
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
,
Node
*
node3
,
Operation
*
operation3
)
{
num_old_nodes_
=
3
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
old_nodes_
[
2
]
=
node3
;
old_operations_
[
2
]
=
operation3
;
}
void
SetNewChild
(
Node
*
new_child
)
{
new_child_
=
new_child
;
}
bool
Help
(
AtomicNodePtr
&
node_guard
,
AtomicOperationPtr
&
oper_guard
)
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
// Freezing step
if
(
!
FreezeAll
(
node_guard
,
oper_guard
))
{
return
IsCommitted
();
}
// All frozen step
if
(
!
SwitchState
(
STATE_FREEZING
,
STATE_ALL_FROZEN
))
{
return
IsCommitted
();
}
// At this point operation may no longer fail - complete it
HelpCommit
(
node_guard
);
return
true
;
}
void
HelpCommit
(
AtomicNodePtr
&
node_guard
)
{
HazardNodePtr
node_hp
(
node_guard
);
// Mark step (retire old nodes)
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
node_hp
.
ProtectSafe
(
old_nodes_
[
i
]);
if
(
IsCommitted
())
return
;
old_nodes_
[
i
]
->
Retire
();
}
// Update step
node_hp
.
ProtectSafe
(
root_
);
if
(
IsCommitted
())
return
;
root_
->
ReplaceChild
(
old_nodes_
[
0
],
new_child_
);
// Commit step
SwitchState
(
STATE_ALL_FROZEN
,
STATE_COMMITTED
);
}
void
HelpAbort
(
Node
*
node
)
{
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
if
(
old_nodes_
[
i
]
==
node
)
{
Unfreeze
(
old_nodes_
[
i
],
old_operations_
[
i
]);
break
;
}
}
}
bool
IsAborted
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
return
state_
==
STATE_ABORTED
;
}
bool
IsInProgress
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
State
state
=
state_
.
Load
();
return
(
state
!=
STATE_ABORTED
&&
state
!=
STATE_COMMITTED
);
}
bool
IsCommitted
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
return
state_
==
STATE_COMMITTED
;
}
void
CleanUp
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
assert
(
!
IsInProgress
());
if
(
IsCommitted
())
{
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
assert
(
old_nodes_
[
i
]
->
GetOperation
()
==
this
);
old_nodes_
[
i
]
->
GetOperation
()
=
RETIRED_DUMMY
;
}
}
}
#ifdef EMBB_DEBUG
void
SetDeleted
()
{
deleted_
=
true
;
}
#endif
private
:
typedef
enum
{
STATE_ABORTED
,
STATE_ROLLBACK
,
STATE_FREEZING
,
STATE_ALL_FROZEN
,
STATE_COMMITTED
}
State
;
typedef
embb
::
base
::
Atomic
<
State
>
AtomicState
;
static
const
size_t
MAX_NODES
=
5
;
static
Operation
*
GetInitialDummmy
()
{
static
ChromaticTreeOperation
initial_dummy
;
initial_dummy
.
state_
=
STATE_COMMITTED
;
return
&
initial_dummy
;
}
static
Operation
*
GetRetiredDummmy
()
{
static
ChromaticTreeOperation
retired_dummy
;
retired_dummy
.
state_
=
STATE_COMMITTED
;
return
&
retired_dummy
;
}
bool
IsRollingBack
()
{
State
state
=
state_
.
Load
();
return
(
state
==
STATE_ROLLBACK
||
state
==
STATE_ABORTED
);
}
bool
IsFreezing
()
{
return
state_
==
STATE_FREEZING
;
}
bool
IsAllFrozen
()
{
State
state
=
state_
.
Load
();
return
(
state
==
STATE_ALL_FROZEN
||
state
==
STATE_COMMITTED
);
}
bool
FreezeAll
(
AtomicNodePtr
&
node_guard
,
AtomicOperationPtr
&
oper_guard
)
{
if
(
IsFreezing
())
{
HazardNodePtr
node_hp
(
node_guard
);
HazardOperationPtr
oper_hp
(
oper_guard
);
node_hp
.
ProtectSafe
(
root_
);
oper_hp
.
ProtectSafe
(
root_operation_
);
if
(
IsFreezing
())
{
Freeze
(
root_
,
root_operation_
);
}
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
node_hp
.
ProtectSafe
(
old_nodes_
[
i
]);
oper_hp
.
ProtectSafe
(
old_operations_
[
i
]);
if
(
!
IsFreezing
())
break
;
Freeze
(
old_nodes_
[
i
],
old_operations_
[
i
]);
}
}
if
(
IsRollingBack
())
{
UnfreezeAll
(
node_guard
);
return
false
;
}
return
true
;
}
bool
Freeze
(
Node
*
node
,
Operation
*
operation
)
{
bool
freezed
=
node
->
GetOperation
().
CompareAndSwap
(
operation
,
this
);
if
(
!
freezed
&&
operation
!=
this
&&
!
IsAllFrozen
())
{
// Node is frozen for another operation - abort "this"
SwitchState
(
STATE_FREEZING
,
STATE_ROLLBACK
);
// If the "operation" was aborted and rolled back, some other thread could
// have helped "this" to freeze all nodes, and the previous "SwitchState"
// would fail
return
IsAllFrozen
();
}
if
(
freezed
&&
IsRollingBack
())
{
// "False-positive" CAS: "this" was aborted and the "operation" might have
// been rolled back; While "node" is hazard protected, unfreeze it again
Unfreeze
(
node
,
operation
);
return
false
;
}
return
true
;
}
void
UnfreezeAll
(
AtomicNodePtr
&
node_guard
)
{
HazardNodePtr
node_hp
(
node_guard
);
node_hp
.
ProtectSafe
(
root_
);
if
(
IsAborted
())
return
;
Unfreeze
(
root_
,
root_operation_
);
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
node_hp
.
ProtectSafe
(
old_nodes_
[
i
]);
if
(
IsAborted
())
return
;
Unfreeze
(
old_nodes_
[
i
],
old_operations_
[
i
]);
}
SwitchState
(
STATE_ROLLBACK
,
STATE_ABORTED
);
}
embb
::
base
::
Mutex
mutex_
;
/**< Fine-grained locking tree: per node mutex */
void
Unfreeze
(
Node
*
node
,
Operation
*
operation
)
{
Operation
*
expected
=
this
;
node
->
GetOperation
().
CompareAndSwap
(
expected
,
operation
);
}
bool
SwitchState
(
State
old_state
,
State
new_state
)
{
if
(
state_
!=
new_state
)
{
bool
switched
=
state_
.
CompareAndSwap
(
old_state
,
new_state
);
if
(
!
switched
&&
old_state
!=
new_state
)
{
return
false
;
}
}
return
true
;
}
ChromaticTreeOperation
(
const
ChromaticTreeOperation
&
);
ChromaticTreeOperation
&
operator
=
(
const
ChromaticTreeOperation
&
);
AtomicState
state_
;
Node
*
root_
;
Operation
*
root_operation_
;
size_t
num_old_nodes_
;
Node
*
old_nodes_
[
MAX_NODES
];
Operation
*
old_operations_
[
MAX_NODES
];
Node
*
new_child_
;
#ifdef EMBB_DEBUG
embb
::
base
::
Atomic
<
bool
>
deleted_
;
#endif
};
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeOperation
<
Key
,
Value
>::
Operation
*
const
ChromaticTreeOperation
<
Key
,
Value
>::
INITIAL_DUMMY
=
ChromaticTreeOperation
::
GetInitialDummmy
();
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeOperation
<
Key
,
Value
>::
Operation
*
const
ChromaticTreeOperation
<
Key
,
Value
>::
RETIRED_DUMMY
=
ChromaticTreeOperation
::
GetRetiredDummmy
();
}
// namespace internal
namespace
test
{
...
...
@@ -329,22 +633,28 @@ class ChromaticTree {
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
/** Typedef for an pointer to a node protected by a Hazard Pointer. */
typedef
internal
::
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
/** Typedef for the chromatic tree operation. */
typedef
internal
::
ChromaticTreeOperation
<
Key
,
Value
>
Operation
;
/** Typedef for an atomic pointer to a tree operation. */
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
/** Typedef for an pointer to a node protected by a Hazard Pointer. */
typedef
internal
::
UniqueHazardPointer
<
Operation
>
HazardOperationPtr
;
/** Typedef for the UniqueLock class. */
typedef
embb
::
base
::
UniqueLock
<
embb
::
base
::
Mutex
>
UniqueLock
;
/** Typedef for an object pool for tree nodes. */
typedef
ObjectPool
<
Node
,
ValuePool
>
NodePool
;
/** Typedef for an object pool for tree operations. */
typedef
ObjectPool
<
Operation
,
ValuePool
>
OperationPool
;
/**
* Follows a path from the root of the tree to some leaf searching for the
* given key (the leaf found by this method may or may not contain the given
* key). Returns the reached leaf together with its ancestors.
*
* \param[IN] key Key to be searched for
* \param[IN,OUT] leaf Reference to the reached leaf
* \param[IN,OUT] parent Reference to the parent of the reached leaf
*/
void
Search
(
const
Key
&
key
,
HazardNodePtr
&
leaf
,
HazardNodePtr
&
parent
);
typedef
enum
{
HIDX_HELPING
=
0
,
HIDX_LEAF
,
HIDX_PARENT
,
HIDX_GRANDPARENT
,
HIDX_SIBLING
,
HIDX_CURRENT_OP
,
HIDX_MAX
}
HazardIndex
;
/**
* Follows a path from the root of the tree to some leaf searching for the
...
...
@@ -427,13 +737,15 @@ class ChromaticTree {
*/
bool
IsBalanced
(
const
Node
*
node
)
const
;
/**
* Free a tree node using the Hazard Pointers memory reclamation routines.
*
* \param[IN] node A node to be freed.
* \param[IN] node_lock A lock holding the mutex of the \c node to be freed.
*/
void
RetireHazardousNode
(
HazardNodePtr
&
node
,
UniqueLock
&
node_lock
);
void
RetireNode
(
HazardNodePtr
&
node
);
void
RetireOperation
(
HazardOperationPtr
&
operation
);
AtomicNodePtr
&
GetNodeGuard
(
HazardIndex
index
);
AtomicOperationPtr
&
GetOperationGuard
(
HazardIndex
index
);
bool
WeakLLX
(
HazardNodePtr
&
node
,
HazardOperationPtr
&
operation
);
/**
* Free a tree node by returning it to the node pool.
...
...
@@ -442,6 +754,8 @@ class ChromaticTree {
*/
void
FreeNode
(
Node
*
node
);
void
FreeOperation
(
Operation
*
operation
);
/**
* Follows the path from the root to some leaf (directed by the given key) and
* checks for any tree balancing violations. If a violation is found, tries
...
...
@@ -480,12 +794,14 @@ class ChromaticTree {
/** Hazard pointer instance for protection of node pointers */
internal
::
HazardPointer
<
Node
*>
node_hazard_manager_
;
internal
::
HazardPointer
<
Operation
*>
operation_hazard_manager_
;
const
Key
undefined_key_
;
/**< A dummy key used by the tree */
const
Value
undefined_value_
;
/**< A dummy value used by the tree */
const
Compare
compare_
;
/**< Comparator object for the keys */
size_t
capacity_
;
/**< User-requested capacity of the tree */
NodePool
node_pool_
;
/**< Comparator object for the keys */
NodePool
node_pool_
;
/**< Pool of tree nodes */
OperationPool
operation_pool_
;
/**< Pool of operation objects */
Node
*
const
entry_
;
/**< Pointer to the sentinel node used as
* the entry point into the tree */
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/include/embb/containers/object_pool.h
View file @
34f6e4f3
...
...
@@ -185,6 +185,12 @@ class ObjectPool {
Type
*
Allocate
(
Param1
const
&
param1
,
Param2
const
&
param2
,
Param3
const
&
param3
,
Param4
const
&
param4
,
Param5
const
&
param5
);
template
<
typename
Param1
,
typename
Param2
,
typename
Param3
,
typename
Param4
,
typename
Param5
,
typename
Param6
>
Type
*
Allocate
(
Param1
const
&
param1
,
Param2
const
&
param2
,
Param3
const
&
param3
,
Param4
const
&
param4
,
Param5
const
&
param5
,
Param6
const
&
param6
);
#endif
};
}
// namespace containers
...
...
This diff is collapsed.
Click to expand it.
containers_cpp/test/tree_test-inl.h
View file @
34f6e4f3
...
...
@@ -66,11 +66,11 @@ TreeTest<Tree>::TreeTest()
Add
(
&
TreeTest
::
TreeTestConcurrentGet_ReaderMethod
,
this
,
NUM_TEST_THREADS
/
2
,
NUM_ITERATIONS
).
Post
(
&
TreeTest
::
TreeTestConcurrentGet_Post
,
this
);
CreateUnit
(
"TreeTestBalance"
).
Pre
(
&
TreeTest
::
TreeTestBalance_Pre
,
this
).
Add
(
&
TreeTest
::
TreeTestBalance_ThreadMethod
,
this
,
NUM_TEST_THREADS
,
1
).
Post
(
&
TreeTest
::
TreeTestBalance_Post
,
this
);
//
CreateUnit("TreeTestBalance").
//
Pre(&TreeTest::TreeTestBalance_Pre, this).
//
Add(&TreeTest::TreeTestBalance_ThreadMethod, this,
//
NUM_TEST_THREADS, 1).
//
Post(&TreeTest::TreeTestBalance_Post, this);
}
template
<
typename
Tree
>
...
...
This diff is collapsed.
Click to expand it.
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