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
a585b9c7
authored
Jun 16, 2015
by
Danila Klimenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added documentation and split the Operation class into declaration/definition.
parent
35ab98de
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
670 additions
and
309 deletions
+670
-309
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
+354
-0
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
+316
-309
No files found.
containers_cpp/include/embb/containers/internal/lock_free_chromatic_tree-inl.h
View file @
a585b9c7
...
...
@@ -129,6 +129,359 @@ bool ChromaticTreeNode<Key, Value>::IsRetired() const {
return
retired_
;
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeNode
<
Key
,
Value
>::
AtomicOperationPtr
&
ChromaticTreeNode
<
Key
,
Value
>::
GetOperation
()
{
return
operation_
;
}
template
<
typename
Key
,
typename
Value
>
ChromaticTreeOperation
<
Key
,
Value
>::
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
{}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetRoot
(
Node
*
root
,
Operation
*
root_operation
)
{
root_
=
root
;
root_operation_
=
root_operation
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
)
{
num_old_nodes_
=
1
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
)
{
num_old_nodes_
=
2
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
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
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
,
Node
*
node3
,
Operation
*
operation3
,
Node
*
node4
,
Operation
*
operation4
)
{
num_old_nodes_
=
4
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
old_nodes_
[
2
]
=
node3
;
old_operations_
[
2
]
=
operation3
;
old_nodes_
[
3
]
=
node4
;
old_operations_
[
3
]
=
operation4
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
,
Node
*
node3
,
Operation
*
operation3
,
Node
*
node4
,
Operation
*
operation4
,
Node
*
node5
,
Operation
*
operation5
)
{
num_old_nodes_
=
5
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
old_nodes_
[
2
]
=
node3
;
old_operations_
[
2
]
=
operation3
;
old_nodes_
[
3
]
=
node4
;
old_operations_
[
3
]
=
operation4
;
old_nodes_
[
4
]
=
node5
;
old_operations_
[
4
]
=
operation5
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetNewChild
(
Node
*
new_child
)
{
new_child_
=
new_child
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
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
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
HelpCommit
(
AtomicNodePtr
&
node_guard
)
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
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
);
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
HelpAbort
(
Node
*
node
)
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
if
(
old_nodes_
[
i
]
==
node
)
{
Unfreeze
(
old_nodes_
[
i
],
old_operations_
[
i
]);
break
;
}
}
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsAborted
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
return
state_
==
STATE_ABORTED
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsInProgress
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
State
state
=
state_
.
Load
();
return
(
state
!=
STATE_ABORTED
&&
state
!=
STATE_COMMITTED
);
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsCommitted
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
return
state_
==
STATE_COMMITTED
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
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
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
SetDeleted
()
{
deleted_
=
true
;
}
#endif
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeOperation
<
Key
,
Value
>::
Operation
*
ChromaticTreeOperation
<
Key
,
Value
>::
GetInitialDummmy
()
{
static
ChromaticTreeOperation
initial_dummy
;
initial_dummy
.
state_
=
STATE_COMMITTED
;
return
&
initial_dummy
;
}
template
<
typename
Key
,
typename
Value
>
typename
ChromaticTreeOperation
<
Key
,
Value
>::
Operation
*
ChromaticTreeOperation
<
Key
,
Value
>::
GetRetiredDummmy
()
{
static
ChromaticTreeOperation
retired_dummy
;
retired_dummy
.
state_
=
STATE_COMMITTED
;
return
&
retired_dummy
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsRollingBack
()
{
State
state
=
state_
.
Load
();
return
(
state
==
STATE_ROLLBACK
||
state
==
STATE_ABORTED
);
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsFreezing
()
{
return
state_
==
STATE_FREEZING
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
IsAllFrozen
()
{
State
state
=
state_
.
Load
();
return
(
state
==
STATE_ALL_FROZEN
||
state
==
STATE_COMMITTED
);
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
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
;
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
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
;
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
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
);
}
template
<
typename
Key
,
typename
Value
>
void
ChromaticTreeOperation
<
Key
,
Value
>::
Unfreeze
(
Node
*
node
,
Operation
*
operation
)
{
Operation
*
expected
=
this
;
node
->
GetOperation
().
CompareAndSwap
(
expected
,
operation
);
}
template
<
typename
Key
,
typename
Value
>
bool
ChromaticTreeOperation
<
Key
,
Value
>::
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
;
}
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
...
...
@@ -558,6 +911,7 @@ template<typename Key, typename Value, typename Compare, typename ValuePool>
void
ChromaticTree
<
Key
,
Value
,
Compare
,
ValuePool
>::
RetireOperation
(
HazardOperationPtr
&
operation
)
{
Operation
*
op
=
operation
.
ReleaseHazard
();
// Make sure we don't return the static dummy-operations to the pool
if
(
op
!=
Operation
::
INITIAL_DUMMY
&&
op
!=
Operation
::
RETIRED_DUMMY
)
{
operation_hazard_manager_
.
EnqueuePointerForDeletion
(
op
);
}
...
...
containers_cpp/include/embb/containers/lock_free_chromatic_tree.h
View file @
a585b9c7
...
...
@@ -42,7 +42,7 @@ template<typename Key, typename Value>
class
ChromaticTreeOperation
;
/**
*
Tree node
*
Chromatic tree node.
*
* Stores the key-value pair, as well as the weight value (used for rebalancing)
* and two pointers to child nodes (left and right).
...
...
@@ -53,19 +53,24 @@ class ChromaticTreeOperation;
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeNode
{
public
:
/** Node of the tree (self type). */
typedef
ChromaticTreeNode
Node
;
/** Atomic pointer to a node. */
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
/** Chromatic tree operation. */
typedef
ChromaticTreeOperation
<
Key
,
Value
>
Operation
;
/** Atomic pointer to a tree operation. */
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
/**
* Creates a node with given parameters.
*
* \param[IN] key Key of the new node
* \param[IN] value Value of the new node
* \param[IN] weight Weight of the new node
* \param[IN] left Pointer to the left child node
* \param[IN] right Pointer to the right child node
* \param[IN] key Key of the new node
* \param[IN] value Value of the new node
* \param[IN] weight Weight of the new node
* \param[IN] left Pointer to the left child node
* \param[IN] right Pointer to the right child node
* \param[IN] operation Pointer to an operation object
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Node
*
left
,
Node
*
right
,
Operation
*
operation
);
...
...
@@ -73,9 +78,10 @@ class ChromaticTreeNode {
/**
* 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
* \param[IN] key Key of the new node
* \param[IN] value Value of the new node
* \param[IN] weight Weight of the new node
* \param[IN] operation Pointer to an operation object
*/
ChromaticTreeNode
(
const
Key
&
key
,
const
Value
&
value
,
int
weight
,
Operation
*
operation
);
...
...
@@ -137,22 +143,21 @@ class ChromaticTreeNode {
void
Retire
();
/**
* Checks whether the node is marked for deletion from the tree
* Checks whether the node is marked for deletion from the tree
.
*
* \return \c true if node is retired, \c false otherwise
*/
bool
IsRetired
()
const
;
/**
* Accessor for the operation pointer of the node
* Accessor for the operation pointer of the node
.
*
* \return Reference to this node's operation pointer
*/
AtomicOperationPtr
&
GetOperation
()
{
return
operation_
;
}
AtomicOperationPtr
&
GetOperation
();
private
:
/** Atomic boolean flag. */
typedef
embb
::
base
::
Atomic
<
bool
>
AtomicFlag
;
/**
...
...
@@ -161,201 +166,167 @@ class ChromaticTreeNode {
ChromaticTreeNode
(
const
ChromaticTreeNode
&
);
ChromaticTreeNode
&
operator
=
(
const
ChromaticTreeNode
&
);
const
Key
key_
;
/**< Stored key */
const
Value
value_
;
/**< Stored value */
const
int
weight_
;
/**< Weight of the node */
AtomicNodePtr
left_
;
/**< Pointer to left child node */
AtomicNodePtr
right_
;
/**< Pointer to right child node */
AtomicFlag
retired_
;
/**< Retired (marked for deletion) flag */
AtomicOperationPtr
operation_
;
/**< Pointer to a tree operation object */
const
Key
key_
;
/**< Stored key
.
*/
const
Value
value_
;
/**< Stored value
.
*/
const
int
weight_
;
/**< Weight of the node
.
*/
AtomicNodePtr
left_
;
/**< Pointer to left child node
.
*/
AtomicNodePtr
right_
;
/**< Pointer to right child node
.
*/
AtomicFlag
retired_
;
/**< Retired (marked for deletion) flag
.
*/
AtomicOperationPtr
operation_
;
/**< Pointer to a tree operation object
.
*/
};
/**
* Tree operation
*
* Describes a chromatic tree operation (insertion, deletion or rotation).
* Contains pointers to the root node of the operation, nodes that are part of
* the operation window, and the newly created node to become a new child of the
* root node. For all existing nodes, the original operation pointers acquired
* through a previous WeakLLXs are stored. Methods for initialization, helping
* and status enquiries are provided.
*
* \tparam Key Key type
* \tparam Value Value type
*/
template
<
typename
Key
,
typename
Value
>
class
ChromaticTreeOperation
{
public
:
/** Node of the tree. */
typedef
ChromaticTreeNode
<
Key
,
Value
>
Node
;
/** Atomic pointer to a node. */
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
/** Hazard-protected pointer to a node. */
typedef
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
/** Chromatic tree operation (self type). */
typedef
ChromaticTreeOperation
Operation
;
/** Atomic pointer to a tree operation. */
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
/** Hazard-protected pointer to a tree operation. */
typedef
UniqueHazardPointer
<
Operation
>
HazardOperationPtr
;
/** Dummy operation used for newly created nodes. */
static
Operation
*
const
INITIAL_DUMMY
;
/** Dummy operation used for nodes removed from the tree after
* an operation commits. */
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
{}
/**
* Creates an empty operation object with an "in progress" state.
*/
ChromaticTreeOperation
();
void
SetRoot
(
Node
*
root
,
Operation
*
root_operation
)
{
root_
=
root
;
root_operation_
=
root_operation
;
}
/**
* Set the root node of this operation together with its original operation
* pointer.
*
* \param root The root node of the operation
* \param root_operation The original operation pointer of the root node
*/
void
SetRoot
(
Node
*
root
,
Operation
*
root_operation
);
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
)
{
num_old_nodes_
=
1
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
}
/**
* Sets the nodes of this operation window together with their original
* operation pointers.
*
* \param node1 The node from the operation window
* \param operation1 The original operation pointer of \c node1
*/
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
);
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
)
{
num_old_nodes_
=
2
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
}
Node
*
node2
,
Operation
*
operation2
);
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
;
}
Node
*
node3
,
Operation
*
operation3
);
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
,
Node
*
node3
,
Operation
*
operation3
,
Node
*
node4
,
Operation
*
operation4
)
{
num_old_nodes_
=
4
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
old_nodes_
[
2
]
=
node3
;
old_operations_
[
2
]
=
operation3
;
old_nodes_
[
3
]
=
node4
;
old_operations_
[
3
]
=
operation4
;
}
Node
*
node4
,
Operation
*
operation4
);
void
SetOldNodes
(
Node
*
node1
,
Operation
*
operation1
,
Node
*
node2
,
Operation
*
operation2
,
Node
*
node3
,
Operation
*
operation3
,
Node
*
node4
,
Operation
*
operation4
,
Node
*
node5
,
Operation
*
operation5
)
{
num_old_nodes_
=
5
;
old_nodes_
[
0
]
=
node1
;
old_operations_
[
0
]
=
operation1
;
old_nodes_
[
1
]
=
node2
;
old_operations_
[
1
]
=
operation2
;
old_nodes_
[
2
]
=
node3
;
old_operations_
[
2
]
=
operation3
;
old_nodes_
[
3
]
=
node4
;
old_operations_
[
3
]
=
operation4
;
old_nodes_
[
4
]
=
node5
;
old_operations_
[
4
]
=
operation5
;
}
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
;
}
Node
*
node5
,
Operation
*
operation5
);
bool
IsInProgress
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
State
state
=
state_
.
Load
();
return
(
state
!=
STATE_ABORTED
&&
state
!=
STATE_COMMITTED
);
}
/**
* Set the node that is to become the new child of the operation root.
*
* \param new_child Node to become the new child of the operation root
*/
void
SetNewChild
(
Node
*
new_child
);
bool
IsCommitted
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
return
state_
==
STATE_COMMITTED
;
}
/**
* Help execute the operation. First tries to freeze all the nodes in the
* operation window, and if succeeds - retires those nodes and injects the new
* window into the tree. If the freezing step fails, rolls back the operation
* by unfreezing all the nodes of the original window.
*
* \param node_guard Node hazard guard used to protect the helped nodes
* \param oper_guard Operation hazard guard to protect the original operation
* pointers of the helped nodes
*
* \return \c true is the operation successfully commits, \c false if it
* aborts
*/
bool
Help
(
AtomicNodePtr
&
node_guard
,
AtomicOperationPtr
&
oper_guard
);
void
CleanUp
()
{
#ifdef EMBB_DEBUG
assert
(
!
deleted_
);
#endif
assert
(
!
IsInProgress
());
/**
* Help an operation that has successfully frozen all the nodes in its window
* to complete. This operation may no longer fail or abort.
*
* \param node_guard Node hazard guard used to protect the helped nodes
*/
void
HelpCommit
(
AtomicNodePtr
&
node_guard
);
/**
* Help an aborted operation by unfreezing the given \c node.
*
* \param node The node to be unfrozen
*/
void
HelpAbort
(
Node
*
node
);
/**
* Check whether the operation is aborted.
*
* \return \c true if operation is aborted, \c false otherwise
*/
bool
IsAborted
();
if
(
IsCommitted
())
{
for
(
size_t
i
=
0
;
i
<
num_old_nodes_
;
++
i
)
{
assert
(
old_nodes_
[
i
]
->
GetOperation
()
==
this
);
old_nodes_
[
i
]
->
GetOperation
()
=
RETIRED_DUMMY
;
}
}
}
/**
* Check whether the operation is in progress.
*
* \return \c true if operation is in progress, \c false otherwise
*/
bool
IsInProgress
();
/**
* Check whether the operation is committed.
*
* \return \c true if operation is committed, \c false otherwise
*/
bool
IsCommitted
();
/**
* Performs the necessary post-processing steps for the operation, i.e. if the
* operation commits, resets all the operation pointers of the nodes of the
* removed operation window to point to the retired dummy-operation. Must be
* called only once after the operation either commits or aborts.
*/
void
CleanUp
();
#ifdef EMBB_DEBUG
void
SetDeleted
()
{
deleted_
=
true
;
}
/**
* Set the deleted flag for this operation. No other method of this operation
* is allowed to be called after this method returns.
*/
void
SetDeleted
();
#endif
private
:
/** Enumeration of possible operation states. */
typedef
enum
{
STATE_ABORTED
,
STATE_ROLLBACK
,
...
...
@@ -363,156 +334,143 @@ class ChromaticTreeOperation {
STATE_ALL_FROZEN
,
STATE_COMMITTED
}
State
;
/** Atomic wrapper for the operation state. */
typedef
embb
::
base
::
Atomic
<
State
>
AtomicState
;
/** Maximal possible number of nodes in an operation window. */
static
const
size_t
MAX_NODES
=
5
;
static
Operation
*
GetInitialDummmy
()
{
static
ChromaticTreeOperation
initial_dummy
;
/**
* Initializes and returns the initial dummy operation.
*
* \return Pointer to the INITIAL_DUMMY operation
*
* \see INITIAL_DUMMY
*/
static
Operation
*
GetInitialDummmy
();
initial_dummy
.
state_
=
STATE_COMMITTED
;
/**
* Initializes and returns the retired dummy operation.
*
* \return Pointer to the RETIRED_DUMMY operation
*
* \see RETIRED_DUMMY
*/
static
Operation
*
GetRetiredDummmy
();
return
&
initial_dummy
;
}
/**
* Check whether the operation is rolling back.
*
* \return \c true if operation is rolling back, \c false otherwise
*/
bool
IsRollingBack
();
static
Operation
*
GetRetiredDummmy
()
{
static
ChromaticTreeOperation
retired_dummy
;
/**
* Check whether the operation is freezing.
*
* \return \c true if operation is freezing, \c false otherwise
*/
bool
IsFreezing
();
retired_dummy
.
state_
=
STATE_COMMITTED
;
/**
* Check whether all the nodes from the operation window were successfully
* frozen for this operation.
*
* \return \c true if all nodes of the window were frozen, \c false otherwise
*/
bool
IsAllFrozen
();
return
&
retired_dummy
;
}
/**
* Tries to freeze all the nodes from the operation window for this operation.
* If the current operation encounters a conflict and fails, this method helps
* to roll back the operation by unfreezing all the nodes.
*
* \param node_guard Node hazard guard used to protect the freezing nodes
* \param oper_guard Operation hazard guard to protect the original operation
* pointers of the freezing nodes
*
* \return \c true if all nodes of this operation window were successfully
* frozen, \c false otherwise
*/
bool
FreezeAll
(
AtomicNodePtr
&
node_guard
,
AtomicOperationPtr
&
oper_guard
);
bool
IsRollingBack
()
{
State
state
=
state_
.
Load
();
return
(
state
==
STATE_ROLLBACK
||
state
==
STATE_ABORTED
);
}
/**
* Tries to freeze the given \c node for the current operation by using a CAS
* to set the node's operation pointer to point to this operation. If the CAS
* fails and the node is not frozen for this operation, tries to switch to the
* "rolling back" state.
*
* \param node The node to be frozen
* \param operation The original operation pointer of the \c node
*
* \return \c true if \c node was successfully frozen, \c false otherwise
*/
bool
Freeze
(
Node
*
node
,
Operation
*
operation
);
bool
IsFreezing
()
{
return
state_
==
STATE_FREEZING
;
}
/**
* Rolls back the current operation by unfreezing all the nodes of the
* operation window, i.e. changing the operation pointers of those nodes to
* their original values.
*
* \param node_guard Node hazard guard used to protect the nodes being
* unfrozen
*/
void
UnfreezeAll
(
AtomicNodePtr
&
node_guard
);
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
);
}
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
;
}
/**
* Unfreezes the given \c node by changing its operation pointer back to the
* original value.
*
* \param node The node to be unfrozen
* \param operation The original operation pointer of the \c node
*/
void
Unfreeze
(
Node
*
node
,
Operation
*
operation
);
/**
* Tries to switch from one operation state to another. If current state is
* already equal to \c new_state, returns \c true. Otherwise, tries to switch
* from \c old_state to \c new_state atomically using a CAS operation, and
* returns \c true if this CAS succeeds.
*
* \param old_state Currently expected state of the operation
* \param new_state New desired state of the operation
*
* \return \c true is state was successfully changed to \c new_state, \c false
* otherwise
*/
bool
SwitchState
(
State
old_state
,
State
new_state
);
/**
* Disable copy construction and assignment.
*/
ChromaticTreeOperation
(
const
ChromaticTreeOperation
&
);
ChromaticTreeOperation
&
operator
=
(
const
ChromaticTreeOperation
&
);
/** Current state of the operation. */
AtomicState
state_
;
/** Root node of the operation. */
Node
*
root_
;
/** Original operation pointer of the root node. */
Operation
*
root_operation_
;
/** Number of nodes in the operation window. */
size_t
num_old_nodes_
;
/** Nodes of the operation window. */
Node
*
old_nodes_
[
MAX_NODES
];
/** Original operation pointers for the nodes of the window. */
Operation
*
old_operations_
[
MAX_NODES
];
/** Pointer to the new node to become the new child of the root. */
Node
*
new_child_
;
#ifdef EMBB_DEBUG
/** Debug flag for memory management control (is set when node is deleted). */
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
{
/**
* Forward declaration of the test class
* Forward declaration of the test class
.
*/
template
<
typename
Tree
>
class
TreeTest
;
...
...
@@ -520,7 +478,7 @@ class TreeTest;
}
// namespace test
/**
* Chromatic balanced binary search tree
* Chromatic balanced binary search tree
.
*
* Implements a balanced BST with support for \c Get, \c Insert and \c Delete
* operations.
...
...
@@ -532,7 +490,7 @@ class TreeTest;
* arguments \c rhs and \c lhs of type \c Key and
* returning \c true if and only if <tt>(rhs < lhs)</tt> holds
* \tparam ValuePool Type of the value pool to be used inside object pools for
* tree nodes and operation objects
.
* tree nodes and operation objects
*/
template
<
typename
Key
,
typename
Value
,
...
...
@@ -542,11 +500,11 @@ template<typename Key,
class
ChromaticTree
{
public
:
/**
* Exposing the \c Key template parameter back to the user
* Exposing the \c Key template parameter back to the user
.
*/
typedef
Key
KeyType
;
/**
* Exposing the \c Value template parameter back to the user
* Exposing the \c Value template parameter back to the user
.
*/
typedef
Value
ValueType
;
...
...
@@ -669,32 +627,34 @@ class ChromaticTree {
bool
IsEmpty
()
const
;
private
:
/**
Typedef for a n
ode of the tree. */
/**
N
ode of the tree. */
typedef
internal
::
ChromaticTreeNode
<
Key
,
Value
>
Node
;
/**
Typedef for an atomic pointer to a node of the tre
e. */
/**
Atomic pointer to a nod
e. */
typedef
embb
::
base
::
Atomic
<
Node
*>
AtomicNodePtr
;
/**
Typedef for an pointer to a node protected by a Hazard Pointer
. */
/**
Hazard-protected pointer to a node
. */
typedef
internal
::
UniqueHazardPointer
<
Node
>
HazardNodePtr
;
/**
Typedef for the c
hromatic tree operation. */
/**
C
hromatic tree operation. */
typedef
internal
::
ChromaticTreeOperation
<
Key
,
Value
>
Operation
;
/**
Typedef for an a
tomic pointer to a tree operation. */
/**
A
tomic pointer to a tree operation. */
typedef
embb
::
base
::
Atomic
<
Operation
*>
AtomicOperationPtr
;
/**
Typedef for an pointer to a node protected by a Hazard Pointer
. */
/**
Hazard-protected pointer to a tree operation
. */
typedef
internal
::
UniqueHazardPointer
<
Operation
>
HazardOperationPtr
;
/**
Typedef for an o
bject pool for tree nodes. */
/**
O
bject pool for tree nodes. */
typedef
ObjectPool
<
Node
,
ValuePool
>
NodePool
;
/**
Typedef for an o
bject pool for tree operations. */
/**
O
bject pool for tree operations. */
typedef
ObjectPool
<
Operation
,
ValuePool
>
OperationPool
;
/** Enumeration of used hazard pointer indexes. */
typedef
enum
{
// Node/operation used for helping
HIDX_HELPING
=
0
,
// Common shared nodes
// Common shared nodes
/operations
HIDX_GRANDGRANDPARENT
,
HIDX_GRANDPARENT
,
HIDX_PARENT
,
HIDX_LEAF
,
HIDX_SIBLING
=
HIDX_GRANDGRANDPARENT
,
// Never occur in the same scope
// Rebalancing nodes
// Rebalancing nodes
/operations
HIDX_U
=
HIDX_GRANDGRANDPARENT
,
// Renamed when passed to "Rebalance"
HIDX_UX
=
HIDX_GRANDPARENT
,
// Renamed when passed to "Rebalance"
HIDX_UXX
=
HIDX_PARENT
,
// Renamed when passed to "Rebalance"
...
...
@@ -799,14 +759,55 @@ class ChromaticTree {
*/
bool
IsBalanced
(
const
Node
*
node
)
const
;
/**
* Retire a hazardous node using the node hazard manager.
*
* \param node A hazardous node to be retired
*/
void
RetireNode
(
HazardNodePtr
&
node
);
/**
* Retire a hazardous operation object using the operation hazard manager.
*
* \param operation A hazardous operation to be retired
*/
void
RetireOperation
(
HazardOperationPtr
&
operation
);
/**
* Get a node hazard guard with the specified \c index from the node hazard
* manager.
*
* \param index Index of requested guard
*
* \return Hazard guard with the specified index
*/
AtomicNodePtr
&
GetNodeGuard
(
HazardIndex
index
);
/**
* Get an operation hazard guard with the specified \c index from the
* operation hazard manager.
*
* \param index Index of requested guard
*
* \return Hazard guard with the specified index
*/
AtomicOperationPtr
&
GetOperationGuard
(
HazardIndex
index
);
/**
* Performs a WeakLLX operation according to the Tree Update template, i.e.
* reads the operation pointer of the given \c node and check whether this
* operation is completed or in progress. If it is completed and the \c node
* is not retired, returns \c true and sets the \c operation variable to point
* to the read operation. If the read operation is in progress, helps it and
* returns \c false.
*
* \param node The node
* \param operation Reference to the current operation pointer value of the
* \c node to be used in the following SCX
*
* \return \c true if the \c node is not reserved by another operation and the
* \c operation was successfully read, \c false if the \c node is busy
*/
bool
WeakLLX
(
HazardNodePtr
&
node
,
HazardOperationPtr
&
operation
);
/**
...
...
@@ -816,6 +817,11 @@ class ChromaticTree {
*/
void
FreeNode
(
Node
*
node
);
/**
* Free a tree operation by returning it to the operation pool.
*
* \param[IN] operation An operation to be freed.
*/
void
FreeOperation
(
Operation
*
operation
);
/**
...
...
@@ -854,18 +860,19 @@ class ChromaticTree {
// directly inside the class definition.
# include <embb/containers/internal/lock_free_chromatic_tree-rebalance.h>
/** Hazard pointer
instance for protection of node pointers
*/
/** Hazard pointer
manager for protecting node pointers.
*/
internal
::
HazardPointer
<
Node
*>
node_hazard_manager_
;
/** Hazard pointer manager for protecting operation pointers. */
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_
;
/**< Pool of tree nodes */
OperationPool
operation_pool_
;
/**< Pool of operation objects */
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_
;
/**< 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 */
* the entry point into the tree
.
*/
/**
* Friending the test class for white-box testing
...
...
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