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