EllenBinTree doc fixed
[libcds.git] / cds / intrusive / impl / ellen_bintree.h
index 06baed3b76aa96302e40f053020742c148fc1f36..21fd7c29396754ab683316bf9c9e6d5c1e014238 100644 (file)
@@ -1,14 +1,13 @@
 //$$CDS-header$$
 
-#ifndef __CDS_INTRUSIVE_IMPL_ELLEN_BINTREE_H
-#define __CDS_INTRUSIVE_IMPL_ELLEN_BINTREE_H
+#ifndef CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
+#define CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H
 
 #include <memory>
 #include <cds/intrusive/details/ellen_bintree_base.h>
 #include <cds/opt/compare.h>
 #include <cds/details/binary_functor_wrapper.h>
 #include <cds/urcu/details/check_deadlock.h>
-#include <cds/gc/guarded_ptr.h>
 
 namespace cds { namespace intrusive {
 
@@ -34,17 +33,17 @@ namespace cds { namespace intrusive {
         the priority value plus some uniformly distributed random value.
 
         @note In the current implementation we do not use helping technique described in the original paper.
-        In Hazard Pointer schema helping is too complicated and does not give any observable benefits.
+        In Hazard Pointer schema the helping is too complicated and does not give any observable benefits.
         Instead of helping, when a thread encounters a concurrent operation it just spins waiting for
-        the operation done. Such solution allows greatly simplify the implementation of tree.
+        the operation done. Such solution allows greatly simplify implementation of the tree.
 
-        @warning Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
+        @attention Recall the tree is <b>unbalanced</b>. The complexity of operations is <tt>O(log N)</tt>
         for uniformly distributed random keys, but in worst case the complexity is <tt>O(N)</tt>.
 
         @note Do not include <tt><cds/intrusive/impl/ellen_bintree.h></tt> header file explicitly.
         There are header file for each GC type:
         - <tt><cds/intrusive/ellen_bintree_hp.h></tt> - for Hazard Pointer GC \p cds::gc::HP
-        - <tt><cds/intrusive/ellen_bintree_dhp.h></tt> - for Pass-the-Buck GC \p cds::gc::DHP
+        - <tt><cds/intrusive/ellen_bintree_dhp.h></tt> - for Dynamic Hazard Pointer GC \p cds::gc::DHP
         - <tt><cds/intrusive/ellen_bintree_rcu.h></tt> - for RCU (see \ref cds_intrusive_EllenBinTree_rcu "RCU-based EllenBinTree")
 
         <b>Template arguments</b> :
@@ -117,8 +116,9 @@ namespace cds { namespace intrusive {
         typedef typename traits::hook      hook;        ///< hook type
         typedef typename hook::node_type   node_type;   ///< node type
         typedef typename traits::disposer  disposer;    ///< leaf node disposer
+        typedef typename traits::back_off  back_off;    ///< back-off strategy
 
-        typedef cds::gc::guarded_ptr< gc, value_type > guarded_ptr; ///< Guarded pointer
+        typedef typename gc::template guarded_ptr< value_type > guarded_ptr; ///< Guarded pointer
 
     protected:
         //@cond
@@ -160,6 +160,8 @@ namespace cds { namespace intrusive {
         typedef typename traits::node_allocator        node_allocator;        ///< Allocator for internal node
         typedef typename traits::update_desc_allocator update_desc_allocator; ///< Update descriptor allocator
 
+        static CDS_CONSTEXPR const size_t c_nHazardPtrCount = 9; ///< Count of hazard pointer required for the algorithm
+
     protected:
         //@cond
         typedef ellen_bintree::details::compare< key_type, value_type, key_comparator, node_traits > node_compare;
@@ -174,9 +176,7 @@ namespace cds { namespace intrusive {
                 Guard_Leaf,
                 Guard_updGrandParent,
                 Guard_updParent,
-
-                // helping
-                Guard_helpLeaf,
+                Guard_temporary,
 
                 // end of guard indices
                 guard_count
@@ -200,11 +200,6 @@ namespace cds { namespace intrusive {
                 ,bRightLeaf( false )
                 ,bRightParent( false )
             {}
-
-            void clean_help_guards()
-            {
-                guards.clear( Guard_helpLeaf );
-            }
         };
         //@endcond
 
@@ -339,8 +334,9 @@ namespace cds { namespace intrusive {
             guardInsert.assign( &val );
 
             unique_internal_node_ptr pNewInternal;
-
             search_result res;
+            back_off bkoff;
+
             for ( ;; ) {
                 if ( search( res, val, node_compare() )) {
                     if ( pNewInternal.get() )
@@ -361,6 +357,7 @@ namespace cds { namespace intrusive {
                     }
                 }
 
+                bkoff();
                 m_Stat.onInsertRetry();
             }
 
@@ -369,20 +366,21 @@ namespace cds { namespace intrusive {
             return true;
         }
 
-        /// Ensures that the \p val exists in the tree
+        /// Updates the node
         /**
             The operation performs inserting or changing data with lock-free manner.
 
-            If the item \p val is not found in the tree, then \p val is inserted into the tree.
+            If the item \p val is not found in the set, then \p val is inserted into the set
+            iff \p bAllowInsert is \p true.
             Otherwise, the functor \p func is called with item found.
-            The functor signature is:
+            The functor \p func signature is:
             \code
                 void func( bool bNew, value_type& item, value_type& val );
             \endcode
             with arguments:
             - \p bNew - \p true if the item has been inserted, \p false otherwise
-            - \p item - an item of the tree
-            - \p val - the argument \p val passed to the \p ensure function
+            - \p item - item of the set
+            - \p val - argument \p val passed into the \p %update() function
             If new item has been inserted (i.e. \p bNew is \p true) then \p item and \p val arguments
             refer to the same thing.
 
@@ -390,20 +388,22 @@ namespace cds { namespace intrusive {
             that during changing no any other modifications could be made on this item by concurrent threads.
 
             Returns std::pair<bool, bool> where \p first is \p true if operation is successfull,
+            i.e. the node has been inserted or updated,
             \p second is \p true if new item has been added or \p false if the item with \p key
-            already is in the tree.
+            already exists.
 
             @warning See \ref cds_intrusive_item_creating "insert item troubleshooting"
         */
         template <typename Func>
-        std::pair<bool, bool> ensure( value_type& val, Func func )
+        std::pair<bool, bool> update( value_type& val, Func func, bool bAllowInsert = true )
         {
             typename gc::Guard guardInsert;
             guardInsert.assign( &val );
 
             unique_internal_node_ptr pNewInternal;
-
             search_result res;
+            back_off bkoff;
+
             for ( ;; ) {
                 if ( search( res, val, node_compare() )) {
                     func( false, *node_traits::to_value_ptr( res.pLeaf ), val );
@@ -414,6 +414,8 @@ namespace cds { namespace intrusive {
                 }
 
                 if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean )  {
+                    if ( !bAllowInsert )
+                        return std::make_pair( false, false );
 
                     if ( !pNewInternal.get() )
                         pNewInternal.reset( alloc_internal_node() );
@@ -424,6 +426,8 @@ namespace cds { namespace intrusive {
                         break;
                     }
                 }
+
+                bkoff();
                 m_Stat.onEnsureRetry();
             }
 
@@ -431,6 +435,14 @@ namespace cds { namespace intrusive {
             m_Stat.onEnsureNew();
             return std::make_pair( true, true );
         }
+        //@cond
+        template <typename Func>
+        CDS_DEPRECATED("ensure() is deprecated, use update()")
+        std::pair<bool, bool> ensure( value_type& val, Func func )
+        {
+            return update( val, func, true );
+        }
+        //@endcond
 
         /// Unlinks the item \p val from the tree
         /**
@@ -480,6 +492,7 @@ namespace cds { namespace intrusive {
         template <typename Q, typename Less>
         bool erase_with( const Q& key, Less pred )
         {
+            CDS_UNUSED( pred );
             typedef ellen_bintree::details::compare<
                 key_type,
                 value_type,
@@ -529,6 +542,7 @@ namespace cds { namespace intrusive {
         template <typename Q, typename Less, typename Func>
         bool erase_with( Q const& key, Less pred, Func f )
         {
+            CDS_UNUSED( pred );
             typedef ellen_bintree::details::compare<
                 key_type,
                 value_type,
@@ -543,82 +557,87 @@ namespace cds { namespace intrusive {
 
         /// Extracts an item with minimal key from the tree
         /**
-            The function searches an item with minimal key, unlinks it, and returns pointer to an item found in \p dest parameter.
-            If the tree is empty the function returns \p false.
+            The function searches an item with minimal key, unlinks it, and returns a guarded pointer to an item found.
+            If the tree is empty the function returns an empty guarded pointer.
 
             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> minimum key.
             It means that the function gets leftmost leaf of the tree and tries to unlink it.
             During unlinking, a concurrent thread may insert an item with key less than leftmost item's key.
             So, the function returns the item with minimum key at the moment of tree traversing.
 
-            The guarded pointer \p dest prevents disposer invocation for returned item,
-            see cds::gc::guarded_ptr for explanation.
+            The returned \p guarded_ptr prevents disposer invocation for returned item,
+            see \p cds::gc::guarded_ptr for explanation.
             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
         */
-        bool extract_min( guarded_ptr& dest )
+        guarded_ptr extract_min()
         {
-            return extract_min_( dest.guard());
+            guarded_ptr gp;
+            extract_min_( gp.guard() );
+            return gp;
         }
 
         /// Extracts an item with maximal key from the tree
         /**
-            The function searches an item with maximal key, unlinks it, and returns pointer to an item found in \p dest parameter.
-            If the tree is empty the function returns \p false.
+            The function searches an item with maximal key, unlinks it, and returns a guarded pointer to an item found.
+            If the tree is empty the function returns an empty \p guarded_ptr.
 
             @note Due the concurrent nature of the tree, the function extracts <i>nearly</i> maximal key.
             It means that the function gets rightmost leaf of the tree and tries to unlink it.
             During unlinking, a concurrent thread may insert an item with key great than rightmost item's key.
             So, the function returns the item with maximal key at the moment of tree traversing.
 
-            The guarded pointer \p dest prevents disposer invocation for returned item,
+            The returned \p guarded_ptr prevents disposer invocation for returned item,
             see cds::gc::guarded_ptr for explanation.
             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
         */
-        bool extract_max( guarded_ptr& dest )
+        guarded_ptr extract_max()
         {
-            return extract_max_( dest.guard() );
+            guarded_ptr gp;
+            extract_max_( gp.guard());
+            return gp;
         }
 
         /// Extracts an item from the tree
         /** \anchor cds_intrusive_EllenBinTree_extract
             The function searches an item with key equal to \p key in the tree,
-            unlinks it, and returns pointer to an item found in \p dest parameter.
-            If the item  is not found the function returns \p false.
+            unlinks it, and returns a guarded pointer to an item found.
+            If the item  is not found the function returns an empty \p guarded_ptr.
 
-            The guarded pointer \p dest prevents disposer invocation for returned item,
+            \p guarded_ptr prevents disposer invocation for returned item,
             see cds::gc::guarded_ptr for explanation.
             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
         */
         template <typename Q>
-        bool extract( guarded_ptr& dest, Q const& key )
+        guarded_ptr extract( Q const& key )
         {
-            return extract_( dest.guard(), key );
+            guarded_ptr gp;
+            extract_( gp.guard(), key );
+            return gp;
         }
 
         /// Extracts an item from the tree using \p pred for searching
         /**
-            The function is an analog of \ref cds_intrusive_EllenBinTree_extract "extract(guarded_ptr& dest, Q const&)"
+            The function is an analog of \ref cds_intrusive_EllenBinTree_extract "extract(Q const&)"
             but \p pred is used for key compare.
             \p Less has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
             "Predicate requirements".
             \p pred must imply the same element order as the comparator used for building the tree.
         */
         template <typename Q, typename Less>
-        bool extract_with( guarded_ptr& dest, Q const& key, Less pred )
+        guarded_ptr extract_with( Q const& key, Less pred )
         {
-            return extract_with_( dest.guard(), key, pred );
+            guarded_ptr gp;
+            extract_with_( gp.guard(), key, pred );
+            return gp;
         }
 
-        /// Finds the key \p key
-        /** @anchor cds_intrusive_EllenBinTree_find_val
+        /// Checks whether the set contains \p key
+        /**
             The function searches the item with key equal to \p key
             and returns \p true if it is found, and \p false otherwise.
-
-            Note the hash functor specified for class \p Traits template parameter
-            should accept a parameter of type \p Q that can be not the same as \p value_type.
         */
         template <typename Q>
-        bool find( Q const& key ) const
+        bool contains( Q const& key ) const
         {
             search_result    res;
             if ( search( res, key, node_compare() )) {
@@ -629,19 +648,25 @@ namespace cds { namespace intrusive {
             m_Stat.onFindFailed();
             return false;
         }
+        //@cond
+        template <typename Q>
+        CDS_DEPRECATED("deprecated, use contains()")
+        bool find( Q const& key ) const
+        {
+            return contains( key );
+        }
+        //@endcond
 
-        /// Finds the key \p key with comparing functor \p pred
+        /// Checks whether the set contains \p key using \p pred predicate for searching
         /**
-            The function is an analog of \ref cds_intrusive_EllenBinTree_find_val "find(Q const&)"
-            but \p pred is used for key compare.
-            \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
-            "Predicate requirements".
-            \p pred must imply the same element order as the comparator used for building the tree.
-            \p pred should accept arguments of type \p Q, \p key_type, \p value_type in any combination.
+            The function is similar to <tt>contains( key )</tt> but \p pred is used for key comparing.
+            \p Less functor has the interface like \p std::less.
+            \p Less must imply the same element order as the comparator used for building the set.
         */
         template <typename Q, typename Less>
-        bool find_with( Q const& key, Less pred ) const
+        bool contains( Q const& key, Less pred ) const
         {
+            CDS_UNUSED( pred );
             typedef ellen_bintree::details::compare<
                 key_type,
                 value_type,
@@ -657,6 +682,14 @@ namespace cds { namespace intrusive {
             m_Stat.onFindFailed();
             return false;
         }
+        //@cond
+        template <typename Q, typename Less>
+        CDS_DEPRECATED("deprecated, use contains()")
+        bool find_with( Q const& key, Less pred ) const
+        {
+            return contains( key, pred );
+        }
+        //@endcond
 
         /// Finds the key \p key
         /** @anchor cds_intrusive_EllenBinTree_find_func
@@ -712,31 +745,35 @@ namespace cds { namespace intrusive {
 
         /// Finds \p key and returns the item found
         /** @anchor cds_intrusive_EllenBinTree_get
-            The function searches the item with key equal to \p key and returns the item found in \p dest parameter.
-            The function returns \p true if \p key is found, \p false otherwise.
+            The function searches the item with key equal to \p key and returns the item found as \p guarded_ptr object.
+            The function returns an empty guarded pointer is \p key is not found.
 
-            The guarded pointer \p dest prevents disposer invocation for returned item,
-            see cds::gc::guarded_ptr for explanation.
+            \p guarded_ptr prevents disposer invocation for returned item,
+            see \p cds::gc::guarded_ptr for explanation.
             @note Each \p guarded_ptr object uses the GC's guard that can be limited resource.
         */
         template <typename Q>
-        bool get( guarded_ptr& dest, Q const& key ) const
+        guarded_ptr get( Q const& key ) const
         {
-            return get_( dest.guard(), key );
+            guarded_ptr gp;
+            get_( gp.guard(), key );
+            return gp;
         }
 
         /// Finds \p key with predicate \p pred and returns the item found
         /**
-            The function is an analog of \ref cds_intrusive_EllenBinTree_get "get(guarded_ptr&, Q const&)"
+            The function is an analog of \ref cds_intrusive_EllenBinTree_get "get(Q const&)"
             but \p pred is used for key comparing.
             \p Less functor has the interface like \p std::less and should meet \ref cds_intrusive_EllenBinTree_less
             "Predicate requirements".
             \p pred must imply the same element order as the comparator used for building the tree.
         */
         template <typename Q, typename Less>
-        bool get_with( guarded_ptr& dest, Q const& key, Less pred ) const
+        guarded_ptr get_with( Q const& key, Less pred ) const
         {
-            return get_with_( dest.guard(), key, pred );
+            guarded_ptr gp;
+            get_with_( gp.guard(), key, pred );
+            return gp;
         }
 
         /// Checks if the tree is empty
@@ -761,7 +798,9 @@ namespace cds { namespace intrusive {
         void clear()
         {
             guarded_ptr gp;
-            while ( extract_min(gp));
+            do {
+                gp = extract_min();
+            }  while ( gp );
         }
 
         /// Clears the tree (not thread safe)
@@ -858,14 +897,21 @@ namespace cds { namespace intrusive {
 
         tree_node * protect_child_node( search_result& res, internal_node * pParent, bool bRight, update_ptr updParent ) const
         {
-            tree_node * p;
-            tree_node * pn = bRight ? pParent->m_pRight.load( memory_model::memory_order_relaxed ) : pParent->m_pLeft.load( memory_model::memory_order_relaxed );
-            do {
-                p = pn;
-                res.guards.assign( search_result::Guard_Leaf, static_cast<internal_node *>( p ));
-                res.guards.assign( search_result::Guard_helpLeaf, node_traits::to_value_ptr( static_cast<leaf_node *>( p ) ));
-                pn = bRight ? pParent->m_pRight.load( memory_model::memory_order_acquire ) : pParent->m_pLeft.load( memory_model::memory_order_acquire );
-            } while ( p != pn );
+        retry:
+            tree_node * p = bRight
+                ? res.guards.protect( search_result::Guard_Leaf, pParent->m_pRight,
+                    []( tree_node * p ) -> internal_node* { return static_cast<internal_node *>(p);})
+                : res.guards.protect( search_result::Guard_Leaf, pParent->m_pLeft,
+                    []( tree_node * p ) -> internal_node* { return static_cast<internal_node *>(p);});
+
+            // If we use member hook, data node pointer != internal node pointer
+            // So, we need protect the child twice: as internal node and as data node
+            // and then analyze what kind of node we have
+            tree_node * pVal = bRight
+                ? res.guards.protect( search_result::Guard_temporary, pParent->m_pRight,
+                    []( tree_node * p ) -> value_type* { return node_traits::to_value_ptr( static_cast<leaf_node *>(p));} )
+                : res.guards.protect( search_result::Guard_temporary, pParent->m_pLeft,
+                    []( tree_node * p ) -> value_type* { return node_traits::to_value_ptr( static_cast<leaf_node *>(p));} );
 
             // child node is guarded
             // See whether pParent->m_pUpdate has not been changed
@@ -874,21 +920,20 @@ namespace cds { namespace intrusive {
                 return nullptr;
             }
 
-            if ( p && p->is_leaf() )
-                res.guards.copy( search_result::Guard_Leaf, search_result::Guard_helpLeaf );
-            res.guards.clear( search_result::Guard_helpLeaf );
+            if ( p != pVal )
+                goto retry;
+
+            if ( p && p->is_leaf())
+                res.guards.assign( search_result::Guard_Leaf, node_traits::to_value_ptr( static_cast<leaf_node *>( p )));
+
+            res.guards.clear( search_result::Guard_temporary );
+
             return p;
         }
 
-        update_ptr search_protect_update( search_result& res, atomics::atomic<update_ptr> const& src ) const
+        static update_ptr search_protect_update( search_result& res, atomics::atomic<update_ptr> const& src )
         {
-            update_ptr ret;
-            update_ptr upd( src.load( memory_model::memory_order_relaxed ) );
-            do {
-                ret = upd;
-                res.guards.assign( search_result::Guard_updParent, upd );
-            } while ( ret != (upd = src.load( memory_model::memory_order_acquire )) );
-            return ret;
+            return res.guards.protect( search_result::Guard_updParent, src, [](update_ptr p) -> update_desc* { return p.ptr(); });
         }
 
         template <typename KeyValue, typename Compare>
@@ -1058,6 +1103,7 @@ namespace cds { namespace intrusive {
             return true;
         }
 
+        /*
         void help( update_ptr pUpdate )
         {
             // pUpdate must be guarded!
@@ -1076,6 +1122,7 @@ namespace cds { namespace intrusive {
                     break;
             }
         }
+        */
 
         void help_insert( update_desc * pOp )
         {
@@ -1103,18 +1150,8 @@ namespace cds { namespace intrusive {
 
             assert( res.pGrandParent != nullptr );
 
-            return
-                static_cast<internal_node *>(
-                    res.bRightParent
-                        ? res.pGrandParent->m_pRight.load(memory_model::memory_order_relaxed)
-                        : res.pGrandParent->m_pLeft.load(memory_model::memory_order_relaxed)
-                    ) == res.pParent
-                &&
-                static_cast<leaf_node *>(
-                    res.bRightLeaf
-                        ? res.pParent->m_pRight.load(memory_model::memory_order_relaxed)
-                        : res.pParent->m_pLeft.load(memory_model::memory_order_relaxed)
-                ) == res.pLeaf;
+            return static_cast<internal_node *>(res.pGrandParent->get_child( res.bRightParent, memory_model::memory_order_relaxed )) == res.pParent
+                && static_cast<leaf_node *>( res.pParent->get_child( res.bRightLeaf, memory_model::memory_order_relaxed )) == res.pLeaf;
         }
 
         bool help_delete( update_desc * pOp )
@@ -1151,21 +1188,11 @@ namespace cds { namespace intrusive {
             }
         }
 
-        tree_node * protect_sibling( typename gc::Guard& guard, atomics::atomic<tree_node *>& sibling )
+        static tree_node * protect_sibling( typename gc::Guard& guard, atomics::atomic<tree_node *>& sibling )
         {
-            typename gc::Guard guardLeaf;
-
-            tree_node * pSibling;
-            tree_node * p = sibling.load( memory_model::memory_order_relaxed );
-            do {
-                pSibling = p;
-                guard.assign( static_cast<internal_node *>(p) );
-                guardLeaf.assign( node_traits::to_value_ptr( static_cast<leaf_node *>(p)));
-            } while ( pSibling != ( p = sibling.load( memory_model::memory_order_acquire )) );
-
+            tree_node * pSibling = guard.protect( sibling, [](tree_node * p) -> internal_node* { return static_cast<internal_node *>(p); } );
             if ( pSibling->is_leaf() )
-                guard.copy( guardLeaf );
-
+                guard.assign( node_traits::to_value_ptr( static_cast<leaf_node *>( pSibling )));
             return pSibling;
         }
 
@@ -1198,18 +1225,15 @@ namespace cds { namespace intrusive {
             assert( res.pLeaf->is_leaf() );
 
             // check search result
-            if ( ( res.bRightLeaf
-                ? res.pParent->m_pRight.load( memory_model::memory_order_acquire )
-                : res.pParent->m_pLeft.load( memory_model::memory_order_acquire ) ) == res.pLeaf )
-            {
+            if ( res.pParent->get_child( res.bRightLeaf, memory_model::memory_order_acquire ) == res.pLeaf ) {
                 leaf_node * pNewLeaf = node_traits::to_node_ptr( val );
 
-                int nCmp = node_compare()( val, *res.pLeaf );
+                int nCmp = node_compare()(val, *res.pLeaf);
                 if ( nCmp < 0 ) {
                     if ( res.pGrandParent ) {
                         assert( !res.pLeaf->infinite_key() );
                         pNewInternal->infinite_key( 0 );
-                        key_extractor()( pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ) );
+                        key_extractor()(pNewInternal->m_Key, *node_traits::to_value_ptr( res.pLeaf ));
                     }
                     else {
                         assert( res.pLeaf->infinite_key() == tree_node::key_infinite1 );
@@ -1220,12 +1244,12 @@ namespace cds { namespace intrusive {
                 }
                 else {
                     assert( !res.pLeaf->is_internal() );
-                    pNewInternal->infinite_key( 0 );
 
-                    key_extractor()( pNewInternal->m_Key, val );
+                    pNewInternal->infinite_key( 0 );
+                    key_extractor()(pNewInternal->m_Key, val);
                     pNewInternal->m_pLeft.store( static_cast<tree_node *>(res.pLeaf), memory_model::memory_order_relaxed );
                     pNewInternal->m_pRight.store( static_cast<tree_node *>(pNewLeaf), memory_model::memory_order_release );
-                    assert( !res.pLeaf->infinite_key());
+                    assert( !res.pLeaf->infinite_key() );
                 }
 
                 typename gc::Guard guard;
@@ -1239,8 +1263,7 @@ namespace cds { namespace intrusive {
 
                 update_ptr updCur( res.updParent.ptr() );
                 if ( res.pParent->m_pUpdate.compare_exchange_strong( updCur, update_ptr( pOp, update_desc::IFlag ),
-                    memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
-                {
+                    memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
                     // do insert
                     help_insert( pOp );
                     retire_update_desc( pOp );
@@ -1251,6 +1274,7 @@ namespace cds { namespace intrusive {
                     free_update_desc( pOp );
                 }
             }
+
             return false;
         }
 
@@ -1259,6 +1283,7 @@ namespace cds { namespace intrusive {
         {
             update_desc * pOp = nullptr;
             search_result res;
+            back_off bkoff;
 
             for ( ;; ) {
                 if ( !search( res, val, cmp ) || !eq( val, *res.pLeaf ) ) {
@@ -1284,11 +1309,10 @@ namespace cds { namespace intrusive {
 
                         update_ptr updGP( res.updGrandParent.ptr() );
                         if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
-                            memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
-                        {
-                            if ( help_delete( pOp )) {
+                            memory_model::memory_order_acquire, atomics::memory_order_relaxed ) ) {
+                            if ( help_delete( pOp ) ) {
                                 // res.pLeaf is not deleted yet since it is guarded
-                                f( *node_traits::to_value_ptr( res.pLeaf ));
+                                f( *node_traits::to_value_ptr( res.pLeaf ) );
                                 break;
                             }
                             pOp = nullptr;
@@ -1296,6 +1320,7 @@ namespace cds { namespace intrusive {
                     }
                 }
 
+                bkoff();
                 m_Stat.onEraseRetry();
             }
 
@@ -1305,15 +1330,15 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q>
-        bool extract_( typename gc::Guard& guard, Q const& key )
+        bool extract_( typename guarded_ptr::native_guard& guard, Q const& key )
         {
             return erase_( key, node_compare(),
                 []( Q const&, leaf_node const& ) -> bool { return true; },
-                [&guard]( value_type& found ) { guard.assign( &found ); } );
+                [&guard]( value_type& found ) { guard.set( &found ); } );
         }
 
         template <typename Q, typename Less>
-        bool extract_with_( typename gc::Guard& guard, Q const& key, Less pred )
+        bool extract_with_( typename guarded_ptr::native_guard& guard, Q const& key, Less /*pred*/ )
         {
             typedef ellen_bintree::details::compare<
                 key_type,
@@ -1324,13 +1349,14 @@ namespace cds { namespace intrusive {
 
             return erase_( key, compare_functor(),
                 []( Q const&, leaf_node const& ) -> bool { return true; },
-                [&guard]( value_type& found ) { guard.assign( &found ); } );
+                [&guard]( value_type& found ) { guard.set( &found ); } );
         }
 
-        bool extract_max_( typename gc::Guard& guard )
+        bool extract_max_( typename guarded_ptr::native_guard& gp )
         {
             update_desc * pOp = nullptr;
             search_result res;
+            back_off bkoff;
 
             for ( ;; ) {
                 if ( !search_max( res )) {
@@ -1341,7 +1367,7 @@ namespace cds { namespace intrusive {
                     return false;
                 }
 
-                if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean )  {
+                if ( res.updGrandParent.bits() == update_desc::Clean && res.updParent.bits() == update_desc::Clean ) {
                     if ( !pOp )
                         pOp = alloc_update_desc();
                     if ( check_delete_precondition( res ) ) {
@@ -1357,28 +1383,30 @@ namespace cds { namespace intrusive {
 
                         update_ptr updGP( res.updGrandParent.ptr() );
                         if ( res.pGrandParent->m_pUpdate.compare_exchange_strong( updGP, update_ptr( pOp, update_desc::DFlag ),
-                            memory_model::memory_order_acquire, atomics::memory_order_relaxed ))
+                                memory_model::memory_order_acquire, atomics::memory_order_relaxed ) )
                         {
-                            if ( help_delete( pOp ))
+                            if ( help_delete( pOp ) )
                                 break;
                             pOp = nullptr;
                         }
                     }
                 }
 
+                bkoff();
                 m_Stat.onExtractMaxRetry();
             }
 
             --m_ItemCounter;
             m_Stat.onExtractMaxSuccess();
-            guard.assign( node_traits::to_value_ptr( res.pLeaf ) );
+            gp.set( node_traits::to_value_ptr( res.pLeaf ));
             return true;
         }
 
-        bool extract_min_( typename gc::Guard& guard )
+        bool extract_min_( typename guarded_ptr::native_guard& gp )
         {
             update_desc * pOp = nullptr;
             search_result res;
+            back_off bkoff;
 
             for ( ;; ) {
                 if ( !search_min( res )) {
@@ -1414,12 +1442,13 @@ namespace cds { namespace intrusive {
                     }
                 }
 
+                bkoff();
                 m_Stat.onExtractMinRetry();
             }
 
             --m_ItemCounter;
             m_Stat.onExtractMinSuccess();
-            guard.assign( node_traits::to_value_ptr( res.pLeaf ));
+            gp.set( node_traits::to_value_ptr( res.pLeaf ));
             return true;
         }
 
@@ -1440,7 +1469,7 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q, typename Less, typename Func>
-        bool find_with_( Q& val, Less pred, Func f ) const
+        bool find_with_( Q& val, Less /*pred*/, Func f ) const
         {
             typedef ellen_bintree::details::compare<
                 key_type,
@@ -1463,15 +1492,15 @@ namespace cds { namespace intrusive {
         }
 
         template <typename Q>
-        bool get_( typename gc::Guard& guard, Q const& val ) const
+        bool get_( typename guarded_ptr::native_guard& guard, Q const& val ) const
         {
-            return find_( val, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } );
+            return find_( val, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
         }
 
         template <typename Q, typename Less>
-        bool get_with_( typename gc::Guard& guard, Q const& val, Less pred ) const
+        bool get_with_( typename guarded_ptr::native_guard& guard, Q const& val, Less pred ) const
         {
-            return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.assign( &found ); } );
+            return find_with_( val, pred, [&guard]( value_type& found, Q const& ) { guard.set( &found ); } );
         }
 
         //@endcond
@@ -1479,4 +1508,4 @@ namespace cds { namespace intrusive {
 
 }} // namespace cds::intrusive
 
-#endif // #ifndef __CDS_INTRUSIVE_IMPL_ELLEN_BINTREE_H
+#endif // #ifndef CDSLIB_INTRUSIVE_IMPL_ELLEN_BINTREE_H