コード例 #1
0
ファイル: HashTable.c プロジェクト: alangenfeld/cloud-nfs
/**
 * 
 * HashTable_Del: Remove a (key,val) couple from the hashtable.
 *
 * Remove a (key,val) couple from the hashtable. The parameter buffkey contains the key which describes the object to be removed
 * from the hash table. 
 *
 * @param ht the hashtable to be used.
 * @param buffkey a pointeur to an object of type hash_buffer_t which describe the key location in memory.
 * @param pusedbuffkeydata the key data buffer that was associated with this entry. Not considered if equal to NULL.
 *
 * @return HASHTABLE_SUCCESS if successfull\n.
 * @return HASHTABLE_ERROR_NO_SUCH_KEY is the key was not found.
 *
 * @see HashTable_Set
 * @see HashTable_Init
 * @see HashTable_Get
 */
int HashTable_Del(hash_table_t * ht, hash_buffer_t * buffkey,
                  hash_buffer_t * p_usedbuffkey, hash_buffer_t * p_usedbuffdata)
{
  unsigned int hashval;
  struct rbt_node *pn;
  int rbt_value = 0;
  struct rbt_head *tete_rbt;
  hash_data_t *pdata = NULL;
  int rc = 0;

  /* Sanity check */
  if(ht == NULL || buffkey == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the RB Tree to be processed */
  hashval = (*(ht->parameter.hash_func_key)) (&ht->parameter, buffkey);

  /* Find the entry to be deleted */
  rbt_value = (*(ht->parameter.hash_func_rbt)) (&ht->parameter, buffkey);

  /* acquire mutex */
  P_w(&(ht->array_lock[hashval]));

  /* We didn't find anything */
  if((rc = Key_Locate(ht, buffkey, hashval, rbt_value, &pn)) != HASHTABLE_SUCCESS)
    {
      ht->stat_dynamic[hashval].notfound.nb_del += 1;
      V_w(&(ht->array_lock[hashval]));
      return rc;
    }

  pdata = (hash_data_t *) RBT_OPAQ(pn);

  /* Return the key buffer back to the end user if pusedbuffkey isn't NULL */
  if(p_usedbuffkey != NULL)
    *p_usedbuffkey = pdata->buffkey;

  if(p_usedbuffdata != NULL)
    *p_usedbuffdata = pdata->buffval;

  /* Key was found */
  tete_rbt = &(ht->array_rbt[hashval]);
  RBT_UNLINK(tete_rbt, pn);

  /* the key was located, the deletion is done */
  ht->stat_dynamic[hashval].nb_entries -= 1;

  /* put back the pdata buffer to pool */
  RELEASE_PREALLOC(pdata, ht->pdata_prealloc[hashval], next_alloc);

  /* Put the node back in the table of preallocated nodes (it could be reused) */
  RELEASE_PREALLOC(pn, ht->node_prealloc[hashval], next);

  ht->stat_dynamic[hashval].ok.nb_del += 1;

  /* release mutex */
  V_w(&(ht->array_lock[hashval]));

  return HASHTABLE_SUCCESS;
}                               /*  HashTable_Del */
コード例 #2
0
ファイル: hashtable.c プロジェクト: srimalik/nfs-ganesha
/**
 * @brief Remove and free all (key,val) couples from the hash store
 *
 * This function removes all (key,val) couples from the hashtable and
 * frees the stored data using the supplied function
 *
 * @param[in,out] ht        The hashtable to be cleared of all entries
 * @param[in]     free_func The function with which to free the contents
 *                          of each entry
 *
 * @return HASHTABLE_SUCCESS or errors
 */
hash_error_t
hashtable_delall(struct hash_table *ht,
		 int (*free_func)(struct gsh_buffdesc,
				  struct gsh_buffdesc))
{
	/* Successive partition numbers */
	uint32_t index = 0;

	for (index = 0; index < ht->parameter.index_size; index++) {
		/* The root of each successive partition */
		struct rbt_head *root = &ht->partitions[index].rbt;
		/* Pointer to node in tree for removal */
		struct rbt_node *cursor = NULL;

		PTHREAD_RWLOCK_wrlock(&ht->partitions[index].lock);

		/* Continue until there are no more entries in the red-black
		   tree */
		while ((cursor = RBT_LEFTMOST(root)) != NULL) {
			/* Pointer to the key and value descriptors
			   for each successive entry */
			struct hash_data *data = NULL;
			/* Aliased poitner to node, for freeing
			   buffers after removal from tree */
			struct rbt_node *holder = cursor;
			/* Buffer descriptor for key, as stored */
			struct gsh_buffdesc key;
			/* Buffer descriptor for value, as stored */
			struct gsh_buffdesc val;
			/* Return code from the free function.  Zero
			   on failure */
			int rc = 0;

			RBT_UNLINK(root, cursor);
			data = RBT_OPAQ(holder);

			key = data->key;
			val = data->val;

			pool_free(ht->data_pool, data);
			pool_free(ht->node_pool, holder);
			--ht->partitions[index].count;
			rc = free_func(key, val);

			if (rc == 0) {
				PTHREAD_RWLOCK_unlock(&ht->partitions[index].
						      lock);
				return HASHTABLE_ERROR_DELALL_FAIL;
			}
		}
		PTHREAD_RWLOCK_unlock(&ht->partitions[index].lock);
	}

	return HASHTABLE_SUCCESS;
}
コード例 #3
0
ファイル: HashTable.c プロジェクト: alangenfeld/cloud-nfs
/**
 * 
 * Key_Locate: Locate a buffer key in the hash table, as a rbt node.
 * 
 * This function is for internal use only 
 *
 * @param ht the hashtable to be used.
 * @param buffkey a pointeur to an object of type hash_buffer_t which describe the key location in memory.
 * @param hashval hash value associated with the key (in order to avoid computing it a second time)
 * @param rbt_value rbt value associated with the key (in order to avoid computing it a second time)
 * @param ppnode if successfull,will point to the pointer to the rbt node to be used 
 *
 * @return HASHTABLE_SUCCESS if successfull\n.
 * @return HASHTABLE_NO_SUCH_KEY if key was not found 
 *
 */
static int Key_Locate(hash_table_t * ht, hash_buffer_t * buffkey, unsigned int hashval,
                      int rbt_value, struct rbt_node **ppnode)
{
  struct rbt_head *tete_rbt;
  hash_data_t *pdata = NULL;
  struct rbt_node *pn;
  int found = 0;

  /* Sanity check */
  if(ht == NULL || buffkey == NULL || ppnode == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the head of the rbt */
  tete_rbt = &(ht->array_rbt[hashval]);

  /* I get the node with this value that is located on the left (first with this value in the rbtree) */
  RBT_FIND_LEFT(tete_rbt, pn, rbt_value);

  /* Find was successfull ? */
  if(pn == NULL)
    return HASHTABLE_ERROR_NO_SUCH_KEY;

  /* For each entry with this value, compare the key value */
  while((pn != 0) && (RBT_VALUE(pn) == rbt_value))
    {
      pdata = (hash_data_t *) RBT_OPAQ(pn);
      /* Verify the key value : this function returns 0 if key are indentical */
      if(!ht->parameter.compare_key(buffkey, &(pdata->buffkey)))
        {
          found = 1;
          break;                /* exit the while loop */
        }
      RBT_INCREMENT(pn);
    }                           /* while */

  /* We didn't find anything */
  if(!found)
    return HASHTABLE_ERROR_NO_SUCH_KEY;

  /* Key was found */
  *ppnode = pn;

  return HASHTABLE_SUCCESS;
}                               /* Key_Locate */
コード例 #4
0
ファイル: HashTable.c プロジェクト: alangenfeld/cloud-nfs
int HashTable_Get(hash_table_t * ht, hash_buffer_t * buffkey, hash_buffer_t * buffval)
{
  unsigned int hashval;
  struct rbt_node *pn;
  struct rbt_head *tete_rbt;
  hash_data_t *pdata = NULL;
  int rbt_value = 0;
  int rc = 0;

  /* Sanity check */
  if(ht == NULL || buffkey == NULL || buffval == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the RB Tree to be processed */
  hashval = (*(ht->parameter.hash_func_key)) (&ht->parameter, buffkey);
  tete_rbt = &(ht->array_rbt[hashval]);

  /* Seek into the RB Tree */
  rbt_value = (*(ht->parameter.hash_func_rbt)) (&ht->parameter, buffkey);

  /* Acquire mutex */
  P_r(&(ht->array_lock[hashval]));

  /* I get the node with this value that is located on the left (first with this value in the rbtree) */
  if((rc = Key_Locate(ht, buffkey, hashval, rbt_value, &pn)) != HASHTABLE_SUCCESS)
    {
      ht->stat_dynamic[hashval].notfound.nb_get += 1;
      V_r(&(ht->array_lock[hashval]));
      return rc;
    }

  /* Key was found */
  pdata = (hash_data_t *) RBT_OPAQ(pn);
  buffval->pdata = pdata->buffval.pdata;
  buffval->len = pdata->buffval.len;

  ht->stat_dynamic[hashval].ok.nb_get += 1;

  /* Release mutex */
  V_r(&(ht->array_lock[hashval]));

  return HASHTABLE_SUCCESS;
}                               /* HashTable_Get */
コード例 #5
0
static bool nfs_rpc_cbsim_get_v40_client_ids(DBusMessageIter *args,
					     DBusMessage *reply)
{
	uint32_t i;
	hash_table_t *ht = ht_confirmed_client_id;
	struct rbt_head *head_rbt;
	struct hash_data *pdata = NULL;
	struct rbt_node *pn;
	nfs_client_id_t *pclientid;
	uint64_t clientid;
	DBusMessageIter iter, sub_iter;
	struct timespec ts;

	/* create a reply from the message */
	now(&ts);
	dbus_message_iter_init_append(reply, &iter);
	dbus_append_timestamp(&iter, &ts);

	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
					 DBUS_TYPE_UINT64_AS_STRING, &sub_iter);
	/* For each bucket of the hashtable */
	for (i = 0; i < ht->parameter.index_size; i++) {
		head_rbt = &(ht->partitions[i].rbt);

		/* acquire mutex */
		PTHREAD_RWLOCK_wrlock(&(ht->partitions[i].lock));

		/* go through all entries in the red-black-tree */
		RBT_LOOP(head_rbt, pn) {
			pdata = RBT_OPAQ(pn);
			pclientid = pdata->val.addr;
			clientid = pclientid->cid_clientid;
			dbus_message_iter_append_basic(&sub_iter,
						       DBUS_TYPE_UINT64,
						       &clientid);
			RBT_INCREMENT(pn);
		}
		PTHREAD_RWLOCK_unlock(&(ht->partitions[i].lock));
	}
コード例 #6
0
static DBusHandlerResult
nfs_rpc_cbsim_get_client_ids(DBusConnection *conn, DBusMessage *msg,
                             void *user_data)
{
    DBusMessage* reply;
    static uint32_t i, serial = 1;
    hash_table_t *ht = ht_confirmed_client_id;
    struct rbt_head *head_rbt;
    hash_data_t *pdata = NULL;
    struct rbt_node *pn;
    nfs_client_id_t *pclientid;
    uint64_t clientid;
    DBusMessageIter iter, sub_iter;

    /* create a reply from the message */
    reply = dbus_message_new_method_return(msg);
    dbus_message_iter_init_append(reply, &iter);

    dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
                                     DBUS_TYPE_UINT64_AS_STRING, &sub_iter);
    /* For each bucket of the hashtable */
    for(i = 0; i < ht->parameter.index_size; i++) {
        head_rbt = &(ht->partitions[i].rbt);

        /* acquire mutex */
        pthread_rwlock_wrlock(&(ht->partitions[i].lock));

        /* go through all entries in the red-black-tree*/
        RBT_LOOP(head_rbt, pn) {
            pdata = RBT_OPAQ(pn);
            pclientid =
                (nfs_client_id_t *)pdata->buffval.pdata;
            clientid = pclientid->cid_clientid;
            dbus_message_iter_append_basic(&sub_iter, DBUS_TYPE_UINT64, &clientid);
            RBT_INCREMENT(pn);
        }
        pthread_rwlock_unlock(&(ht->partitions[i].lock));
    }
コード例 #7
0
ファイル: hashtable.c プロジェクト: srimalik/nfs-ganesha
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;
}
コード例 #8
0
ファイル: hashtable.c プロジェクト: srimalik/nfs-ganesha
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);

	descriptors = pool_alloc(ht->data_pool);

	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;
}
コード例 #9
0
ファイル: hashtable.c プロジェクト: srimalik/nfs-ganesha
/**
 * @brief Look up an entry, latching the table
 *
 * This function looks up an entry in the hash table and latches the
 * partition in which that entry would belong in preparation for other
 * activities.  This function is a primitive and is intended more for
 * use building other access functions than for client code itself.
 *
 * @brief[in]  ht        The hash table to search
 * @brief[in]  key       The key for which to search
 * @brief[out] val       The value found
 * @brief[in]  may_write This must be true if the followup call might
 *                       mutate the hash table (set or delete)
 * @brief[out] latch     Opaque structure holding information on the
 *                       table.
 *
 * @retval HASHTABLE_SUCCESS The entry was found, the table is
 *         latched.
 * @retval HASHTABLE_ERROR_NOT_FOUND The entry was not found, the
 *         table is latched.
 * @retval Others, failure, the table is not latched.
 */
