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.
......
...@@ -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