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