hash_error_t
hashtable_getlatch(struct hash_table *ht,
		   const struct gsh_buffdesc *key,
		   struct gsh_buffdesc *val, bool may_write,
		   struct hash_latch *latch)
{
	/* The index specifying the partition to search */
	uint32_t index = 0;
	/* The node found for the key */
	struct rbt_node *locator = NULL;
	/* The buffer descritpros for the key and value for the found entry */
	struct hash_data *data = NULL;
	/* The hash value to be searched for within the Red-Black tree */
	uint64_t rbt_hash = 0;
	/* Stored error return */
	hash_error_t rc = HASHTABLE_SUCCESS;

	/* This combination of options makes no sense ever */
	assert(!(may_write && !latch));

	rc = compute(ht, key, &index, &rbt_hash);
	if (rc != HASHTABLE_SUCCESS)
		return rc;

	/* Acquire mutex */
	if (may_write)
		PTHREAD_RWLOCK_wrlock(&(ht->partitions[index].lock));
	else
		PTHREAD_RWLOCK_rdlock(&(ht->partitions[index].lock));

	rc = key_locate(ht, key, index, rbt_hash, &locator);

	if (rc == HASHTABLE_SUCCESS) {
		/* Key was found */
		data = RBT_OPAQ(locator);
		if (val) {
			val->addr = data->val.addr;
			val->len = data->val.len;
		}

		if (isDebug(COMPONENT_HASHTABLE)
		    && isFullDebug(ht->parameter.ht_log_component)) {
			char dispval[HASHTABLE_DISPLAY_STRLEN];

			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,
				     "Get %s returning Value=%p {%s}",
				     ht->parameter.ht_name, data->val.addr,
				     dispval);
		}
	}

	if (((rc == HASHTABLE_SUCCESS) || (rc == HASHTABLE_ERROR_NO_SUCH_KEY))
	    && (latch != NULL)) {
		latch->index = index;
		latch->rbt_hash = rbt_hash;
		latch->locator = locator;
	} else {
		PTHREAD_RWLOCK_unlock(&ht->partitions[index].lock);
	}

	if (rc != HASHTABLE_SUCCESS && isDebug(COMPONENT_HASHTABLE)
	    && isFullDebug(ht->parameter.ht_log_component))
		LogFullDebug(ht->parameter.ht_log_component,
			     "Get %s returning failure %s",
			     ht->parameter.ht_name, hash_table_err_to_str(rc));

	return rc;
}
コード例 #10
0
ファイル: hashtable.c プロジェクト: srimalik/nfs-ganesha
/**
 * @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;
}
コード例 #11
0
ファイル: HashTable.c プロジェクト: alangenfeld/cloud-nfs
/**
 * 
 * HashTable_Test_And_Set: set a pair (key,value) into the Hash Table.
 *
 * Set a (key,val) couple in the hashtable .
 *
 * @param ht the hashtable to be used.
 * @param buffkey a pointeur to an object of type hash_buffer_t which describe the key location in memory.
 * @param buffval a pointeur to an object of type hash_buffer_t which describe the value location in memory.
 * @param how a switch to tell if the entry is to be tested or overwritten or not
 *
 * @return HASHTABLE_SUCCESS if successfull\n.
 * @return HASHTABLE_INSERT_MALLOC_ERROR if an error occured during the insertion process.
 *
 * @see HashTable_Get
 * @see HashTable_Init
 * @see HashTable_Del
 */
