X-Git-Url: https://git.liburcu.org/?p=urcu.git;a=blobdiff_plain;f=rculfhash.c;h=600feecfa8f4f8230eede1683cf79cff14a0333f;hp=f4187e7993ca9ea53a6915ede1edb6673388db48;hb=5f74363e048fb82d7ad97a780eadbeb063840787;hpb=cc6b0c208a9707f8a64609a51167290caeace288 diff --git a/rculfhash.c b/rculfhash.c index f4187e7..600feec 100644 --- a/rculfhash.c +++ b/rculfhash.c @@ -534,7 +534,7 @@ int get_count_order_ulong(unsigned long x) #endif static -void cds_lfht_resize_lazy(struct cds_lfht *ht, unsigned long size, int growth); +void cds_lfht_resize_lazy_grow(struct cds_lfht *ht, unsigned long size, int growth); static void cds_lfht_resize_lazy_count(struct cds_lfht *ht, unsigned long size, @@ -604,7 +604,7 @@ int ht_get_split_count_index(unsigned long hash) assert(split_count_mask >= 0); cpu = sched_getcpu(); - if (unlikely(cpu < 0)) + if (caa_unlikely(cpu < 0)) return hash & split_count_mask; else return cpu & split_count_mask; @@ -623,11 +623,11 @@ void ht_count_add(struct cds_lfht *ht, unsigned long size, unsigned long hash) unsigned long split_count; int index; - if (unlikely(!ht->split_count)) + if (caa_unlikely(!ht->split_count)) return; index = ht_get_split_count_index(hash); split_count = uatomic_add_return(&ht->split_count[index].add, 1); - if (unlikely(!(split_count & ((1UL << COUNT_COMMIT_ORDER) - 1)))) { + if (caa_unlikely(!(split_count & ((1UL << COUNT_COMMIT_ORDER) - 1)))) { long count; dbg_printf("add split count %lu\n", split_count); @@ -650,11 +650,11 @@ void ht_count_del(struct cds_lfht *ht, unsigned long size, unsigned long hash) unsigned long split_count; int index; - if (unlikely(!ht->split_count)) + if (caa_unlikely(!ht->split_count)) return; index = ht_get_split_count_index(hash); split_count = uatomic_add_return(&ht->split_count[index].del, 1); - if (unlikely(!(split_count & ((1UL << COUNT_COMMIT_ORDER) - 1)))) { + if (caa_unlikely(!(split_count & ((1UL << COUNT_COMMIT_ORDER) - 1)))) { long count; dbg_printf("del split count %lu\n", split_count); @@ -695,7 +695,7 @@ void check_resize(struct cds_lfht *ht, unsigned long size, uint32_t chain_len) dbg_printf("WARNING: large chain length: %u.\n", chain_len); if (chain_len >= CHAIN_LEN_RESIZE_THRESHOLD) - cds_lfht_resize_lazy(ht, size, + cds_lfht_resize_lazy_grow(ht, size, get_count_order_u32(chain_len - (CHAIN_LEN_TARGET - 1))); } @@ -742,7 +742,8 @@ int is_end(struct cds_lfht_node *node) } static -unsigned long _uatomic_max(unsigned long *ptr, unsigned long v) +unsigned long _uatomic_xchg_monotonic_increase(unsigned long *ptr, + unsigned long v) { unsigned long old1, old2; @@ -752,7 +753,7 @@ unsigned long _uatomic_max(unsigned long *ptr, unsigned long v) if (old2 >= v) return old2; } while ((old1 = uatomic_cmpxchg(ptr, old2, v)) != old2); - return v; + return old2; } static @@ -806,12 +807,12 @@ void _cds_lfht_gc_bucket(struct cds_lfht_node *dummy, struct cds_lfht_node *node */ assert(dummy != node); for (;;) { - if (unlikely(is_end(iter))) + if (caa_unlikely(is_end(iter))) return; - if (likely(clear_flag(iter)->p.reverse_hash > node->p.reverse_hash)) + if (caa_likely(clear_flag(iter)->p.reverse_hash > node->p.reverse_hash)) return; next = rcu_dereference(clear_flag(iter)->p.next); - if (likely(is_removed(next))) + if (caa_likely(is_removed(next))) break; iter_prev = clear_flag(iter); iter = next; @@ -915,9 +916,9 @@ void _cds_lfht_add(struct cds_lfht *ht, iter = rcu_dereference(iter_prev->p.next); assert(iter_prev->p.reverse_hash <= node->p.reverse_hash); for (;;) { - if (unlikely(is_end(iter))) + if (caa_unlikely(is_end(iter))) goto insert; - if (likely(clear_flag(iter)->p.reverse_hash > node->p.reverse_hash)) + if (caa_likely(clear_flag(iter)->p.reverse_hash > node->p.reverse_hash)) goto insert; /* dummy node is the first node of the identical-hash-value chain */ @@ -925,7 +926,7 @@ void _cds_lfht_add(struct cds_lfht *ht, goto insert; next = rcu_dereference(clear_flag(iter)->p.next); - if (unlikely(is_removed(next))) + if (caa_unlikely(is_removed(next))) goto gc_node; /* uniquely add */ @@ -1015,7 +1016,7 @@ int _cds_lfht_del(struct cds_lfht *ht, unsigned long size, struct cds_lfht_node *new_next; next = old; - if (unlikely(is_removed(next))) + if (caa_unlikely(is_removed(next))) return -ENOENT; if (dummy_removal) assert(is_dummy(next)); @@ -1408,20 +1409,20 @@ void cds_lfht_lookup(struct cds_lfht *ht, void *key, size_t key_len, node = rcu_dereference(dummy_node->p.next); node = clear_flag(node); for (;;) { - if (unlikely(is_end(node))) { + if (caa_unlikely(is_end(node))) { node = next = NULL; break; } - if (unlikely(node->p.reverse_hash > reverse_hash)) { + if (caa_unlikely(node->p.reverse_hash > reverse_hash)) { node = next = NULL; break; } next = rcu_dereference(node->p.next); assert(node == clear_flag(node)); - if (likely(!is_removed(next)) + if (caa_likely(!is_removed(next)) && !is_dummy(next) && node->p.reverse_hash == reverse_hash - && likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) { + && caa_likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) { break; } node = clear_flag(next); @@ -1446,18 +1447,18 @@ void cds_lfht_next_duplicate(struct cds_lfht *ht, struct cds_lfht_iter *iter) node = clear_flag(next); for (;;) { - if (unlikely(is_end(node))) { + if (caa_unlikely(is_end(node))) { node = next = NULL; break; } - if (unlikely(node->p.reverse_hash > reverse_hash)) { + if (caa_unlikely(node->p.reverse_hash > reverse_hash)) { node = next = NULL; break; } next = rcu_dereference(node->p.next); - if (likely(!is_removed(next)) + if (caa_likely(!is_removed(next)) && !is_dummy(next) - && likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) { + && caa_likely(!ht->compare_fct(node->key, node->key_len, key, key_len))) { break; } node = clear_flag(next); @@ -1473,12 +1474,12 @@ void cds_lfht_next(struct cds_lfht *ht, struct cds_lfht_iter *iter) node = clear_flag(iter->next); for (;;) { - if (unlikely(is_end(node))) { + if (caa_unlikely(is_end(node))) { node = next = NULL; break; } next = rcu_dereference(node->p.next); - if (likely(!is_removed(next)) + if (caa_likely(!is_removed(next)) && !is_dummy(next)) { break; } @@ -1753,11 +1754,9 @@ void _do_cds_lfht_resize(struct cds_lfht *ht) } static -unsigned long resize_target_update(struct cds_lfht *ht, unsigned long size, - int growth_order) +unsigned long resize_target_grow(struct cds_lfht *ht, unsigned long new_size) { - return _uatomic_max(&ht->t.resize_target, - size << growth_order); + return _uatomic_xchg_monotonic_increase(&ht->t.resize_target, new_size); } static @@ -1797,15 +1796,13 @@ void do_resize_cb(struct rcu_head *head) } static -void cds_lfht_resize_lazy(struct cds_lfht *ht, unsigned long size, int growth) +void __cds_lfht_resize_lazy_launch(struct cds_lfht *ht) { struct rcu_resize_work *work; - unsigned long target_size; - target_size = resize_target_update(ht, size, growth); /* Store resize_target before read resize_initiated */ cmm_smp_mb(); - if (!CMM_LOAD_SHARED(ht->t.resize_initiated) && size < target_size) { + if (!CMM_LOAD_SHARED(ht->t.resize_initiated)) { uatomic_inc(&ht->in_progress_resize); cmm_smp_mb(); /* increment resize count before load destroy */ if (CMM_LOAD_SHARED(ht->in_progress_destroy)) { @@ -1819,27 +1816,47 @@ void cds_lfht_resize_lazy(struct cds_lfht *ht, unsigned long size, int growth) } } +static +void cds_lfht_resize_lazy_grow(struct cds_lfht *ht, unsigned long size, int growth) +{ + unsigned long target_size = size << growth; + + if (resize_target_grow(ht, target_size) >= target_size) + return; + + __cds_lfht_resize_lazy_launch(ht); +} + +/* + * We favor grow operations over shrink. A shrink operation never occurs + * if a grow operation is queued for lazy execution. A grow operation + * cancels any pending shrink lazy execution. + */ static void cds_lfht_resize_lazy_count(struct cds_lfht *ht, unsigned long size, unsigned long count) { - struct rcu_resize_work *work; - if (!(ht->flags & CDS_LFHT_AUTO_RESIZE)) return; - resize_target_update_count(ht, count); - /* Store resize_target before read resize_initiated */ - cmm_smp_mb(); - if (!CMM_LOAD_SHARED(ht->t.resize_initiated)) { - uatomic_inc(&ht->in_progress_resize); - cmm_smp_mb(); /* increment resize count before load destroy */ - if (CMM_LOAD_SHARED(ht->in_progress_destroy)) { - uatomic_dec(&ht->in_progress_resize); + count = max(count, ht->min_alloc_size); + if (count == size) + return; /* Already the right size, no resize needed */ + if (count > size) { /* lazy grow */ + if (resize_target_grow(ht, count) >= count) return; + } else { /* lazy shrink */ + for (;;) { + unsigned long s; + + s = uatomic_cmpxchg(&ht->t.resize_target, size, count); + if (s == size) + break; /* no resize needed */ + if (s > size) + return; /* growing is/(was just) in progress */ + if (s <= count) + return; /* some other thread do shrink */ + size = s; } - work = malloc(sizeof(*work)); - work->ht = ht; - ht->cds_lfht_call_rcu(&work->head, do_resize_cb); - CMM_STORE_SHARED(ht->t.resize_initiated, 1); } + __cds_lfht_resize_lazy_launch(ht); }