1313#define CONCURRENT_SET_HASH_MASK (~CONCURRENT_SET_HASH_RECLAIMABLE_BIT)
1414
1515#define CONCURRENT_SET_DEBUG 0
16+ #define CONCURRENT_SET_DEBUG_STATS 0
17+ #define CONCURRENT_SET_DEBUG_DUPLICATES 0
18+ #define CONCURRENT_SET_DEBUG_BAD_HASH_FN 0
1619
1720enum concurrent_set_special_values {
1821 CONCURRENT_SET_EMPTY = 0 ,
@@ -33,7 +36,7 @@ struct concurrent_set {
3336 const struct rb_concurrent_set_funcs * funcs ;
3437 struct concurrent_set_entry * entries ;
3538 int key_type ;
36- #if CONCURRENT_SET_DEBUG
39+ #if CONCURRENT_SET_DEBUG_STATS
3740 rb_atomic_t find_count ;
3841 rb_atomic_t find_probe_total ;
3942 rb_atomic_t find_probe_max ;
@@ -68,6 +71,10 @@ static VALUE
6871concurrent_set_hash (const struct concurrent_set * set , VALUE key )
6972{
7073 VALUE hash = set -> funcs -> hash (key );
74+ #if CONCURRENT_SET_DEBUG_BAD_HASH_FN
75+ hash = hash % 1024 ;
76+ if (hash == 0 ) hash = 1 ;
77+ #endif
7178 hash &= CONCURRENT_SET_HASH_MASK ;
7279 if (hash == 0 ) hash = ~(VALUE )0 & CONCURRENT_SET_HASH_MASK ;
7380 RUBY_ASSERT (hash != 0 );
@@ -155,7 +162,7 @@ rb_concurrent_set_probe_stats(VALUE set_obj,
155162 rb_atomic_t * find_count , rb_atomic_t * find_probe_total , rb_atomic_t * find_probe_max ,
156163 rb_atomic_t * insert_count , rb_atomic_t * insert_probe_total , rb_atomic_t * insert_probe_max )
157164{
158- #if CONCURRENT_SET_DEBUG
165+ #if CONCURRENT_SET_DEBUG_STATS
159166 struct concurrent_set * set = RTYPEDDATA_GET_DATA (set_obj );
160167 * find_count = RUBY_ATOMIC_LOAD (set -> find_count );
161168 * find_probe_total = RUBY_ATOMIC_LOAD (set -> find_probe_total );
@@ -173,7 +180,7 @@ rb_concurrent_set_probe_stats(VALUE set_obj,
173180#endif
174181}
175182
176- #if CONCURRENT_SET_DEBUG
183+ #if CONCURRENT_SET_DEBUG_STATS
177184static void
178185concurrent_set_atomic_max (rb_atomic_t * target , rb_atomic_t val )
179186{
@@ -244,6 +251,7 @@ concurrent_set_try_resize_locked(VALUE old_set_obj, VALUE *set_obj_ptr, VALUE ne
244251 // Insert key into new_set.
245252 struct concurrent_set_probe probe ;
246253 int idx = concurrent_set_probe_start (& probe , new_set , hash );
254+ int start_idx = idx ;
247255
248256 while (true) {
249257 struct concurrent_set_entry * entry = & new_set -> entries [idx ];
@@ -262,6 +270,7 @@ concurrent_set_try_resize_locked(VALUE old_set_obj, VALUE *set_obj_ptr, VALUE ne
262270 RUBY_ASSERT (entry -> key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT );
263271 entry -> key |= CONCURRENT_SET_CONTINUATION_BIT ;
264272 idx = concurrent_set_probe_next (& probe );
273+ RUBY_ASSERT (idx != start_idx );
265274 }
266275 }
267276
@@ -397,7 +406,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
397406 VALUE curr_hash = rbimpl_atomic_value_load (& entry -> hash , RBIMPL_ATOMIC_ACQUIRE ) & CONCURRENT_SET_HASH_MASK ;
398407
399408 if (curr_hash == 0 ) {
400- #if CONCURRENT_SET_DEBUG
409+ #if CONCURRENT_SET_DEBUG_STATS
401410 rbimpl_atomic_fetch_add (& set -> find_count , 1 , RBIMPL_ATOMIC_RELAXED );
402411 rbimpl_atomic_fetch_add (& set -> find_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
403412 concurrent_set_atomic_max (& set -> find_probe_max , probe .d );
@@ -411,7 +420,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
411420
412421 if (curr_hash != hash ) {
413422 if (!continuation ) {
414- #if CONCURRENT_SET_DEBUG
423+ #if CONCURRENT_SET_DEBUG_STATS
415424 rbimpl_atomic_fetch_add (& set -> find_count , 1 , RBIMPL_ATOMIC_RELAXED );
416425 rbimpl_atomic_fetch_add (& set -> find_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
417426 concurrent_set_atomic_max (& set -> find_probe_max , probe .d );
@@ -442,7 +451,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
442451
443452 if (set -> funcs -> cmp (key , curr_key )) {
444453 // We've found a match.
445- #if CONCURRENT_SET_DEBUG
454+ #if CONCURRENT_SET_DEBUG_STATS
446455 rbimpl_atomic_fetch_add (& set -> find_count , 1 , RBIMPL_ATOMIC_RELAXED );
447456 rbimpl_atomic_fetch_add (& set -> find_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
448457 concurrent_set_atomic_max (& set -> find_probe_max , probe .d );
@@ -452,7 +461,7 @@ rb_concurrent_set_find(VALUE *set_obj_ptr, VALUE key)
452461 }
453462
454463 if (!continuation ) {
455- #if CONCURRENT_SET_DEBUG
464+ #if CONCURRENT_SET_DEBUG_STATS
456465 rbimpl_atomic_fetch_add (& set -> find_count , 1 , RBIMPL_ATOMIC_RELAXED );
457466 rbimpl_atomic_fetch_add (& set -> find_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
458467 concurrent_set_atomic_max (& set -> find_probe_max , probe .d );
@@ -551,10 +560,35 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
551560
552561 VALUE prev_raw_key = rbimpl_atomic_value_cas (& entry -> key , raw_key , key | (continuation ? CONCURRENT_SET_CONTINUATION_BIT : 0 ), RBIMPL_ATOMIC_RELEASE , RBIMPL_ATOMIC_ACQUIRE );
553562 if (prev_raw_key == raw_key ) {
554- #if CONCURRENT_SET_DEBUG
563+ #if CONCURRENT_SET_DEBUG_STATS
555564 rbimpl_atomic_fetch_add (& set -> insert_count , 1 , RBIMPL_ATOMIC_RELAXED );
556565 rbimpl_atomic_fetch_add (& set -> insert_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
557566 concurrent_set_atomic_max (& set -> insert_probe_max , probe .d );
567+ #endif
568+ #if CONCURRENT_SET_DEBUG_DUPLICATES
569+ {
570+ // Probe further to verify no duplicate of our key exists
571+ struct concurrent_set_probe dup_probe = probe ;
572+ int dup_idx = concurrent_set_probe_next (& dup_probe );
573+ int dup_idx_start = dup_idx ;
574+ while (true) {
575+ struct concurrent_set_entry * dup_entry = & set -> entries [dup_idx ];
576+ VALUE dup_raw_key = rbimpl_atomic_value_load (& dup_entry -> key , RBIMPL_ATOMIC_ACQUIRE );
577+ VALUE dup_key = dup_raw_key & CONCURRENT_SET_KEY_MASK ;
578+
579+ if (dup_key == CONCURRENT_SET_EMPTY ) break ;
580+ if (dup_key == CONCURRENT_SET_MOVED ) break ;
581+
582+ if (dup_key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT && dup_key == key ) {
583+ rb_bug ("concurrent_set_find_or_insert: duplicate key %p found at index %d after inserting at index %d" ,
584+ (void * )key , dup_idx , idx );
585+ }
586+ int next_dup_idx = concurrent_set_probe_next (& dup_probe );
587+ if (dup_idx < dup_idx_start && next_dup_idx >= dup_idx_start ) break ;
588+ if (next_dup_idx == dup_idx_start ) break ;
589+ dup_idx = next_dup_idx ;
590+ }
591+ }
558592#endif
559593 RB_GC_GUARD (set_obj );
560594 return key ;
@@ -593,7 +627,7 @@ rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
593627
594628 if (set -> funcs -> cmp (key , curr_key )) {
595629 // We've found a live match.
596- #if CONCURRENT_SET_DEBUG
630+ #if CONCURRENT_SET_DEBUG_STATS
597631 rbimpl_atomic_fetch_add (& set -> insert_count , 1 , RBIMPL_ATOMIC_RELAXED );
598632 rbimpl_atomic_fetch_add (& set -> insert_probe_total , probe .d , RBIMPL_ATOMIC_RELAXED );
599633 concurrent_set_atomic_max (& set -> insert_probe_max , probe .d );
0 commit comments