static inline void gweakref_delete_impl(gweakref_table_t *wt, gweakref_t *ref, uint32_t flags) { struct avltree_node *node; gweakref_priv_t refk, *tref; gweakref_partition_t *wp; /* lookup up ref.ptr, delete iff ref.ptr is found and * ref.gen == found.gen */ refk.k = *ref; wp = gwt_partition_of_addr_k(wt, refk.k.ptr); if (!(flags & GWR_FLAG_WLOCKED)) pthread_rwlock_wrlock(&wp->lock); node = avltree_lookup(&refk.node_k, &wp->t); if (node) { /* found it, maybe */ tref = avltree_container_of(node, gweakref_priv_t, node_k); /* XXX generation mismatch would be in error, we think */ if (tref->k.gen == ref->gen) { /* unhook it */ avltree_remove(node, &wp->t); gsh_free(tref); if (wp->cache) wp->cache[cache_offsetof(wt, refk.k.ptr)] = NULL; } } if (!(flags & GWR_FLAG_WLOCKED)) pthread_rwlock_unlock(&wp->lock); }
void *gweakref_lookupex(gweakref_table_t *wt, gweakref_t *ref, pthread_rwlock_t **lock) { struct avltree_node *node = NULL; gweakref_priv_t refk, *tref; gweakref_partition_t *wp; void *ret = NULL; /* look up ref.ptr--return !NULL iff ref.ptr is found and * ref.gen == found.gen */ refk.k = *ref; wp = gwt_partition_of_addr_k(wt, refk.k.ptr); pthread_rwlock_rdlock(&wp->lock); /* check cache */ if (wp->cache) node = wp->cache[cache_offsetof(wt, refk.k.ptr)]; if (! node) node = avltree_lookup(&refk.node_k, &wp->t); if (node) { /* found it, maybe */ tref = avltree_container_of(node, gweakref_priv_t, node_k); if (tref->k.gen == ref->gen) { ret = ref->ptr; if (wp->cache) wp->cache[cache_offsetof(wt, refk.k.ptr)] = node; } } if (ret) { *lock = &wp->lock; } else { pthread_rwlock_unlock(&wp->lock); } return (ret); }
void hashtable_deletelatched(struct hash_table *ht, const struct gsh_buffdesc *key, struct hash_latch *latch, struct gsh_buffdesc *stored_key, struct gsh_buffdesc *stored_val) { /* The pair of buffer descriptors comprising the stored entry */ struct hash_data *data = NULL; /* Its partition */ struct hash_partition *partition = &ht->partitions[latch->index]; if (!latch->locator) return; data = RBT_OPAQ(latch->locator); if (isDebug(COMPONENT_HASHTABLE) && isFullDebug(ht->parameter.ht_log_component)) { char dispkey[HASHTABLE_DISPLAY_STRLEN]; char dispval[HASHTABLE_DISPLAY_STRLEN]; if (ht->parameter.key_to_str != NULL) ht->parameter.key_to_str(&data->key, dispkey); else dispkey[0] = '\0'; if (ht->parameter.val_to_str != NULL) ht->parameter.val_to_str(&data->val, dispval); else dispval[0] = '\0'; LogFullDebug(ht->parameter.ht_log_component, "Delete %s Key=%p {%s} Value=%p {%s} index=%" PRIu32 " rbt_hash=%" PRIu64 " was removed", ht->parameter.ht_name, data->key.addr, dispkey, data->val.addr, dispval, latch->index, latch->rbt_hash); } if (stored_key) *stored_key = data->key; if (stored_val) *stored_val = data->val; /* Clear cache */ if (partition->cache) { uint32_t offset = cache_offsetof(ht, latch->rbt_hash); struct rbt_node *cnode = partition->cache[offset]; if (cnode) { #if COMPARE_BEFORE_CLEAR_CACHE struct hash_data *data1 = RBT_OPAQ(cnode); struct hash_data *data2 = RBT_OPAQ(latch->locator); if (ht->parameter. compare_key(&(data1->key), &(data2->key)) == 0) { LogFullDebug(COMPONENT_HASHTABLE_CACHE, "hash clear index %d slot %" PRIu64 latch->index, offset); partition->cache[offset] = NULL; } #else LogFullDebug(COMPONENT_HASHTABLE_CACHE, "hash clear slot %d", offset); partition->cache[offset] = NULL; #endif } } /* Now remove the entry */ RBT_UNLINK(&partition->rbt, latch->locator); pool_free(ht->data_pool, data); pool_free(ht->node_pool, latch->locator); --ht->partitions[latch->index].count; }
/** * @brief Locate a key within a partition * * This function traverses the red-black tree within a hash table * partition and returns, if one exists, a pointer to a node matching * the supplied key. * * @param[in] ht The hashtable to be used * @param[in] key The key to look up * @param[in] index Index into RBT array * @param[in] rbthash Hash in red-black tree * @param[out] node On success, the found node, NULL otherwise * * @retval HASHTABLE_SUCCESS if successfull * @retval HASHTABLE_NO_SUCH_KEY if key was not found */ static hash_error_t key_locate(struct hash_table *ht, const struct gsh_buffdesc *key, uint32_t index, uint64_t rbthash, struct rbt_node **node) { /* The current partition */ struct hash_partition *partition = &(ht->partitions[index]); /* The root of the red black tree matching this index */ struct rbt_head *root = NULL; /* A pair of buffer descriptors locating key and value for this entry */ struct hash_data *data = NULL; /* The node in the red-black tree currently being traversed */ struct rbt_node *cursor = NULL; /* true if we have located the key */ int found = false; *node = NULL; if (partition->cache) { void **cache_slot = (void **) &(partition->cache[cache_offsetof(ht, rbthash)]); cursor = atomic_fetch_voidptr(cache_slot); LogFullDebug(COMPONENT_HASHTABLE_CACHE, "hash %s index %" PRIu32 " slot %d", (cursor) ? "hit" : "miss", index, cache_offsetof(ht, rbthash)); if (cursor) { data = RBT_OPAQ(cursor); if (ht->parameter. compare_key((struct gsh_buffdesc *)key, &(data->key)) == 0) { goto out; } } } root = &(ht->partitions[index].rbt); /* The lefmost occurrence of the value is the one from which we may start iteration to visit all nodes containing a value. */ RBT_FIND_LEFT(root, cursor, rbthash); if (cursor == NULL) { if (isFullDebug(COMPONENT_HASHTABLE) && isFullDebug(ht->parameter.ht_log_component)) LogFullDebug(ht->parameter.ht_log_component, "Key not found: rbthash = %" PRIu64, rbthash); return HASHTABLE_ERROR_NO_SUCH_KEY; } while ((cursor != NULL) && (RBT_VALUE(cursor) == rbthash)) { data = RBT_OPAQ(cursor); if (ht->parameter. compare_key((struct gsh_buffdesc *)key, &(data->key)) == 0) { if (partition->cache) { void **cache_slot = (void **) &(partition-> cache[cache_offsetof(ht, rbthash)]); atomic_store_voidptr(cache_slot, cursor); } found = true; break; } RBT_INCREMENT(cursor); } if (!found) { if (isFullDebug(COMPONENT_HASHTABLE) && isFullDebug(ht->parameter.ht_log_component)) LogFullDebug(ht->parameter.ht_log_component, "Matching hash found, but no matching key."); return HASHTABLE_ERROR_NO_SUCH_KEY; } out: *node = cursor; return HASHTABLE_SUCCESS; }