Fixed BronsonAVLTree insert/update bug (incomplete)
authorkhizmax <khizmax@gmail.com>
Fri, 3 Apr 2015 15:52:01 +0000 (18:52 +0300)
committerkhizmax <khizmax@gmail.com>
Fri, 3 Apr 2015 15:52:01 +0000 (18:52 +0300)
cds/container/details/bronson_avltree_base.h
cds/container/impl/bronson_avltree_map_rcu.h
tests/unit/print_bronsonavltree_stat.h

index 349e36ed3c7904ac853c076c055cff629d63331c..ea2757d97e318182c782b8714f09bea0cd5d6a5f 100644 (file)
@@ -181,6 +181,7 @@ namespace cds { namespace container {
             event_counter   m_nFindWaitShrinking;   ///< Count of waiting until shrinking completed duting \p find() call
 
             event_counter   m_nInsertSuccess;       ///< Count of inserting data node
+            event_counter   m_nInsertFailed;        ///< Count of insert failures
             event_counter   m_nRelaxedInsertFailed; ///< Count of false creating of data nodes (only if @ref bronson_avltree::relaxed_insert "relaxed insertion" is enabled)
             event_counter   m_nInsertRetry;         ///< Count of insert retries via concurrent operations
             event_counter   m_nUpdateWaitShrinking; ///< Count of waiting until shrinking completed during \p update() call
@@ -222,7 +223,8 @@ namespace cds { namespace container {
             void onFindRetry()          { ++m_nFindRetry        ; }
             void onFindWaitShrinking()  { ++m_nFindWaitShrinking; }
 
-            void onInsertSuccess()          { ++m_nInsertSuccess    ; }
+            void onInsertSuccess()          { ++m_nInsertSuccess; }
+            void onInsertFailed()           { ++m_nInsertFailed; }
             void onRelaxedInsertFailed()    { ++m_nRelaxedInsertFailed; }
             void onInsertRetry()            { ++m_nInsertRetry      ; }
             void onUpdateWaitShrinking()    { ++m_nUpdateWaitShrinking; }
@@ -269,6 +271,7 @@ namespace cds { namespace container {
             void onFindWaitShrinking()  const {}
 
             void onInsertSuccess()          const {}
+            void onInsertFailed()           const {}
             void onRelaxedInsertFailed()    const {}
             void onInsertRetry()            const {}
             void onUpdateWaitShrinking()    const {}
index 13347c5b86ea5c484f9148219bc0385f21701a52..36449e81c04e6f9903bfc54d7d7bca17e0f5c062 100644 (file)
@@ -1086,11 +1086,8 @@ namespace cds { namespace container {
             assert( nVersion != node_type::unlinked );
 
             int nCmp = cmp( key, pNode->m_key );
-            if ( nCmp == 0 ) {
-                if ( nFlags & update_flags::allow_update )
-                    return try_update_node( funcUpdate, pNode, nVersion, disp );
-                return update_flags::failed;
-            }
+            if ( nCmp == 0 )
+                return try_update_node( nFlags, funcUpdate, pNode, nVersion, disp );
 
             while ( true ) {
                 int result;
@@ -1313,7 +1310,7 @@ namespace cds { namespace container {
         }
 
         template <typename Func>
-        int try_update_node( Func funcUpdate, node_type * pNode, version_type nVersion, rcu_disposer& disp )
+        int try_update_node( int nFlags, Func funcUpdate, node_type * pNode, version_type nVersion, rcu_disposer& disp )
         {
             mapped_type pOld;
             assert( pNode != nullptr );
@@ -1328,6 +1325,12 @@ namespace cds { namespace container {
                     return update_flags::retry;
                 }
 
+                if ( pNode->is_valued( memory_model::memory_order_relaxed ) && !(nFlags & update_flags::allow_update) ) {
+                    m_stat.onInsertFailed();
+                    return update_flags::failed;
+                }
+
+
                 pOld = pNode->value( memory_model::memory_order_relaxed );
                 mapped_type pVal = funcUpdate( pNode );
                 if ( pVal == pOld )
index 1a1d39d7749c5edb81b3a05bb4d18b7030196562..e1c6996c790d6146d7a3268477704bb33cf868d2 100644 (file)
@@ -20,6 +20,7 @@ namespace std {
             << "\t\t               m_nFindRetry: " << s.m_nFindRetry.get()           << "\n"
             << "\t\t       m_nFindWaitShrinking: " << s.m_nFindWaitShrinking.get()   << "\n"
             << "\t\t           m_nInsertSuccess: " << s.m_nInsertSuccess.get()       << "\n"
+            << "\t\t            m_nInsertFailed: " << s.m_nInsertFailed.get()        << "\n"
             << "\t\t     m_nRelaxedInsertFailed: " << s.m_nRelaxedInsertFailed.get() << "\n"
             << "\t\t             m_nInsertRetry: " << s.m_nInsertRetry.get()         << "\n"
             << "\t\t     m_nUpdateWaitShrinking: " << s.m_nUpdateWaitShrinking.get() << "\n"