static inline int _ol_close_common(ol_database *db) { debug("Closing \"%s\" database.", db->name); /* TODO: Commit/abort transactions here. */ /* if (!new_db->is_enabled(OL_F_DISABLE_TX, &new_db->feature_set)) { } */ unsigned int iterations = ol_ht_bucket_max(db->cur_ht_size); int rcrd_cnt = db->rcrd_cnt; int freed = 0; debug("Freeing %d records.", rcrd_cnt); debug("Hash table iterations: %d.", iterations); int i = 0; for (; i < iterations; i++) { /* 8=======D */ if (db->hashes[i] != NULL) { ol_bucket *ptr, *next; for (ptr = db->hashes[i]; NULL != ptr; ptr = next) { next = ptr->next; _ol_free_bucket(&ptr); freed++; } } } if (!db->is_enabled(OL_F_DISABLE_TX, &db->feature_set)) { ols_close(db->cur_transactions); free(db->cur_transactions); check(freed >= rcrd_cnt, "Error: Couldn't free all records.\nRecords freed: %d", freed); } if (db->tree != NULL) { debug("Destroying tree."); ols_close(db->tree); free(db->tree); db->tree = NULL; } return OL_SUCCESS; error: return OL_FAILURE; }
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; }