Commit 2f75565c by Danila Klimenko

chromatic_tree: Fine-grained locking implementation (complete with rebalancing)

parent 871b5391
...@@ -182,7 +182,9 @@ HazardPointerThreadEntry<GuardType>::~HazardPointerThreadEntry() { ...@@ -182,7 +182,9 @@ HazardPointerThreadEntry<GuardType>::~HazardPointerThreadEntry() {
} }
template< typename GuardType > template< typename GuardType >
GuardType HazardPointerThreadEntry<GuardType>::GetGuard(int pos) const { typename HazardPointerThreadEntry<GuardType>::AtomicGuard&
HazardPointerThreadEntry<GuardType>::GetGuard(int pos) const {
assert(pos >= 0 && pos < guards_per_thread);
return guarded_pointers[pos]; return guarded_pointers[pos];
} }
...@@ -393,6 +395,12 @@ void HazardPointer< GuardType >::GuardPointer(int guardPosition, ...@@ -393,6 +395,12 @@ void HazardPointer< GuardType >::GuardPointer(int guardPosition,
} }
template< typename GuardType > template< typename GuardType >
typename HazardPointer< GuardType >::AtomicGuard&
HazardPointer< GuardType >::GetGuardedPointer(int guardPosition) {
return GetHazardPointerElementForCurrentThread().GetGuard(guardPosition);
}
template< typename GuardType >
void HazardPointer< GuardType >::EnqueuePointerForDeletion( void HazardPointer< GuardType >::EnqueuePointerForDeletion(
GuardType guardedElement) { GuardType guardedElement) {
GetHazardPointerElementForCurrentThread().AddRetired(guardedElement); GetHazardPointerElementForCurrentThread().AddRetired(guardedElement);
......
...@@ -238,6 +238,8 @@ class HazardPointerThreadEntry { ...@@ -238,6 +238,8 @@ class HazardPointerThreadEntry {
HazardPointerThreadEntry & operator= (const HazardPointerThreadEntry&); HazardPointerThreadEntry & operator= (const HazardPointerThreadEntry&);
public: public:
typedef embb::base::Atomic< GuardType > AtomicGuard;
/** /**
* Checks if current thread is active (with respect to participating in hazard * Checks if current thread is active (with respect to participating in hazard
* pointer management) * pointer management)
...@@ -318,7 +320,7 @@ class HazardPointerThreadEntry { ...@@ -318,7 +320,7 @@ class HazardPointerThreadEntry {
* Gets the guard at the specified position. * Gets the guard at the specified position.
* Positions are numbered, beginning with 0. * Positions are numbered, beginning with 0.
*/ */
GuardType GetGuard( AtomicGuard& GetGuard(
int pos int pos
/**< [IN] Position of the guard */) const; /**< [IN] Position of the guard */) const;
...@@ -467,6 +469,8 @@ class HazardPointer { ...@@ -467,6 +469,8 @@ class HazardPointer {
can be deleted*/); can be deleted*/);
public: public:
typedef typename HazardPointerThreadEntry_t::AtomicGuard AtomicGuard;
/** /**
* Gets the capacity of one retired list * Gets the capacity of one retired list
* *
...@@ -516,6 +520,9 @@ class HazardPointer { ...@@ -516,6 +520,9 @@ class HazardPointer {
* Guards \c guardedElement with the guard at position \c guardPosition * Guards \c guardedElement with the guard at position \c guardPosition
*/ */
void GuardPointer(int guardPosition, GuardType guardedElement); void GuardPointer(int guardPosition, GuardType guardedElement);
AtomicGuard& GetGuardedPointer(int guardPosition);
/** /**
* Enqueue a pointer for deletion. It is added to the retired list and * Enqueue a pointer for deletion. It is added to the retired list and
* deleted when no thread accesses it anymore. * deleted when no thread accesses it anymore.
......
...@@ -105,7 +105,7 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value, ...@@ -105,7 +105,7 @@ ChromaticTree(size_t capacity, Key undefined_key, Value undefined_value,
#ifdef EMBB_PLATFORM_COMPILER_MSVC #ifdef EMBB_PLATFORM_COMPILER_MSVC
#pragma warning(pop) #pragma warning(pop)
#endif #endif
node_hazard_manager_(free_node_callback_, NULL, 8), node_hazard_manager_(free_node_callback_, NULL, 10),
undefined_key_(undefined_key), undefined_key_(undefined_key),
undefined_value_(undefined_value), undefined_value_(undefined_value),
compare_(compare), compare_(compare),
...@@ -128,8 +128,9 @@ ChromaticTree<Key, Value, Compare, NodePool>:: ...@@ -128,8 +128,9 @@ ChromaticTree<Key, Value, Compare, NodePool>::
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: bool ChromaticTree<Key, Value, Compare, NodePool>::
Get(const Key& key, Value& value) { Get(const Key& key, Value& value) {
NodePtr leaf; HazardNodePtr parent(node_hazard_manager_.GetGuardedPointer(0), NULL);
Search(key, leaf); HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(1), NULL);
Search(key, leaf, parent);
bool keys_are_equal = !IsSentinel(leaf) && bool keys_are_equal = !IsSentinel(leaf) &&
!(compare_(key, leaf->GetKey()) || !(compare_(key, leaf->GetKey()) ||
...@@ -139,8 +140,6 @@ Get(const Key& key, Value& value) { ...@@ -139,8 +140,6 @@ Get(const Key& key, Value& value) {
value = leaf->GetValue(); value = leaf->GetValue();
} }
node_hazard_manager_.GuardPointer(0, NULL);
return keys_are_equal; return keys_are_equal;
} }
...@@ -158,9 +157,11 @@ TryInsert(const Key& key, const Value& value, Value& old_value) { ...@@ -158,9 +157,11 @@ TryInsert(const Key& key, const Value& value, Value& old_value) {
NodePtr new_sibling = NULL; NodePtr new_sibling = NULL;
NodePtr new_parent = NULL; NodePtr new_parent = NULL;
bool insertion_succeeded = false; bool insertion_succeeded = false;
bool added_violation = false;
while (!insertion_succeeded) { while (!insertion_succeeded) {
NodePtr leaf, parent; HazardNodePtr parent(node_hazard_manager_.GetGuardedPointer(0), NULL);
HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(1), NULL);
Search(key, leaf, parent); Search(key, leaf, parent);
// Try to lock the parent // Try to lock the parent
...@@ -200,23 +201,21 @@ TryInsert(const Key& key, const Value& value, Value& old_value) { ...@@ -200,23 +201,21 @@ TryInsert(const Key& key, const Value& value, Value& old_value) {
if (new_parent == NULL) break; if (new_parent == NULL) break;
} }
GetPointerToChild(parent, leaf).CompareAndSwap(leaf, new_parent); NodePtr expected = leaf;
insertion_succeeded = GetPointerToChild(parent, leaf)
insertion_succeeded = true; .CompareAndSwap(expected, new_parent);
assert(insertion_succeeded); // For now (FGL tree) this CAS may not fail
if (!insertion_succeeded) continue;
leaf->Retire(); RetireHazardousNode(leaf, leaf_lock);
leaf_lock.Unlock();
node_hazard_manager_.GuardPointer(1, NULL);
RemoveNode(leaf);
// if (parent->GetWeight() == 0 && new_parent->GetWeight() == 0) { added_violation = (parent->GetWeight() == 0 &&
// CleanUp(key); new_parent->GetWeight() == 0);
// }
} }
node_hazard_manager_.GuardPointer(0, NULL);
node_hazard_manager_.GuardPointer(1, NULL);
if (!insertion_succeeded) { if (insertion_succeeded) {
if (added_violation) CleanUp(key);
} else {
if (new_leaf != NULL) FreeNode(new_leaf); if (new_leaf != NULL) FreeNode(new_leaf);
if (new_sibling != NULL) FreeNode(new_sibling); if (new_sibling != NULL) FreeNode(new_sibling);
if (new_parent != NULL) FreeNode(new_parent); if (new_parent != NULL) FreeNode(new_parent);
...@@ -237,9 +236,12 @@ bool ChromaticTree<Key, Value, Compare, NodePool>:: ...@@ -237,9 +236,12 @@ bool ChromaticTree<Key, Value, Compare, NodePool>::
TryDelete(const Key& key, Value& old_value) { TryDelete(const Key& key, Value& old_value) {
NodePtr new_leaf = NULL; NodePtr new_leaf = NULL;
bool deletion_succeeded = false; bool deletion_succeeded = false;
bool added_violation = false;
while (!deletion_succeeded) { while (!deletion_succeeded) {
NodePtr leaf, parent, grandparent; HazardNodePtr grandparent(node_hazard_manager_.GetGuardedPointer(0), NULL);
HazardNodePtr parent (node_hazard_manager_.GetGuardedPointer(1), NULL);
HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(2), NULL);
Search(key, leaf, parent, grandparent); Search(key, leaf, parent, grandparent);
// Reached leaf has a different key - nothing to delete // Reached leaf has a different key - nothing to delete
...@@ -259,15 +261,16 @@ TryDelete(const Key& key, Value& old_value) { ...@@ -259,15 +261,16 @@ TryDelete(const Key& key, Value& old_value) {
// Try to lock the parent // Try to lock the parent
UniqueLock parent_lock(parent->GetMutex(), embb::base::try_lock); UniqueLock parent_lock(parent->GetMutex(), embb::base::try_lock);
if (!parent_lock.OwnsLock() || parent->IsRetired()) continue; if (!parent_lock.OwnsLock() || parent->IsRetired()) continue;
// Verify that the leaf is still the parent's child
if (!HasChild(parent, leaf)) continue;
AtomicNodePtr& other_child = ((parent->GetLeft() == leaf) ? // Get the sibling (and protect it with hazard pointer)
HazardNodePtr sibling(node_hazard_manager_.GetGuardedPointer(3), NULL);
sibling.ProtectHazard((parent->GetLeft() == leaf) ?
parent->GetRight() : parent->GetLeft()); parent->GetRight() : parent->GetLeft());
NodePtr sibling = other_child; if (parent->IsRetired() || !sibling.IsActive()) continue;
node_hazard_manager_.GuardPointer(3, sibling); VERIFY_ADDRESS(static_cast<NodePtr>(sibling));
if (sibling != other_child) continue;
VERIFY_ADDRESS(sibling); // Verify that the leaf is still the parent's child
if (!HasChild(parent, leaf)) continue;
// Try to lock the sibling // Try to lock the sibling
UniqueLock sibling_lock(sibling->GetMutex(), embb::base::try_lock); UniqueLock sibling_lock(sibling->GetMutex(), embb::base::try_lock);
...@@ -287,33 +290,22 @@ TryDelete(const Key& key, Value& old_value) { ...@@ -287,33 +290,22 @@ TryDelete(const Key& key, Value& old_value) {
old_value = leaf->GetValue(); old_value = leaf->GetValue();
GetPointerToChild(grandparent, parent).CompareAndSwap(parent, new_leaf); NodePtr expected = parent;
deletion_succeeded = GetPointerToChild(grandparent, parent)
.CompareAndSwap(expected, new_leaf);
assert(deletion_succeeded); // For now (FGL tree) this CAS may not fail
if (!deletion_succeeded) continue;
deletion_succeeded = true; RetireHazardousNode(parent, parent_lock);
RetireHazardousNode(leaf, leaf_lock);
RetireHazardousNode(sibling, sibling_lock);
added_violation = (new_weight > 1);
}
parent->Retire(); if (deletion_succeeded) {
parent_lock.Unlock(); if (added_violation) CleanUp(key);
node_hazard_manager_.GuardPointer(1, NULL); } else {
RemoveNode(parent);
leaf->Retire();
leaf_lock.Unlock();
node_hazard_manager_.GuardPointer(2, NULL);
RemoveNode(leaf);
sibling->Retire();
sibling_lock.Unlock();
node_hazard_manager_.GuardPointer(3, NULL);
RemoveNode(sibling);
// if (new_weight > 1) {
// CleanUp(key);
// }
}
node_hazard_manager_.GuardPointer(0, NULL);
node_hazard_manager_.GuardPointer(1, NULL);
node_hazard_manager_.GuardPointer(2, NULL);
node_hazard_manager_.GuardPointer(3, NULL);
if (!deletion_succeeded) {
if (new_leaf != NULL) FreeNode(new_leaf); if (new_leaf != NULL) FreeNode(new_leaf);
} }
...@@ -340,39 +332,22 @@ IsEmpty() { ...@@ -340,39 +332,22 @@ IsEmpty() {
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>:: void ChromaticTree<Key, Value, Compare, NodePool>::
Search(const Key& key, NodePtr& leaf) { Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent) {
NodePtr parent;
Search(key, leaf, parent);
node_hazard_manager_.GuardPointer(0, leaf);
node_hazard_manager_.GuardPointer(1, NULL);
}
template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>::
Search(const Key& key, NodePtr& leaf, NodePtr& parent) {
bool reached_leaf = false; bool reached_leaf = false;
while (!reached_leaf) { while (!reached_leaf) {
parent = entry_; parent.ProtectHazard(entry_);
node_hazard_manager_.GuardPointer(0, parent); leaf.ProtectHazard(entry_->GetLeft());
if (parent->IsRetired() || !leaf.IsActive()) continue;
leaf = entry_->GetLeft();
node_hazard_manager_.GuardPointer(1, leaf);
if (leaf != entry_->GetLeft()) continue;
reached_leaf = IsLeaf(leaf); reached_leaf = IsLeaf(leaf);
while (!reached_leaf) { while (!reached_leaf) {
parent = leaf; parent.AdoptGuard(leaf);
node_hazard_manager_.GuardPointer(0, parent); leaf.ProtectHazard((IsSentinel(leaf) || compare_(key, leaf->GetKey())) ?
leaf->GetLeft() : leaf->GetRight());
AtomicNodePtr& next_leaf = if (parent->IsRetired() || !leaf.IsActive()) break;
(IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? VERIFY_ADDRESS(static_cast<NodePtr>(leaf));
leaf->GetLeft() : leaf->GetRight();
leaf = next_leaf;
node_hazard_manager_.GuardPointer(1, leaf);
if (leaf != next_leaf || parent->IsRetired()) break;
VERIFY_ADDRESS(leaf);
reached_leaf = IsLeaf(leaf); reached_leaf = IsLeaf(leaf);
} }
} }
...@@ -380,35 +355,25 @@ Search(const Key& key, NodePtr& leaf, NodePtr& parent) { ...@@ -380,35 +355,25 @@ Search(const Key& key, NodePtr& leaf, NodePtr& parent) {
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
void ChromaticTree<Key, Value, Compare, NodePool>:: void ChromaticTree<Key, Value, Compare, NodePool>::
Search(const Key& key, NodePtr& leaf, NodePtr& parent, NodePtr& grandparent) { Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent,
HazardNodePtr& grandparent) {
bool reached_leaf = false; bool reached_leaf = false;
while (!reached_leaf) { while (!reached_leaf) {
grandparent = NULL; grandparent.ProtectHazard(entry_);
parent.ProtectHazard(entry_);
parent = entry_; leaf.ProtectHazard(entry_->GetLeft());
node_hazard_manager_.GuardPointer(1, parent); if (parent->IsRetired() || !leaf.IsActive()) continue;
leaf = entry_->GetLeft();
node_hazard_manager_.GuardPointer(2, leaf);
if (leaf != entry_->GetLeft()) continue;
reached_leaf = IsLeaf(leaf); reached_leaf = IsLeaf(leaf);
while (!reached_leaf) { while (!reached_leaf) {
grandparent = parent; grandparent.AdoptGuard(parent);
node_hazard_manager_.GuardPointer(0, grandparent); 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<NodePtr>(leaf));
parent = leaf;
node_hazard_manager_.GuardPointer(1, parent);
AtomicNodePtr& next_leaf =
(IsSentinel(leaf) || compare_(key, leaf->GetKey())) ?
leaf->GetLeft() : leaf->GetRight();
leaf = next_leaf;
node_hazard_manager_.GuardPointer(2, leaf);
if (leaf != next_leaf || parent->IsRetired()) break;
VERIFY_ADDRESS(leaf);
reached_leaf = IsLeaf(leaf); reached_leaf = IsLeaf(leaf);
} }
} }
...@@ -423,13 +388,15 @@ IsLeaf(const NodePtr& node) const { ...@@ -423,13 +388,15 @@ IsLeaf(const NodePtr& node) const {
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: bool ChromaticTree<Key, Value, Compare, NodePool>::
IsSentinel(const NodePtr& node) const { IsSentinel(const NodePtr& node) const {
return (node == entry_) || (node == entry_->GetLeft()); NodePtr entry = entry_; //Bug: "operator->()" is not const in AtomicPointer<>
return (node == entry) || (node == entry->GetLeft());
} }
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: bool ChromaticTree<Key, Value, Compare, NodePool>::
HasFixedWeight(const NodePtr& node) const { HasFixedWeight(const NodePtr& node) const {
return (IsSentinel(node)) || (node == entry_->GetLeft()->GetLeft()); NodePtr entry = entry_; //Bug: "operator->()" is not const in AtomicPointer<>
return (IsSentinel(node)) || (node == entry->GetLeft()->GetLeft());
} }
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
...@@ -470,7 +437,8 @@ GetHeight(const NodePtr& node) const { ...@@ -470,7 +437,8 @@ GetHeight(const NodePtr& node) const {
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: bool ChromaticTree<Key, Value, Compare, NodePool>::
IsBalanced() const { IsBalanced() const {
return IsBalanced(entry_->GetLeft()); NodePtr entry = entry_; //Bug: "operator->()" is not const in AtomicPointer<>
return IsBalanced(entry->GetLeft());
} }
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
...@@ -509,92 +477,137 @@ FreeNode(NodePtr node) { ...@@ -509,92 +477,137 @@ FreeNode(NodePtr node) {
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: bool ChromaticTree<Key, Value, Compare, NodePool>::
CleanUp(const Key& key) { CleanUp(const Key& key) {
for (;;) { HazardNodePtr grangranparent(node_hazard_manager_.GetGuardedPointer(0), NULL);
NodePtr grandgrandparent = NULL; HazardNodePtr grandparent (node_hazard_manager_.GetGuardedPointer(1), NULL);
NodePtr grandparent = NULL; HazardNodePtr parent (node_hazard_manager_.GetGuardedPointer(2), NULL);
NodePtr parent = entry_; HazardNodePtr leaf (node_hazard_manager_.GetGuardedPointer(3), NULL);
NodePtr leaf = entry_->GetLeft(); bool reached_leaf = false;
while (!IsLeaf(leaf) && (leaf->GetWeight() <= 1) && while (!reached_leaf) {
(leaf->GetWeight() != 0 || parent->GetWeight() != 0)) { bool found_violation = false;
grandgrandparent = grandparent;
grandparent = parent; grangranparent.ProtectHazard(entry_);
parent = leaf; grandparent.ProtectHazard(entry_);
leaf = (IsSentinel(leaf) || compare_(key, leaf->GetKey())) ? parent.ProtectHazard(entry_);
leaf->GetLeft() : leaf->GetRight(); leaf.ProtectHazard(entry_->GetLeft());
VERIFY_ADDRESS(leaf); if (parent->IsRetired() || !leaf.IsActive()) continue;
}
reached_leaf = IsLeaf(leaf);
if (leaf->GetWeight() == 1) { while (!reached_leaf && !found_violation) {
break; grangranparent.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<NodePtr>(leaf));
found_violation = (leaf->GetWeight() > 1) ||
(leaf->GetWeight() == 0 && parent->GetWeight() == 0);
reached_leaf = IsLeaf(leaf);
} }
if (!Rebalance(grandgrandparent, grandparent, parent, leaf)) { if (found_violation) {
reached_leaf = false;
if (Rebalance(grangranparent, grandparent, parent, leaf) == EMBB_NOMEM) {
assert(false && "No memory for rebalancing!");
return false; return false;
} }
} }
}
return true; return true;
} }
#define PROTECT_NODE_WITH_LOCK(node, lock_name) \
UniqueLock lock_name(node->GetMutex(), embb::base::try_lock); \
if (!lock_name.OwnsLock() || node->IsRetired()) return EMBB_BUSY;
#define DEFINE_NODE_WITH_HAZARD(h_num, node, parent, method) \
HazardNodePtr node(node_hazard_manager_.GetGuardedPointer(h_num), NULL); \
node.ProtectHazard(parent->method()); \
if (parent->IsRetired() || !node.IsActive()) return EMBB_BUSY; \
VERIFY_ADDRESS(static_cast<NodePtr>(node))
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: embb_errors_t ChromaticTree<Key, Value, Compare, NodePool>::
Rebalance(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, Rebalance(HazardNodePtr& u, HazardNodePtr& ux, HazardNodePtr& uxx,
const NodePtr& uxxx) { HazardNodePtr& uxxx) {
//TODO: weakLLX(u); // Protect node 'u'
if (!HasChild(u, ux)) return false; PROTECT_NODE_WITH_LOCK(u, u_lock);
// Verify that ux is still a child of u
//TODO: weakLLX(ux); if (!HasChild(u, ux)) return EMBB_BUSY;
NodePtr uxl = ux->GetLeft(); VERIFY_ADDRESS(uxl);
NodePtr uxr = ux->GetRight(); VERIFY_ADDRESS(uxr); // Protect node 'ux'
bool uxx_is_left = (uxx == uxl); PROTECT_NODE_WITH_LOCK(ux, ux_lock);
if (!HasChild(ux, uxx)) return false; // Get children of 'ux'
DEFINE_NODE_WITH_HAZARD(4, uxl, ux, GetLeft);
//TODO: weakLLX(uxx); DEFINE_NODE_WITH_HAZARD(5, uxr, ux, GetRight);
NodePtr uxxl = uxx->GetLeft(); VERIFY_ADDRESS(uxxl); // Verify that 'uxx' is still a child of 'ux'
NodePtr uxxr = uxx->GetRight(); VERIFY_ADDRESS(uxxr); bool uxx_is_left = (uxx == uxl); (void)uxx_is_left;
if (!HasChild(ux, uxx)) return EMBB_BUSY;
// Protect node 'uxx'
PROTECT_NODE_WITH_LOCK(uxx, uxx_lock);
// Get children of 'uxx'
DEFINE_NODE_WITH_HAZARD(6, uxxl, uxx, GetLeft);
DEFINE_NODE_WITH_HAZARD(7, uxxr, uxx, GetRight);
// Verify that 'uxxx' is still a child of 'uxx'
bool uxxx_is_left = (uxxx == uxxl); bool uxxx_is_left = (uxxx == uxxl);
if (!HasChild(uxx, uxxx)) return false; if (!HasChild(uxx, uxxx)) return EMBB_BUSY;
if (uxxx->GetWeight() > 1) { if (uxxx->GetWeight() > 1) {
if (uxxx_is_left) { if (uxxx_is_left) {
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
return OverweightLeft(u, ux, uxx, uxl, uxr, uxxl, uxxr, uxx_is_left); PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
return OverweightLeft(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxl, uxr,
uxxl, uxxl_lock, uxxr, uxx_is_left);
} else { } else {
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
return OverweightRight(u, ux, uxx, uxl, uxr, uxxl, uxxr, !uxx_is_left); PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
return OverweightRight(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxl, uxr,
uxxl, uxxr, uxxr_lock, !uxx_is_left);
} }
} else { } else {
assert(uxxx->GetWeight() == 0 && uxx->GetWeight() == 0); //Red-red violation
if (uxx_is_left) { if (uxx_is_left) {
if (uxr->GetWeight() == 0) { if (uxr->GetWeight() == 0) {
//TODO: weakLLX(uxr); // Protect node 'uxr'
return BLK(u, ux, uxx, uxr); PROTECT_NODE_WITH_LOCK(uxr, uxr_lock);
return BLK(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxr, uxr_lock);
} else if (uxxx_is_left) { } else if (uxxx_is_left) {
return RB1_L(u, ux, uxx); return RB1_L(u, u_lock, ux, ux_lock, uxx, uxx_lock);
} else { } else {
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
return RB2_L(u, ux, uxx, uxxr); PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
return RB2_L(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxxr, uxxr_lock);
} }
} else { } else {
if (uxl->GetWeight() == 0) { if (uxl->GetWeight() == 0) {
//TODO: weakLLX(uxl); // Protect node 'uxl'
return BLK(u, ux, uxl, uxx); PROTECT_NODE_WITH_LOCK(uxl, uxl_lock);
return BLK(u, u_lock, ux, ux_lock, uxl, uxl_lock, uxx, uxx_lock);
} else if (!uxxx_is_left) { } else if (!uxxx_is_left) {
return RB1_R(u, ux, uxx); return RB1_R(u, u_lock, ux, ux_lock, uxx, uxx_lock);
} else { } else {
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
return RB2_R(u, ux, uxx, uxxl); PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
return RB2_R(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock);
} }
} }
} }
} }
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: embb_errors_t ChromaticTree<Key, Value, Compare, NodePool>::
OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, OverweightLeft(HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, const NodePtr& uxr, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxxl, const NodePtr& uxxr, HazardNodePtr& uxx, UniqueLock& uxx_lock,
const bool& uxx_is_left) { HazardNodePtr& uxl, HazardNodePtr& uxr,
HazardNodePtr& uxxl, UniqueLock& uxxl_lock,
HazardNodePtr& uxxr, bool uxx_is_left) {
// Let "Root" be the top of the overweight violation decision tree (see p.30) // Let "Root" be the top of the overweight violation decision tree (see p.30)
// Root -> Middle // Root -> Middle
if (uxxr->GetWeight() == 0) { if (uxxr->GetWeight() == 0) {
...@@ -604,14 +617,16 @@ OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, ...@@ -604,14 +617,16 @@ OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx,
if (uxx_is_left) { if (uxx_is_left) {
// Root -> Middle -> Left -> Left -> Left // Root -> Middle -> Left -> Left -> Left
if (uxr->GetWeight() == 0) { if (uxr->GetWeight() == 0) {
//TODO: weakLLX(uxr); // Protect node 'uxr'
return BLK(u, ux, uxx, uxr); PROTECT_NODE_WITH_LOCK(uxr, uxr_lock);
return BLK(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxr, uxr_lock);
// Root -> Middle -> Left -> Left -> Right // Root -> Middle -> Left -> Left -> Right
} else { } else {
assert(uxr->GetWeight() > 0); assert(uxr->GetWeight() > 0);
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
return RB2_L(u, ux, uxx, uxxr); PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
return RB2_L(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxxr, uxxr_lock);
} }
// Root -> Middle -> Left -> Right // Root -> Middle -> Left -> Right
...@@ -619,102 +634,126 @@ OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, ...@@ -619,102 +634,126 @@ OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx,
assert(!uxx_is_left); assert(!uxx_is_left);
// Root -> Middle -> Left -> Right -> Left // Root -> Middle -> Left -> Right -> Left
if (uxl->GetWeight() == 0) { if (uxl->GetWeight() == 0) {
//TODO: weakLLX(uxl); // Protect node 'uxl'
return BLK(u, ux, uxl, uxx); PROTECT_NODE_WITH_LOCK(uxl, uxl_lock);
return BLK(u, u_lock, ux, ux_lock, uxl, uxl_lock, uxx, uxx_lock);
// Root -> Middle -> Left -> Right -> Right // Root -> Middle -> Left -> Right -> Right
} else { } else {
assert(uxl->GetWeight() > 0); assert(uxl->GetWeight() > 0);
return RB1_R(u, ux, uxx); return RB1_R(u, u_lock, ux, ux_lock, uxx, uxx_lock);
} }
} }
// Root -> Middle -> Right // Root -> Middle -> Right
} else { } else {
assert(uxx->GetWeight() > 0); assert(uxx->GetWeight() > 0);
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
// Get left child of 'uxxr'
// Note: we know that 'uxxr' is not a leaf because it has weight 0. // Note: we know that 'uxxr' is not a leaf because it has weight 0.
NodePtr uxxrl = uxxr->GetLeft(); VERIFY_ADDRESS(uxxrl); DEFINE_NODE_WITH_HAZARD(8, uxxrl, uxxr, GetLeft);
//TODO: weakLLX(uxxrl);
// Protect node 'uxxrl'
PROTECT_NODE_WITH_LOCK(uxxrl, uxxrl_lock);
// Root -> Middle -> Right -> Left // Root -> Middle -> Right -> Left
if (uxxrl->GetWeight() == 0) { if (uxxrl->GetWeight() == 0) {
return RB2_R(ux, uxx, uxxr, uxxrl); return RB2_R(ux, ux_lock, uxx, uxx_lock,
uxxr, uxxr_lock, uxxrl, uxxrl_lock);
// Root -> Middle -> Right -> Middle // Root -> Middle -> Right -> Middle
} else if (uxxrl->GetWeight() == 1) { } else if (uxxrl->GetWeight() == 1) {
NodePtr uxxrll = uxxrl->GetLeft(); VERIFY_ADDRESS(uxxrll); DEFINE_NODE_WITH_HAZARD(9, uxxrlr, uxxrl, GetRight);
NodePtr uxxrlr = uxxrl->GetRight(); VERIFY_ADDRESS(uxxrlr); if (uxxrlr == NULL) return EMBB_BUSY;
if (uxxrlr == NULL) return false;
// Root -> Middle -> Right -> Middle -> Left // Root -> Middle -> Right -> Middle -> Left
if (uxxrlr->GetWeight() == 0) { if (uxxrlr->GetWeight() == 0) {
//TODO: weakLLX(uxxrlr); // Protect node 'uxxrlr'
return W4_L(ux, uxx, uxxl, uxxr, uxxrl, uxxrlr); PROTECT_NODE_WITH_LOCK(uxxrlr, uxxrlr_lock);
return W4_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxrl, uxxrl_lock, uxxrlr, uxxrlr_lock);
// Root -> Middle -> Right -> Middle -> Right // Root -> Middle -> Right -> Middle -> Right
} else { } else {
assert(uxxrlr->GetWeight() > 0); assert(uxxrlr->GetWeight() > 0);
// Root -> Middle -> Right -> Middle -> Right -> Left // Root -> Middle -> Right -> Middle -> Right -> Left
// Node: reusing hazard of node 'uxxrlr' as it is no longer used
DEFINE_NODE_WITH_HAZARD(9, uxxrll, uxxrl, GetLeft);
if (uxxrll->GetWeight() == 0) { if (uxxrll->GetWeight() == 0) {
//TODO: weakLLX(uxxrll); // Protect node 'uxxrll'
return W3_L(ux, uxx, uxxl, uxxr, uxxrl, uxxrll); PROTECT_NODE_WITH_LOCK(uxxrll, uxxrll_lock);
return W3_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock, uxxr,
uxxr_lock, uxxrl, uxxrl_lock, uxxrll, uxxrll_lock);
// Root -> Middle -> Right -> Middle -> Right -> Right // Root -> Middle -> Right -> Middle -> Right -> Right
} else { } else {
assert(uxxrll->GetWeight() > 0); assert(uxxrll->GetWeight() > 0);
return W2_L(ux, uxx, uxxl, uxxr, uxxrl); return W2_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxrl, uxxrl_lock);
} }
} }
// Root -> Middle -> Right -> Right // Root -> Middle -> Right -> Right
} else { } else {
assert(uxxrl->GetWeight() > 1); assert(uxxrl->GetWeight() > 1);
return W1_L(ux, uxx, uxxl, uxxr, uxxrl); return W1_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxrl, uxxrl_lock);
} }
} }
// Root -> Right // Root -> Right
} else if (uxxr->GetWeight() == 1) { } else if (uxxr->GetWeight() == 1) {
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
NodePtr uxxrl = uxxr->GetLeft(); VERIFY_ADDRESS(uxxrl); PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
NodePtr uxxrr = uxxr->GetRight(); VERIFY_ADDRESS(uxxrr); // Get children of 'uxxr'
if (uxxrl == NULL) return false; DEFINE_NODE_WITH_HAZARD(8, uxxrl, uxxr, GetLeft);
DEFINE_NODE_WITH_HAZARD(9, uxxrr, uxxr, GetRight);
if (uxxrl == NULL) return EMBB_BUSY;
// Root -> Right -> Left // Root -> Right -> Left
if (uxxrr->GetWeight() == 0) { if (uxxrr->GetWeight() == 0) {
//TODO: weakLLX(uxxrr); // Protect node 'uxxrr'
return W5_L(ux, uxx, uxxl, uxxr, uxxrr); PROTECT_NODE_WITH_LOCK(uxxrr, uxxrr_lock);
return W5_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxrr, uxxrr_lock);
// Root -> Right -> Right // Root -> Right -> Right
} else { } else {
assert(uxxrr->GetWeight() > 0); assert(uxxrr->GetWeight() > 0);
// Root -> Right -> Right -> Left // Root -> Right -> Right -> Left
if (uxxrl->GetWeight() == 0) { if (uxxrl->GetWeight() == 0) {
//TODO: weakLLX(uxxrl); // Protect node 'uxxrl'
return W6_L(ux, uxx, uxxl, uxxr, uxxrl); PROTECT_NODE_WITH_LOCK(uxxrl, uxxrl_lock);
return W6_L(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxrl, uxxrl_lock);
// Root -> Right -> Right -> Right // Root -> Right -> Right -> Right
} else { } else {
assert(uxxrl->GetWeight() > 0); assert(uxxrl->GetWeight() > 0);
return PUSH_L(ux, uxx, uxxl, uxxr); return PUSH_L(ux, ux_lock, uxx, uxx_lock,
uxxl, uxxl_lock, uxxr, uxxr_lock);
} }
} }
// Root -> Left // Root -> Left
} else { } else {
assert(uxxr->GetWeight() > 1); assert(uxxr->GetWeight() > 1);
//TODO: weakLLX(uxxr); // Protect node 'uxxr'
return W7(ux, uxx, uxxl, uxxr); PROTECT_NODE_WITH_LOCK(uxxr, uxxr_lock);
return W7(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock, uxxr, uxxr_lock);
} }
} }
template<typename Key, typename Value, typename Compare, typename NodePool> template<typename Key, typename Value, typename Compare, typename NodePool>
bool ChromaticTree<Key, Value, Compare, NodePool>:: embb_errors_t ChromaticTree<Key, Value, Compare, NodePool>::
OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, OverweightRight(HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, const NodePtr& uxr, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxxl, const NodePtr& uxxr, HazardNodePtr& uxx, UniqueLock& uxx_lock,
const bool& uxx_is_right) { HazardNodePtr& uxl, HazardNodePtr& uxr,
HazardNodePtr& uxxl, HazardNodePtr& uxxr,
UniqueLock& uxxr_lock, bool uxx_is_right) {
// Let "Root" be the top of the overweight violation decision tree (see p.30) // Let "Root" be the top of the overweight violation decision tree (see p.30)
// Root -> Middle // Root -> Middle
if (uxxl->GetWeight() == 0) { if (uxxl->GetWeight() == 0) {
...@@ -724,14 +763,16 @@ OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, ...@@ -724,14 +763,16 @@ OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx,
if (uxx_is_right) { if (uxx_is_right) {
// Root -> Middle -> Left -> Left -> Left // Root -> Middle -> Left -> Left -> Left
if (uxl->GetWeight() == 0) { if (uxl->GetWeight() == 0) {
//TODO: weakLLX(uxl); // Protect node 'uxl'
return BLK(u, ux, uxl, uxx); PROTECT_NODE_WITH_LOCK(uxl, uxl_lock);
return BLK(u, u_lock, ux, ux_lock, uxl, uxl_lock, uxx, uxx_lock);
// Root -> Middle -> Left -> Left -> Right // Root -> Middle -> Left -> Left -> Right
} else { } else {
assert(uxl->GetWeight() > 0); assert(uxl->GetWeight() > 0);
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
return RB2_R(u, ux, uxx, uxxl); PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
return RB2_R(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock);
} }
// Root -> Middle -> Left -> Right // Root -> Middle -> Left -> Right
...@@ -739,93 +780,115 @@ OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, ...@@ -739,93 +780,115 @@ OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx,
assert(!uxx_is_right); assert(!uxx_is_right);
// Root -> Middle -> Left -> Right -> Left // Root -> Middle -> Left -> Right -> Left
if (uxr->GetWeight() == 0) { if (uxr->GetWeight() == 0) {
//TODO: weakLLX(uxr); // Protect node 'uxr'
return BLK(u, ux, uxx, uxr); PROTECT_NODE_WITH_LOCK(uxr, uxr_lock);
return BLK(u, u_lock, ux, ux_lock, uxx, uxx_lock, uxr, uxr_lock);
// Root -> Middle -> Left -> Right -> Right // Root -> Middle -> Left -> Right -> Right
} else { } else {
assert(uxr->GetWeight() > 0); assert(uxr->GetWeight() > 0);
return RB1_L(u, ux, uxx); return RB1_L(u, u_lock, ux, ux_lock, uxx, uxx_lock);
} }
} }
// Root -> Middle -> Right // Root -> Middle -> Right
} else { } else {
assert(uxx->GetWeight() > 0); assert(uxx->GetWeight() > 0);
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
// Get left child of 'uxxl'
// Note: we know that 'uxxl' is not a leaf because it has weight 0. // Note: we know that 'uxxl' is not a leaf because it has weight 0.
NodePtr uxxlr = uxxl->GetRight(); VERIFY_ADDRESS(uxxlr); DEFINE_NODE_WITH_HAZARD(8, uxxlr, uxxl, GetRight);
//TODO: weakLLX(uxxlr);
// Protect node 'uxxlr'
PROTECT_NODE_WITH_LOCK(uxxlr, uxxlr_lock);
// Root -> Middle -> Right -> Left // Root -> Middle -> Right -> Left
if (uxxlr->GetWeight() == 0) { if (uxxlr->GetWeight() == 0) {
return RB2_L(ux, uxx, uxxl, uxxlr); return RB2_L(ux, ux_lock, uxx, uxx_lock,
uxxl, uxxl_lock, uxxlr, uxxlr_lock);
// Root -> Middle -> Right -> Middle // Root -> Middle -> Right -> Middle
} else if (uxxlr->GetWeight() == 1) { } else if (uxxlr->GetWeight() == 1) {
NodePtr uxxlrl = uxxlr->GetLeft(); VERIFY_ADDRESS(uxxlrl); DEFINE_NODE_WITH_HAZARD(9, uxxlrl, uxxlr, GetLeft);
NodePtr uxxlrr = uxxlr->GetRight(); VERIFY_ADDRESS(uxxlrr); if (uxxlrl == NULL) return EMBB_BUSY;
if (uxxlrl == NULL) return false;
// Root -> Middle -> Right -> Middle -> Left // Root -> Middle -> Right -> Middle -> Left
if (uxxlrl->GetWeight() == 0) { if (uxxlrl->GetWeight() == 0) {
//TODO: weakLLX(uxxlrl); // Protect node 'uxxlrl'
return W4_R(ux, uxx, uxxl, uxxr, uxxlr, uxxlrl); PROTECT_NODE_WITH_LOCK(uxxlrl, uxxlrl_lock);
return W4_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxlr, uxxlr_lock, uxxlrl, uxxlrl_lock);
// Root -> Middle -> Right -> Middle -> Right // Root -> Middle -> Right -> Middle -> Right
} else { } else {
assert(uxxlrl->GetWeight() > 0); assert(uxxlrl->GetWeight() > 0);
// Root -> Middle -> Right -> Middle -> Right -> Left // Root -> Middle -> Right -> Middle -> Right -> Left
// Node: reusing hazard of node 'uxxlrl' as it is no longer used
DEFINE_NODE_WITH_HAZARD(9, uxxlrr, uxxlr, GetRight);
if (uxxlrr->GetWeight() == 0) { if (uxxlrr->GetWeight() == 0) {
//TODO: weakLLX(uxxlrr); // Protect node 'uxxlrr'
return W3_R(ux, uxx, uxxl, uxxr, uxxlr, uxxlrr); PROTECT_NODE_WITH_LOCK(uxxlrr, uxxlrr_lock);
return W3_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock, uxxr,
uxxr_lock, uxxlr, uxxlr_lock, uxxlrr, uxxlrr_lock);
// Root -> Middle -> Right -> Middle -> Right -> Right // Root -> Middle -> Right -> Middle -> Right -> Right
} else { } else {
assert(uxxlrr->GetWeight() > 0); assert(uxxlrr->GetWeight() > 0);
return W2_R(ux, uxx, uxxl, uxxr, uxxlr); return W2_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxlr, uxxlr_lock);
} }
} }
// Root -> Middle -> Right -> Right // Root -> Middle -> Right -> Right
} else { } else {
assert(uxxlr->GetWeight() > 1); assert(uxxlr->GetWeight() > 1);
return W1_R(ux, uxx, uxxl, uxxr, uxxlr); return W1_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxlr, uxxlr_lock);
} }
} }
// Root -> Right // Root -> Right
} else if (uxxl->GetWeight() == 1) { } else if (uxxl->GetWeight() == 1) {
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
NodePtr uxxll = uxxl->GetLeft(); VERIFY_ADDRESS(uxxll); PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
NodePtr uxxlr = uxxl->GetRight(); VERIFY_ADDRESS(uxxlr); // Get children of 'uxxl'
if (uxxll == NULL) return false; DEFINE_NODE_WITH_HAZARD(8, uxxll, uxxl, GetLeft);
DEFINE_NODE_WITH_HAZARD(9, uxxlr, uxxl, GetRight);
if (uxxll == NULL) return EMBB_BUSY;
// Root -> Right -> Left // Root -> Right -> Left
if (uxxll->GetWeight() == 0) { if (uxxll->GetWeight() == 0) {
//TODO: weakLLX(uxxll); // Protect node 'uxxll'
return W5_R(ux, uxx, uxxl, uxxr, uxxll); PROTECT_NODE_WITH_LOCK(uxxll, uxxll_lock);
return W5_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxll, uxxll_lock);
// Root -> Right -> Right // Root -> Right -> Right
} else { } else {
assert(uxxll->GetWeight() > 0); assert(uxxll->GetWeight() > 0);
// Root -> Right -> Right -> Left // Root -> Right -> Right -> Left
if (uxxlr->GetWeight() == 0) { if (uxxlr->GetWeight() == 0) {
//TODO: weakLLX(uxxlr); // Protect node 'uxxlr'
return W6_R(ux, uxx, uxxl, uxxr, uxxlr); PROTECT_NODE_WITH_LOCK(uxxlr, uxxlr_lock);
return W6_R(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock,
uxxr, uxxr_lock, uxxlr, uxxlr_lock);
// Root -> Right -> Right -> Right // Root -> Right -> Right -> Right
} else { } else {
assert(uxxlr->GetWeight() > 0); assert(uxxlr->GetWeight() > 0);
return PUSH_R(ux, uxx, uxxl, uxxr); return PUSH_R(ux, ux_lock, uxx, uxx_lock,
uxxl, uxxl_lock, uxxr, uxxr_lock);
} }
} }
// Root -> Left // Root -> Left
} else { } else {
assert(uxxl->GetWeight() > 1); assert(uxxl->GetWeight() > 1);
//TODO: weakLLX(uxxl); // Protect node 'uxxl'
return W7(ux, uxx, uxxl, uxxr); PROTECT_NODE_WITH_LOCK(uxxl, uxxl_lock);
return W7(ux, ux_lock, uxx, uxx_lock, uxxl, uxxl_lock, uxxr, uxxr_lock);
} }
} }
......
...@@ -32,10 +32,11 @@ ...@@ -32,10 +32,11 @@
#ifndef EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_ #ifndef EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_
#define EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_ #define EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_
bool BLK(const NodePtr& u, embb_errors_t BLK(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr) { HazardNodePtr& uxl, UniqueLock& uxl_lock,
HazardNodePtr& uxr, UniqueLock& uxr_lock) {
NodePtr nxl = node_pool_.Allocate( NodePtr nxl = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
1, 1,
...@@ -55,23 +56,28 @@ bool BLK(const NodePtr& u, ...@@ -55,23 +56,28 @@ bool BLK(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool PUSH_L(const NodePtr& u, embb_errors_t PUSH_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr) { HazardNodePtr& uxl, UniqueLock& uxl_lock,
HazardNodePtr& uxr, UniqueLock& uxr_lock) {
NodePtr nxl = node_pool_.Allocate( NodePtr nxl = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -91,23 +97,28 @@ bool PUSH_L(const NodePtr& u, ...@@ -91,23 +97,28 @@ bool PUSH_L(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool PUSH_R(const NodePtr& u, embb_errors_t PUSH_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr) { HazardNodePtr& uxl, UniqueLock& uxl_lock,
HazardNodePtr& uxr, UniqueLock& uxr_lock) {
NodePtr nxr = node_pool_.Allocate( NodePtr nxr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -127,22 +138,27 @@ bool PUSH_R(const NodePtr& u, ...@@ -127,22 +138,27 @@ bool PUSH_R(const NodePtr& u,
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool RB1_L(const NodePtr& u, embb_errors_t RB1_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl) { HazardNodePtr& ux, UniqueLock& ux_lock,
HazardNodePtr& uxl, UniqueLock& uxl_lock) {
NodePtr nxr = node_pool_.Allocate( NodePtr nxr = node_pool_.Allocate(
ux->GetKey(), ux->GetValue(), ux->GetKey(), ux->GetValue(),
0, 0,
...@@ -156,21 +172,26 @@ bool RB1_L(const NodePtr& u, ...@@ -156,21 +172,26 @@ bool RB1_L(const NodePtr& u,
nx == NULL) { nx == NULL) {
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool RB1_R(const NodePtr& u, embb_errors_t RB1_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxr) { HazardNodePtr& ux, UniqueLock& ux_lock,
HazardNodePtr& uxr, UniqueLock& uxr_lock) {
NodePtr nxl = node_pool_.Allocate( NodePtr nxl = node_pool_.Allocate(
ux->GetKey(), ux->GetValue(), ux->GetKey(), ux->GetValue(),
0, 0,
...@@ -184,22 +205,27 @@ bool RB1_R(const NodePtr& u, ...@@ -184,22 +205,27 @@ bool RB1_R(const NodePtr& u,
nx == NULL) { nx == NULL) {
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool RB2_L(const NodePtr& u, embb_errors_t RB2_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxlr) { HazardNodePtr& uxl, UniqueLock& uxl_lock,
HazardNodePtr& uxlr, UniqueLock& uxlr_lock) {
NodePtr nxl = node_pool_.Allocate( NodePtr nxl = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
0, 0,
...@@ -219,23 +245,28 @@ bool RB2_L(const NodePtr& u, ...@@ -219,23 +245,28 @@ bool RB2_L(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
RetireNode(uxlr); RetireHazardousNode(uxlr, uxlr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool RB2_R(const NodePtr& u, embb_errors_t RB2_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxr, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxrl) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxrl, UniqueLock& uxrl_lock) {
NodePtr nxr = node_pool_.Allocate( NodePtr nxr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
0, 0,
...@@ -255,24 +286,29 @@ bool RB2_R(const NodePtr& u, ...@@ -255,24 +286,29 @@ bool RB2_R(const NodePtr& u,
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
RetireNode(uxrl); RetireHazardousNode(uxrl, uxrl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
bool W1_L(const NodePtr& u, embb_errors_t W1_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrl) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxrl, UniqueLock& uxrl_lock) {
NodePtr nxll = node_pool_.Allocate( NodePtr nxll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -298,25 +334,30 @@ bool W1_L(const NodePtr& u, ...@@ -298,25 +334,30 @@ bool W1_L(const NodePtr& u,
if (nxlr) FreeNode(nxlr); if (nxlr) FreeNode(nxlr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrl); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxrl, uxrl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W1_R(const NodePtr& u, embb_errors_t W1_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxlr) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxlr, UniqueLock& uxlr_lock) {
NodePtr nxrr = node_pool_.Allocate( NodePtr nxrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -342,25 +383,30 @@ bool W1_R(const NodePtr& u, ...@@ -342,25 +383,30 @@ bool W1_R(const NodePtr& u,
if (nxrl) FreeNode(nxrl); if (nxrl) FreeNode(nxrl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxlr); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxlr, uxlr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W2_L(const NodePtr& u, embb_errors_t W2_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrl) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxrl, UniqueLock& uxrl_lock) {
NodePtr nxll = node_pool_.Allocate( NodePtr nxll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -386,25 +432,30 @@ bool W2_L(const NodePtr& u, ...@@ -386,25 +432,30 @@ bool W2_L(const NodePtr& u,
if (nxlr) FreeNode(nxlr); if (nxlr) FreeNode(nxlr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrl); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxrl, uxrl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W2_R(const NodePtr& u, embb_errors_t W2_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxlr) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxlr, UniqueLock& uxlr_lock) {
NodePtr nxrr = node_pool_.Allocate( NodePtr nxrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -430,26 +481,31 @@ bool W2_R(const NodePtr& u, ...@@ -430,26 +481,31 @@ bool W2_R(const NodePtr& u,
if (nxrl) FreeNode(nxrl); if (nxrl) FreeNode(nxrl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxlr); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxlr, uxlr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W3_L(const NodePtr& u, embb_errors_t W3_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrl, HazardNodePtr& uxr, UniqueLock& uxr_lock,
const NodePtr& uxrll) { HazardNodePtr& uxrl, UniqueLock& uxrl_lock,
HazardNodePtr& uxrll, UniqueLock& uxrll_lock) {
NodePtr nxlll = node_pool_.Allocate( NodePtr nxlll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -481,27 +537,32 @@ bool W3_L(const NodePtr& u, ...@@ -481,27 +537,32 @@ bool W3_L(const NodePtr& u,
if (nxlr) FreeNode(nxlr); if (nxlr) FreeNode(nxlr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrl); RetireHazardousNode(ux, ux_lock);
RetireNode(uxrll); RetireHazardousNode(uxl, uxl_lock);
RetireHazardousNode(uxr, uxr_lock);
return true; RetireHazardousNode(uxrl, uxrl_lock);
RetireHazardousNode(uxrll, uxrll_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W3_R(const NodePtr& u, embb_errors_t W3_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxlr, HazardNodePtr& uxr, UniqueLock& uxr_lock,
const NodePtr& uxlrr) { HazardNodePtr& uxlr, UniqueLock& uxlr_lock,
HazardNodePtr& uxlrr, UniqueLock& uxlrr_lock) {
NodePtr nxrrr = node_pool_.Allocate( NodePtr nxrrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -533,27 +594,32 @@ bool W3_R(const NodePtr& u, ...@@ -533,27 +594,32 @@ bool W3_R(const NodePtr& u,
if (nxrl) FreeNode(nxrl); if (nxrl) FreeNode(nxrl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxlr); RetireHazardousNode(ux, ux_lock);
RetireNode(uxlrr); RetireHazardousNode(uxl, uxl_lock);
RetireHazardousNode(uxr, uxr_lock);
return true; RetireHazardousNode(uxlr, uxlr_lock);
RetireHazardousNode(uxlrr, uxlrr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W4_L(const NodePtr& u, embb_errors_t W4_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrl, HazardNodePtr& uxr, UniqueLock& uxr_lock,
const NodePtr& uxrlr) { HazardNodePtr& uxrl, UniqueLock& uxrl_lock,
HazardNodePtr& uxrlr, UniqueLock& uxrlr_lock) {
NodePtr nxll = node_pool_.Allocate( NodePtr nxll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -585,27 +651,32 @@ bool W4_L(const NodePtr& u, ...@@ -585,27 +651,32 @@ bool W4_L(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrl); RetireHazardousNode(ux, ux_lock);
RetireNode(uxrlr); RetireHazardousNode(uxl, uxl_lock);
RetireHazardousNode(uxr, uxr_lock);
return true; RetireHazardousNode(uxrl, uxrl_lock);
RetireHazardousNode(uxrlr, uxrlr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W4_R(const NodePtr& u, embb_errors_t W4_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxlr, HazardNodePtr& uxr, UniqueLock& uxr_lock,
const NodePtr& uxlrl) { HazardNodePtr& uxlr, UniqueLock& uxlr_lock,
HazardNodePtr& uxlrl, UniqueLock& uxlrl_lock) {
NodePtr nxrr = node_pool_.Allocate( NodePtr nxrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -637,26 +708,31 @@ bool W4_R(const NodePtr& u, ...@@ -637,26 +708,31 @@ bool W4_R(const NodePtr& u,
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxlr); RetireHazardousNode(ux, ux_lock);
RetireNode(uxlrl); RetireHazardousNode(uxl, uxl_lock);
RetireHazardousNode(uxr, uxr_lock);
return true; RetireHazardousNode(uxlr, uxlr_lock);
RetireHazardousNode(uxlrl, uxlrl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W5_L(const NodePtr& u, embb_errors_t W5_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrr) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxrr, UniqueLock& uxrr_lock) {
NodePtr nxll = node_pool_.Allocate( NodePtr nxll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -682,25 +758,30 @@ bool W5_L(const NodePtr& u, ...@@ -682,25 +758,30 @@ bool W5_L(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrr); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxrr, uxrr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W5_R(const NodePtr& u, embb_errors_t W5_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxll) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxll, UniqueLock& uxll_lock) {
NodePtr nxrr = node_pool_.Allocate( NodePtr nxrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -726,25 +807,30 @@ bool W5_R(const NodePtr& u, ...@@ -726,25 +807,30 @@ bool W5_R(const NodePtr& u,
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxll); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxll, uxll_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W6_L(const NodePtr& u, embb_errors_t W6_L(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxrl) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxrl, UniqueLock& uxrl_lock) {
NodePtr nxll = node_pool_.Allocate( NodePtr nxll = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -770,25 +856,30 @@ bool W6_L(const NodePtr& u, ...@@ -770,25 +856,30 @@ bool W6_L(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxrl); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxrl, uxrl_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W6_R(const NodePtr& u, embb_errors_t W6_R(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr, HazardNodePtr& uxl, UniqueLock& uxl_lock,
const NodePtr& uxlr) { HazardNodePtr& uxr, UniqueLock& uxr_lock,
HazardNodePtr& uxlr, UniqueLock& uxlr_lock) {
NodePtr nxrr = node_pool_.Allocate( NodePtr nxrr = node_pool_.Allocate(
uxr->GetKey(), uxr->GetValue(), uxr->GetKey(), uxr->GetValue(),
uxr->GetWeight() - 1, uxr->GetWeight() - 1,
...@@ -814,24 +905,29 @@ bool W6_R(const NodePtr& u, ...@@ -814,24 +905,29 @@ bool W6_R(const NodePtr& u,
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
RetireNode(ux); assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
RetireNode(uxl); if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(uxr);
RetireNode(uxlr); RetireHazardousNode(ux, ux_lock);
RetireHazardousNode(uxl, uxl_lock);
return true; RetireHazardousNode(uxr, uxr_lock);
RetireHazardousNode(uxlr, uxlr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return EMBB_SUCCESS;
} }
bool W7(const NodePtr& u, embb_errors_t W7(
const NodePtr& ux, HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxl, HazardNodePtr& ux, UniqueLock& ux_lock,
const NodePtr& uxr) { HazardNodePtr& uxl, UniqueLock& uxl_lock,
HazardNodePtr& uxr, UniqueLock& uxr_lock) {
NodePtr nxl = node_pool_.Allocate( NodePtr nxl = node_pool_.Allocate(
uxl->GetKey(), uxl->GetValue(), uxl->GetKey(), uxl->GetValue(),
uxl->GetWeight() - 1, uxl->GetWeight() - 1,
...@@ -851,17 +947,21 @@ bool W7(const NodePtr& u, ...@@ -851,17 +947,21 @@ bool W7(const NodePtr& u,
if (nxl) FreeNode(nxl); if (nxl) FreeNode(nxl);
if (nxr) FreeNode(nxr); if (nxr) FreeNode(nxr);
if (nx) FreeNode(nx); if (nx) FreeNode(nx);
return false; return EMBB_NOMEM;
} }
NodePtr expected = ux; NodePtr expected = ux;
GetPointerToChild(u, ux).CompareAndSwap(expected, nx); bool rotation_succeeded = GetPointerToChild(u, ux)
.CompareAndSwap(expected, nx);
assert(rotation_succeeded); // For now (FGL tree) this CAS may not fail
if (!rotation_succeeded) return EMBB_BUSY;
RetireNode(ux); RetireHazardousNode(ux, ux_lock);
RetireNode(uxl); RetireHazardousNode(uxl, uxl_lock);
RetireNode(uxr); RetireHazardousNode(uxr, uxr_lock);
(void)u_lock; // For now (FGL tree) u_lock is not used here
return true; return EMBB_SUCCESS;
} }
#endif // EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_ #endif // EMBB_CONTAINERS_LOCK_FREE_CHROMATIC_TREE_REBALANCE_H_
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <stddef.h> #include <stddef.h>
#include <functional> #include <functional>
#include <embb/base/c/errors.h>
#include <embb/base/mutex.h> #include <embb/base/mutex.h>
#include <embb/containers/internal/hazard_pointer.h> #include <embb/containers/internal/hazard_pointer.h>
...@@ -70,6 +71,7 @@ class ChromaticTreeNode { ...@@ -70,6 +71,7 @@ class ChromaticTreeNode {
* *
* \param[IN] key Key of the new node * \param[IN] key Key of the new node
* \param[IN] value Value 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, const int weight = 1); ChromaticTreeNode(const Key& key, const Value& value, const int weight = 1);
...@@ -126,6 +128,75 @@ class ChromaticTreeNode { ...@@ -126,6 +128,75 @@ class ChromaticTreeNode {
embb::base::Mutex mutex_; embb::base::Mutex mutex_;
}; };
template<typename GuardedType>
class UniqueHazardGuard {
public:
typedef embb::base::Atomic<GuardedType> AtomicGuard;
UniqueHazardGuard(AtomicGuard& guard, const GuardedType& undefined_guard)
: guard_(guard),
undefined_guard_(undefined_guard),
active_(guard_.Load() == undefined_guard_) {}
~UniqueHazardGuard() {
if (active_) SetUndefinedGuard();
}
bool ProtectHazard(const AtomicGuard& hazard) {
// Read the hazard and store it into the guard
guard_ = hazard.Load();
// Check whether the guard is valid
active_ = (guard_.Load() == hazard.Load());
// Clear the guard if it is invalid
if (!active_) SetUndefinedGuard();
return active_;
}
bool IsActive() const {
return active_;
}
operator GuardedType () const {
assert(active_ == true);
return guard_.Load();
}
GuardedType operator->() const {
assert(active_ == true);
return guard_.Load();
}
void AdoptGuard(const UniqueHazardGuard<GuardedType>& other) {
guard_ = other.guard_.Load();
active_ = other.active_;
}
GuardedType ReleaseHazard() {
assert(active_ == true);
GuardedType released_hazard = guard_.Load();
SetUndefinedGuard();
active_ = false;
return released_hazard;
}
private:
void SetUndefinedGuard() {
guard_ = undefined_guard_;
}
// Non-copyable
UniqueHazardGuard(const UniqueHazardGuard<GuardedType>&);
UniqueHazardGuard<GuardedType>&
operator=(const UniqueHazardGuard<GuardedType>&);
AtomicGuard& guard_;
GuardedType undefined_guard_;
bool active_;
};
} // namespace internal } // namespace internal
namespace test { namespace test {
...@@ -301,29 +372,20 @@ class ChromaticTree { ...@@ -301,29 +372,20 @@ class ChromaticTree {
*/ */
typedef embb::base::Atomic<NodePtr> AtomicNodePtr; typedef embb::base::Atomic<NodePtr> AtomicNodePtr;
typedef internal::UniqueHazardGuard<NodePtr> HazardNodePtr;
typedef embb::base::UniqueLock<embb::base::Mutex> UniqueLock; typedef embb::base::UniqueLock<embb::base::Mutex> UniqueLock;
/** /**
* Follows a path from the root of the tree to some leaf searching for the * 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 * given key (the leaf found by this method may or may not contain the given
* key). Returns the reached leaf.
*
* \param[IN] key Key to be searched for
* \param[IN,OUT] leaf Reference to the reached leaf
*/
void Search(const Key& key, NodePtr& leaf);
/**
* 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. * key). Returns the reached leaf together with its ancestors.
* *
* \param[IN] key Key to be searched for * \param[IN] key Key to be searched for
* \param[IN,OUT] leaf Reference to the reached leaf * \param[IN,OUT] leaf Reference to the reached leaf
* \param[IN,OUT] parent Reference to the parent of the reached leaf * \param[IN,OUT] parent Reference to the parent of the reached leaf
*/ */
void Search(const Key& key, NodePtr& leaf, NodePtr& parent); void Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent);
/** /**
* Follows a path from the root of the tree to some leaf searching for the * Follows a path from the root of the tree to some leaf searching for the
...@@ -335,8 +397,8 @@ class ChromaticTree { ...@@ -335,8 +397,8 @@ class ChromaticTree {
* \param[IN,OUT] parent Reference to the parent of the reached leaf * \param[IN,OUT] parent Reference to the parent of the reached leaf
* \param[IN,OUT] grandparent Reference to the grandparent of the reached leaf * \param[IN,OUT] grandparent Reference to the grandparent of the reached leaf
*/ */
void Search(const Key& key, NodePtr& leaf, NodePtr& parent, void Search(const Key& key, HazardNodePtr& leaf, HazardNodePtr& parent,
NodePtr& grandparent); HazardNodePtr& grandparent);
/** /**
* Checks whether the given node is a leaf. * Checks whether the given node is a leaf.
...@@ -415,8 +477,11 @@ class ChromaticTree { ...@@ -415,8 +477,11 @@ class ChromaticTree {
bool IsBalanced() const; bool IsBalanced() const;
bool IsBalanced(const NodePtr& node) const; bool IsBalanced(const NodePtr& node) const;
void RemoveNode(const NodePtr& node) { void RetireHazardousNode(HazardNodePtr& node, UniqueLock& node_lock) {
node_hazard_manager_.EnqueuePointerForDeletion(node); node->Retire();
node_lock.Unlock();
NodePtr node_to_delete = node.ReleaseHazard();
node_hazard_manager_.EnqueuePointerForDeletion(node_to_delete);
} }
/** /**
...@@ -440,16 +505,22 @@ class ChromaticTree { ...@@ -440,16 +505,22 @@ class ChromaticTree {
/** /**
* Next block of methods is used internally to keep the balance of the tree. * Next block of methods is used internally to keep the balance of the tree.
*/ */
bool Rebalance(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, embb_errors_t Rebalance(HazardNodePtr& u, HazardNodePtr& ux,
const NodePtr& uxxx); HazardNodePtr& uxx, HazardNodePtr& uxxx);
bool OverweightLeft(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx,
const NodePtr& uxl, const NodePtr& uxr, embb_errors_t OverweightLeft(HazardNodePtr& u, UniqueLock& u_lock,
const NodePtr& uxxl, const NodePtr& uxxr, HazardNodePtr& ux, UniqueLock& ux_lock,
const bool& uxx_is_left); HazardNodePtr& uxx, UniqueLock& uxx_lock,
bool OverweightRight(const NodePtr& u, const NodePtr& ux, const NodePtr& uxx, HazardNodePtr& uxl, HazardNodePtr& uxr,
const NodePtr& uxl, const NodePtr& uxr, HazardNodePtr& uxxl, UniqueLock& uxxl_lock,
const NodePtr& uxxl, const NodePtr& uxxr, HazardNodePtr& uxxr, bool uxx_is_left);
const bool& uxx_is_right);
embb_errors_t OverweightRight(HazardNodePtr& u, UniqueLock& u_lock,
HazardNodePtr& ux, UniqueLock& ux_lock,
HazardNodePtr& uxx, UniqueLock& uxx_lock,
HazardNodePtr& uxl, HazardNodePtr& uxr,
HazardNodePtr& uxxl, HazardNodePtr& uxxr,
UniqueLock& uxxr_lock, bool uxx_is_right);
// The following included header contains the class methods implementing // The following included header contains the class methods implementing
// tree rotations. It is generated automatically and must be included // tree rotations. It is generated automatically and must be included
...@@ -466,7 +537,7 @@ class ChromaticTree { ...@@ -466,7 +537,7 @@ class ChromaticTree {
const Compare compare_; /**< Comparator object for the keys */ const Compare compare_; /**< Comparator object for the keys */
size_t capacity_; /**< User-requested capacity of the tree */ size_t capacity_; /**< User-requested capacity of the tree */
NodePool node_pool_; /**< Comparator object for the keys */ NodePool node_pool_; /**< Comparator object for the keys */
NodePtr entry_; /**< Pointer to the sentinel node used as AtomicNodePtr entry_; /**< Pointer to the sentinel node used as
* the entry point into the tree */ * the entry point into the tree */
/** /**
......
...@@ -66,11 +66,11 @@ TreeTest<Tree>::TreeTest() ...@@ -66,11 +66,11 @@ TreeTest<Tree>::TreeTest()
Add(&TreeTest::TreeTestConcurrentGet_ReaderMethod, this, Add(&TreeTest::TreeTestConcurrentGet_ReaderMethod, this,
NUM_TEST_THREADS / 2, NUM_ITERATIONS). NUM_TEST_THREADS / 2, NUM_ITERATIONS).
Post(&TreeTest::TreeTestConcurrentGet_Post, this); Post(&TreeTest::TreeTestConcurrentGet_Post, this);
// CreateUnit("TreeTestBalance"). CreateUnit("TreeTestBalance").
// Pre(&TreeTest::TreeTestBalance_Pre, this). Pre(&TreeTest::TreeTestBalance_Pre, this).
// Add(&TreeTest::TreeTestBalance_ThreadMethod, this, Add(&TreeTest::TreeTestBalance_ThreadMethod, this,
// NUM_TEST_THREADS, 1). NUM_TEST_THREADS, 1).
// Post(&TreeTest::TreeTestBalance_Post, this); Post(&TreeTest::TreeTestBalance_Post, this);
} }
template<typename Tree> template<typename Tree>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment