Fixed max bucket count error in SplitList
authorkhizmax <libcds.dev@gmail.com>
Fri, 24 Apr 2015 19:57:13 +0000 (22:57 +0300)
committerkhizmax <libcds.dev@gmail.com>
Fri, 24 Apr 2015 19:57:13 +0000 (22:57 +0300)
cds/intrusive/split_list.h
cds/intrusive/split_list_nogc.h
cds/intrusive/split_list_rcu.h

index e28cdf936ae6f005913fd8f6aa834921e925f34e..3f154110cd6a6012a827d26bb210ec438520ca3a 100644 (file)
@@ -3,8 +3,8 @@
 #ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_H
 #define CDSLIB_INTRUSIVE_SPLIT_LIST_H
 
-#include <cds/intrusive/details/split_list_base.h>
 #include <limits>
+#include <cds/intrusive/details/split_list_base.h>
 
 namespace cds { namespace intrusive {
 
@@ -470,16 +470,19 @@ namespace cds { namespace intrusive {
             if ( ++m_ItemCounter <= nMaxCount )
                 return;
 
-            const size_t nLoadFactor = m_Buckets.load_factor();
             size_t sz = m_nBucketCountLog2.load(memory_model::memory_order_relaxed);
             const size_t nBucketCount = static_cast<size_t>(1) << sz;
-            if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
-                return; // someone already have updated m_nBucketCountLog2, so stop here
-
-            const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
-                                                                              : std::numeric_limits<size_t>::max();
-            m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed, atomics::memory_order_relaxed );
-            m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, atomics::memory_order_relaxed );
+            if ( nBucketCount < m_Buckets.capacity() ) {
+                // we may grow the bucket table
+                const size_t nLoadFactor = m_Buckets.load_factor();
+                if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
+                    return; // someone already have updated m_nBucketCountLog2, so stop here
+
+                const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
+                                                                                  : std::numeric_limits<size_t>::max();
+                m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed, atomics::memory_order_relaxed );
+                m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, atomics::memory_order_relaxed );
+            }
         }
 
         template <typename Q, typename Compare, typename Func>
index 5bf894ba515628555dfe2181ff06a390aa65d4f5..cdf9c5e021c522de2974c489cf2ef32e9cd73ebc 100644 (file)
@@ -3,11 +3,11 @@
 #ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_NOGC_H
 #define CDSLIB_INTRUSIVE_SPLIT_LIST_NOGC_H
 
+#include <limits>
+
 #include <cds/intrusive/details/split_list_base.h>
 #include <cds/gc/nogc.h>
 
-#include <limits>
-
 namespace cds { namespace intrusive {
 
     /// Split-ordered list (template specialization for gc::nogc)
@@ -267,17 +267,20 @@ namespace cds { namespace intrusive {
             if ( ++m_ItemCounter <= nMaxCount )
                 return;
 
-            const size_t nLoadFactor = m_Buckets.load_factor();
             size_t sz = m_nBucketCountLog2.load(memory_model::memory_order_relaxed);
             const size_t nBucketCount = static_cast<size_t>(1) << sz;
-            if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
-                return; // someone already have updated m_nBucketCountLog2, so stop here
-
-            const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
-                                                                              : std::numeric_limits<size_t>::max();
-            m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed,
-                memory_model::memory_order_relaxed );
-            m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, memory_model::memory_order_relaxed );
+            if ( nBucketCount < m_Buckets.capacity() ) {
+                // we may grow the bucket table
+                const size_t nLoadFactor = m_Buckets.load_factor();
+                if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
+                    return; // someone already have updated m_nBucketCountLog2, so stop here
+
+                const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
+                                                                                  : std::numeric_limits<size_t>::max();
+                m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed,
+                    memory_model::memory_order_relaxed );
+                m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, memory_model::memory_order_relaxed );
+            }
         }
 
         //@endcond
index 8deeb7ce75b84505d8a7b77f3988011f8f6c46a2..7774dfda5f57f9c5e4b2e8916a43e9ec1f1d7079 100644 (file)
@@ -3,9 +3,10 @@
 #ifndef CDSLIB_INTRUSIVE_SPLIT_LIST_RCU_H
 #define CDSLIB_INTRUSIVE_SPLIT_LIST_RCU_H
 
+#include <limits>
+
 #include <cds/intrusive/details/split_list_base.h>
 #include <cds/details/binary_functor_wrapper.h>
-#include <limits>
 
 namespace cds { namespace intrusive {
 
@@ -363,17 +364,20 @@ namespace cds { namespace intrusive {
             if ( ++m_ItemCounter <= nMaxCount )
                 return;
 
-            const size_t nLoadFactor = m_Buckets.load_factor();
             size_t sz = m_nBucketCountLog2.load(memory_model::memory_order_relaxed);
             const size_t nBucketCount = static_cast<size_t>(1) << sz;
-            if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
-                return; // someone already have updated m_nBucketCountLog2, so stop here
-
-            const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
-                                                                              : std::numeric_limits<size_t>::max();
-            m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed,
-                memory_model::memory_order_relaxed );
-            m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, memory_model::memory_order_relaxed );
+            if ( nBucketCount < m_Buckets.capacity() ) {
+                // we may grow the bucket table
+                const size_t nLoadFactor = m_Buckets.load_factor();
+                if ( nMaxCount < max_item_count( nBucketCount, nLoadFactor ))
+                    return; // someone already have updated m_nBucketCountLog2, so stop here
+
+                const size_t nNewMaxCount = (nBucketCount < m_Buckets.capacity()) ? max_item_count( nBucketCount << 1, nLoadFactor )
+                                                                                  : std::numeric_limits<size_t>::max();
+                m_nMaxItemCount.compare_exchange_strong( nMaxCount, nNewMaxCount, memory_model::memory_order_relaxed,
+                    memory_model::memory_order_relaxed );
+                m_nBucketCountLog2.compare_exchange_strong( sz, sz + 1, memory_model::memory_order_relaxed, memory_model::memory_order_relaxed );
+            }
         }
 
         template <typename Q, typename Compare, typename Func>