int HashTable_Test_And_Set(hash_table_t * ht, hash_buffer_t * buffkey,
                           hash_buffer_t * buffval, hashtable_set_how_t how)
{
  unsigned int hashval = 0;
  int rbt_value = 0;
  struct rbt_head *tete_rbt = NULL;
  struct rbt_node *qn = NULL;
  struct rbt_node *pn = NULL;
  hash_data_t *pdata = NULL;

  /* Sanity check */
  if(ht == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;
  else if(buffkey == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;
  else if(buffval == NULL)
    return HASHTABLE_ERROR_INVALID_ARGUMENT;

  /* Find the RB Tree to be used */
  hashval = (*(ht->parameter.hash_func_key)) (&ht->parameter, buffkey);
  tete_rbt = &(ht->array_rbt[hashval]);
  rbt_value = (*(ht->parameter.hash_func_rbt)) (&ht->parameter, buffkey);

  LogFullDebug(COMPONENT_HASHTABLE,"Key = %p   Value = %p  hashval = %u  rbt_value = %x\n", buffkey->pdata,
         buffval->pdata, hashval, rbt_value);

  /* acquire mutex for protection */
  P_w(&(ht->array_lock[hashval]));

  if(Key_Locate(ht, buffkey, hashval, rbt_value, &pn) == HASHTABLE_SUCCESS)
    {
      /* An entry of that key already exists */
      if(how == HASHTABLE_SET_HOW_TEST_ONLY)
        {
          ht->stat_dynamic[hashval].ok.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_SUCCESS;
        }

      if(how == HASHTABLE_SET_HOW_SET_NO_OVERWRITE)
        {
          ht->stat_dynamic[hashval].err.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_ERROR_KEY_ALREADY_EXISTS;
        }
      qn = pn;
      pdata = RBT_OPAQ(qn);

      LogFullDebug(COMPONENT_HASHTABLE,"Ecrasement d'une ancienne entree (k=%p,v=%p)\n", buffkey->pdata,
             buffval->pdata);

    }
  else
    {
      /* No entry of that key, add it to the trees */
      if(how == HASHTABLE_SET_HOW_TEST_ONLY)
        {
          ht->stat_dynamic[hashval].notfound.nb_test += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_ERROR_NO_SUCH_KEY;
        }

      /* Insert a new node in the table */
      RBT_FIND(tete_rbt, pn, rbt_value);

#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("rbt_node_t");
#endif
      /* This entry does not exist, create it */
      /* First get a new entry in the preallocated node array */
      GET_PREALLOC(qn, ht->node_prealloc[hashval], ht->parameter.nb_node_prealloc,
                   rbt_node_t, next);
      if(qn == NULL)
        {
          ht->stat_dynamic[hashval].err.nb_set += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_INSERT_MALLOC_ERROR;
        }
#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("hash_data_t");
#endif
      GET_PREALLOC(pdata, ht->pdata_prealloc[hashval], ht->parameter.nb_node_prealloc,
                   hash_data_t, next_alloc);
      if(pdata == NULL)
        {
          ht->stat_dynamic[hashval].err.nb_set += 1;
          V_w(&(ht->array_lock[hashval]));
          return HASHTABLE_INSERT_MALLOC_ERROR;
        }
#ifdef _DEBUG_MEMLEAKS
      /* For debugging memory leaks */
      BuddySetDebugLabel("N/A");
#endif
      RBT_OPAQ(qn) = pdata;
      RBT_VALUE(qn) = rbt_value;
      RBT_INSERT(tete_rbt, qn, pn);

      LogFullDebug(COMPONENT_HASHTABLE,"Creation d'une nouvelle entree (k=%p,v=%p), qn=%p, pdata=%p\n",
             buffkey->pdata, buffval->pdata, qn, RBT_OPAQ(qn));
    }

  pdata->buffval.pdata = buffval->pdata;
  pdata->buffval.len = buffval->len;

  pdata->buffkey.pdata = buffkey->pdata;
  pdata->buffkey.len = buffkey->len;

  ht->stat_dynamic[hashval].nb_entries += 1;
  ht->stat_dynamic[hashval].ok.nb_set += 1;

  /* Release mutex */
  V_w(&(ht->array_lock[hashval]));

  return HASHTABLE_SUCCESS;
}                               /* HashTable_Set */
コード例 #12
0
static void reap_hash_table(hash_table_t * ht_reap)
{
  struct rbt_head     * head_rbt;
  hash_data_t         * pdata = NULL;
  uint32_t              i;
  int                   v4, rc;
  struct rbt_node     * pn;
  nfs_client_id_t     * pclientid;
  nfs_client_record_t * precord;

  /* For each bucket of the requested hashtable */
  for(i = 0; i < ht_reap->parameter.index_size; i++)
    {
      head_rbt = &ht_reap->partitions[i].rbt;

 restart:
      /* acquire mutex */
      pthread_rwlock_wrlock(&ht_reap->partitions[i].lock);

      /* go through all entries in the red-black-tree*/
      RBT_LOOP(head_rbt, pn)
        {
          pdata = RBT_OPAQ(pn);

          pclientid = (nfs_client_id_t *)pdata->buffval.pdata;
          /*
           * little hack: only want to reap v4 clients
           * 4.1 initializess this field to '1'
           */
          v4 = (pclientid->cid_create_session_sequence == 0);

          P(pclientid->cid_mutex);

          if(!valid_lease(pclientid) && v4)
            {
              inc_client_id_ref(pclientid);

              /* Take a reference to the client record */
              precord = pclientid->cid_client_record;
              inc_client_record_ref(precord);

              V(pclientid->cid_mutex);

              pthread_rwlock_unlock(&ht_reap->partitions[i].lock);

              if(isDebug(COMPONENT_CLIENTID))
                {
                  char str[HASHTABLE_DISPLAY_STRLEN];

                  display_client_id_rec(pclientid, str);

                  LogFullDebug(COMPONENT_CLIENTID,
                               "Expire index %d %s",
                               i, str);
                }

              /* Take cr_mutex and expire clientid */
              P(precord->cr_mutex);

              rc = nfs_client_id_expire(pclientid);

              V(precord->cr_mutex);

              dec_client_id_ref(pclientid);
              dec_client_record_ref(precord);
              if(rc)
                goto restart;
            }
          else
            {
              V(pclientid->cid_mutex);
            }

          RBT_INCREMENT(pn);
        }

      pthread_rwlock_unlock(&ht_reap->partitions[i].lock);
    }
コード例 #13
0
void *reaper_thread(void *unused)
{
        hash_table_t *ht = ht_client_id;
        struct rbt_head *head_rbt;
        hash_data_t *pdata = NULL;
        int i, v4;
        struct rbt_node *pn;
        nfs_client_id_t *clientp;

#ifndef _NO_BUDDY_SYSTEM
        if((i = BuddyInit(&nfs_param.buddy_param_admin)) != BUDDY_SUCCESS) {
        /* Failed init */
                LogFatal(COMPONENT_MAIN,
                    "Memory manager could not be initialized");
        }
        LogInfo(COMPONENT_MAIN, "Memory manager successfully initialized");
#endif

        SetNameFunction("reaper_thr");

        while(1) {
                /* Initial wait */
                /* TODO: should this be configurable? */
                /* sleep(nfs_param.core_param.reaper_delay); */
                sleep(reaper_delay);
                LogFullDebug(COMPONENT_MAIN,
                    "NFS reaper : now checking clients");

                /* For each bucket of the hashtable */
                for(i = 0; i < ht->parameter.index_size; i++) {
                        head_rbt = &(ht->array_rbt[i]);

restart:
                        /* acquire mutex */
                        P_w(&(ht->array_lock[i]));

                        /* go through all entries in the red-black-tree*/
                        RBT_LOOP(head_rbt, pn) {
                                pdata = RBT_OPAQ(pn);

                                clientp =
                                    (nfs_client_id_t *)pdata->buffval.pdata;
                                /*
                                 * little hack: only want to reap v4 clients
                                 * 4.1 initializess this field to '1'
                                 */
                                v4 = (clientp->create_session_sequence == 0);
                                if (clientp->confirmed != EXPIRED_CLIENT_ID &&
                                    nfs4_is_lease_expired(clientp) && v4) {
                                        V_w(&(ht->array_lock[i]));
                                        LogDebug(COMPONENT_MAIN,
                                            "NFS reaper: expire client %s",
                                            clientp->client_name);
                                        nfs_client_id_expire(clientp);
                                        goto restart;
                                }

                                if (clientp->confirmed == EXPIRED_CLIENT_ID) {
                                        LogDebug(COMPONENT_MAIN,
                                            "reaper: client %s already expired",
                                            clientp->client_name);
                                }

                                RBT_INCREMENT(pn);
                        }
                        V_w(&(ht->array_lock[i]));
                }

        }                           /* while ( 1 ) */
コード例 #14
0
ファイル: nfs_reaper_thread.c プロジェクト: asias/nfs-ganesha
static int reap_hash_table(hash_table_t *ht_reap)
{
	struct rbt_head *head_rbt;
	struct hash_data *addr = NULL;
	uint32_t i;
	int rc;
	struct rbt_node *pn;
	nfs_client_id_t *pclientid;
	nfs_client_record_t *precord;
	int count = 0;
	struct req_op_context req_ctx;
	struct user_cred creds;

	/* We need a real context.  Make all reaping done
	 * by root,root
	 */
	memset(&creds, 0, sizeof(creds));
	req_ctx.creds = &creds;

	/* For each bucket of the requested hashtable */
	for (i = 0; i < ht_reap->parameter.index_size; i++) {
		head_rbt = &ht_reap->partitions[i].rbt;

 restart:
		/* acquire mutex */
		PTHREAD_RWLOCK_wrlock(&ht_reap->partitions[i].lock);

		/* go through all entries in the red-black-tree */
		RBT_LOOP(head_rbt, pn) {
			addr = RBT_OPAQ(pn);

			pclientid = addr->val.addr;
			count++;

			pthread_mutex_lock(&pclientid->cid_mutex);

			if (!valid_lease(pclientid)) {
				inc_client_id_ref(pclientid);

				/* Take a reference to the client record */
				precord = pclientid->cid_client_record;
				inc_client_record_ref(precord);

				pthread_mutex_unlock(&pclientid->cid_mutex);

				PTHREAD_RWLOCK_unlock(&ht_reap->partitions[i].
						      lock);

				if (isDebug(COMPONENT_CLIENTID)) {
					char str[HASHTABLE_DISPLAY_STRLEN];

					display_client_id_rec(pclientid, str);

					LogFullDebug(COMPONENT_CLIENTID,
						     "Expire index %d %s", i,
						     str);
				}

				/* Take cr_mutex and expire clientid */
				pthread_mutex_lock(&precord->cr_mutex);
/**
 * @TODO This is incomplete! the context has to be filled in from
 * somewhere
 */
				memset(&req_ctx, 0, sizeof(req_ctx));
				rc = nfs_client_id_expire(pclientid, &req_ctx);

				pthread_mutex_unlock(&precord->cr_mutex);

				dec_client_id_ref(pclientid);
				dec_client_record_ref(precord);
				if (rc)
					goto restart;
			} else {
				pthread_mutex_unlock(&pclientid->cid_mutex);
			}

			RBT_INCREMENT(pn);
		}

		PTHREAD_RWLOCK_unlock(&ht_reap->partitions[i].lock);
	}