Beispiel #1
0
/**
 * @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;
}
Beispiel #2
0
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;
}