ol_bucket *ol_get_bucket(const ol_database *db, const char *key, const size_t klen, char (*_key)[KEY_SIZE], size_t *_klen) { if (db == NULL) return NULL; uint32_t hash; _ol_trunc(key, klen, *_key); *_klen = strnlen(*_key, KEY_SIZE); if (*_klen == 0) return NULL; MurmurHash3_x86_32(*_key, *_klen, DEVILS_SEED, &hash); unsigned int index = _ol_calc_idx(db->cur_ht_size, hash); if (db->hashes[index] != NULL) { size_t larger_key = 0; ol_bucket *tmp_bucket; tmp_bucket = db->hashes[index]; larger_key = tmp_bucket->klen > klen ? tmp_bucket->klen : klen; if (strncmp(tmp_bucket->key, key, larger_key) == 0) { return tmp_bucket; } else if (tmp_bucket->next != NULL) { /* Keys were not the same, traverse the linked list to see if it's * farther down. */ do { tmp_bucket = tmp_bucket->next; larger_key = tmp_bucket->klen > klen ? tmp_bucket->klen : klen; if (strncmp(tmp_bucket->key, key, larger_key) == 0) return tmp_bucket; } while (tmp_bucket->next != NULL); } } return NULL; }
static inline void _ol_rehash_insert_bucket( ol_bucket **tmp_hashes, const size_t to_alloc, ol_bucket *bucket) { int new_index; new_index = _ol_calc_idx(to_alloc, bucket->hash); if (tmp_hashes[new_index] != NULL) { /* Enforce that this is the last bucket, KILL THE ORPHANS */ ol_bucket *last_bucket = _ol_get_last_bucket_in_slot( tmp_hashes[new_index]); last_bucket->next = bucket; } else { tmp_hashes[new_index] = bucket; } }
static inline void _ol_rehash_insert_bucket( ol_bucket **tmp_hashes, const size_t to_alloc, ol_bucket *bucket) { int new_index; uint32_t hash; MurmurHash3_x86_32(bucket->key, bucket->klen, DEVILS_SEED, &hash); new_index = _ol_calc_idx(to_alloc, hash); if (tmp_hashes[new_index] != NULL) { /* Enforce that this is the last bucket, KILL THE ORPHANS */ ol_bucket *last_bucket = _ol_get_last_bucket_in_slot( tmp_hashes[new_index]); last_bucket->next = bucket; } else tmp_hashes[new_index] = bucket; }
int _ol_set_bucket_no_incr(ol_database *db, ol_bucket *bucket, uint32_t hash) { /* TODO: error codes? */ unsigned int index = _ol_calc_idx(db->cur_ht_size, hash); if (db->hashes[index] != NULL) { db->meta->key_collisions++; ol_bucket *tmp_bucket = db->hashes[index]; tmp_bucket = _ol_get_last_bucket_in_slot(tmp_bucket); tmp_bucket->next = bucket; } else { db->hashes[index] = bucket; } if (db->is_enabled(OL_F_SPLAYTREE, &db->feature_set)) { /* Put the bucket into the tree */ ol_splay_tree_node *node = NULL; node = ols_insert(db->tree, bucket->key, bucket->klen, bucket); /* Make sure the bucket can reference the node. */ bucket->node = node; } return 0; }
int olt_scoop(ol_transaction *tx, const char *key, size_t klen) { /* you know... like scoop some data from the jar and eat it? All gone. */ uint32_t hash; char _key[KEY_SIZE] = {'\0'}; _ol_trunc(key, klen, _key); size_t _klen = strnlen(_key, KEY_SIZE); check(_klen > 0, "Key length cannot be zero."); MurmurHash3_x86_32(_key, _klen, DEVILS_SEED, &hash); ol_database *operating_db = tx->transaction_db; /* First attempt to calculate the index in the transaction_db */ unsigned int index = _ol_calc_idx(tx->transaction_db->cur_ht_size, hash); /* If we couldn't find it in the transaction_db, look for the value in the * parent_db (the one we forked from) */ if (tx->transaction_db->hashes[index] == NULL && tx->parent_db != NULL) { index = _ol_calc_idx(tx->parent_db->cur_ht_size, hash); operating_db = tx->parent_db; } if (operating_db->hashes[index] == NULL) return OL_FAILURE; /* Now that we know what database we're operating on, continue * as usual. */ ol_bucket *to_free = NULL; int return_level = OL_FAILURE; size_t larger_key = 0; ol_bucket *bucket = operating_db->hashes[index]; larger_key = bucket->klen > _klen ? bucket->klen : _klen; if (strncmp(bucket->key, _key, larger_key) == 0) { /* We only ACTUALLY want to delete something if we're operating on the transaction_db */ if (operating_db == tx->transaction_db) operating_db->hashes[index] = bucket->next; to_free = bucket; return_level = OL_SUCCESS; } else { /* Keys weren't the same, traverse the bucket LL */ while (bucket->next != NULL) { ol_bucket *last = bucket; bucket = bucket->next; larger_key = bucket->klen > klen ? bucket->klen : klen; if (strncmp(bucket->key, _key, larger_key) == 0) { if (operating_db == tx->transaction_db) { if (bucket->next != NULL) last->next = bucket->next; else last->next = NULL; } to_free = bucket; return_level = OL_SUCCESS; break; } } } if (to_free != NULL) { /* Only delete the node from the transaction_db. */ if (operating_db == tx->transaction_db && tx->transaction_db->is_enabled(OL_F_SPLAYTREE, &tx->transaction_db->feature_set)) { ols_delete(tx->transaction_db->tree, to_free->node); to_free->node = NULL; } /* Write the SCOOP command to the log, so we can replay it later. */ if (tx->transaction_db->state != OL_S_STARTUP) { ol_aol_write_cmd(tx->transaction_db, "SCOOP", bucket); } /* Again, only delete the key from the transaction_db, not the parent. */ if (operating_db == tx->transaction_db) { unsigned char *data_ptr = tx->transaction_db->values + to_free->data_offset; const size_t data_size = to_free->data_size; if (data_size != 0) memset(data_ptr, '\0', data_size); _ol_free_bucket(&to_free); tx->transaction_db->rcrd_cnt -= 1; } } /* Flag the transaction as dirty. */ tx->dirty = 1; return return_level; error: return OL_FAILURE; }