/** * @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; }
hash_error_t hashtable_setlatched(struct hash_table *ht, struct gsh_buffdesc *key, struct gsh_buffdesc *val, struct hash_latch *latch, int overwrite, struct gsh_buffdesc *stored_key, struct gsh_buffdesc *stored_val) { /* Stored error return */ hash_error_t rc = HASHTABLE_SUCCESS; /* The pair of buffer descriptors locating both key and value for this object, what actually gets stored. */ struct hash_data *descriptors = NULL; /* Node giving the location to insert new node */ struct rbt_node *locator = NULL; /* New node for the case of non-overwrite */ struct rbt_node *mutator = NULL; 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(key, dispkey); else dispkey[0] = '\0'; if (ht->parameter.val_to_str != NULL) ht->parameter.val_to_str(val, dispval); else dispval[0] = '\0'; LogFullDebug(ht->parameter.ht_log_component, "Set %s Key=%p {%s} Value=%p {%s} index=%" PRIu32 " rbt_hash=%" PRIu64, ht->parameter.ht_name, key->addr, dispkey, val->addr, dispval, latch->index, latch->rbt_hash); } /* In the case of collision */ if (latch->locator) { if (!overwrite) { rc = HASHTABLE_ERROR_KEY_ALREADY_EXISTS; goto out; } descriptors = 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(&descriptors->key, dispkey); else dispkey[0] = '\0'; if (ht->parameter.val_to_str != NULL) ht->parameter.val_to_str(&descriptors->val, dispval); else dispval[0] = '\0'; LogFullDebug(ht->parameter.ht_log_component, "Set %s Key=%p {%s} Value=%p {%s} " "index=%" PRIu32 " rbt_hash=%" PRIu64 " was replaced", ht->parameter.ht_name, descriptors->key.addr, dispkey, descriptors->val.addr, dispval, latch->index, latch->rbt_hash); } if (stored_key) *stored_key = descriptors->key; if (stored_val) *stored_val = descriptors->val; descriptors->key = *key; descriptors->val = *val; rc = HASHTABLE_OVERWRITTEN; goto out; } /* We have no collision, so go about creating and inserting a new node. */ RBT_FIND(&ht->partitions[latch->index].rbt, locator, latch->rbt_hash); mutator = pool_alloc(ht->node_pool, NULL); if (mutator == NULL) { rc = HASHTABLE_INSERT_MALLOC_ERROR; goto out; } descriptors = pool_alloc(ht->data_pool, NULL); if (descriptors == NULL) { pool_free(ht->node_pool, mutator); rc = HASHTABLE_INSERT_MALLOC_ERROR; goto out; } RBT_OPAQ(mutator) = descriptors; RBT_VALUE(mutator) = latch->rbt_hash; RBT_INSERT(&ht->partitions[latch->index].rbt, mutator, locator); descriptors->key.addr = key->addr; descriptors->key.len = key->len; descriptors->val.addr = val->addr; descriptors->val.len = val->len; /* Only in the non-overwrite case */ ++ht->partitions[latch->index].count; rc = HASHTABLE_SUCCESS; out: hashtable_releaselatched(ht, latch); if (rc != HASHTABLE_SUCCESS && isDebug(COMPONENT_HASHTABLE) && isFullDebug(ht->parameter.ht_log_component)) LogFullDebug(ht->parameter.ht_log_component, "Set %s returning failure %s", ht->parameter.ht_name, hash_table_err_to_str(rc)); return rc; }