/** * * 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 */
/** * @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; }
/** * * 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 */
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 */
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)); }
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)); }
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; }
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; }
/** * @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; }
/** * @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; }
/** * * 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 */
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); }
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 ) */
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); }