Commit ffb68b5c authored by Yoni Fogel's avatar Yoni Fogel

Improved speed of range tree hash table.

git-svn-id: file:///svn/tokudb@2770 c7de825b-a66e-492c-adef-691d508d4ae1
parent 8beace59
......@@ -4,8 +4,8 @@
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."
/**
\file hash_table.h
\brief Hash table
\file hash_rth.h
\brief Hash rth
*/
......@@ -14,146 +14,156 @@
#include <errno.h>
#include <string.h>
/* TODO: reallocate the hash table if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */
/* TODO: reallocate the hash rth if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */
const uint32 __toku_rth_init_size = 521;
static inline uint32 toku__rth_hash(toku_rth* table, DB_TXN* key) {
static inline uint32 toku__rth_hash(toku_rth* rth, DB_TXN* key) {
size_t tmp = (size_t)key;
return tmp % table->array_size;
return tmp % rth->num_buckets;
}
static inline void toku__invalidate_scan(toku_rth* table) {
table->finger_end = TRUE;
static inline void toku__invalidate_scan(toku_rth* rth) {
rth->iter_is_valid = FALSE;
}
int toku_rth_create(toku_rth** ptable,
int toku_rth_create(toku_rth** prth,
void* (*user_malloc) (size_t),
void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) {
assert(ptable && user_malloc && user_free && user_realloc);
int r;
toku_rth* tmp = (toku_rth*)user_malloc(sizeof(*tmp));
if (0) { died1: user_free(tmp); return r; }
if (!tmp) return errno;
int r = ENOSYS;
assert(prth && user_malloc && user_free && user_realloc);
toku_rth* tmp = NULL;
tmp = (toku_rth*)user_malloc(sizeof(*tmp));
if (!tmp) { r = ENOMEM; goto cleanup; }
memset(tmp, 0, sizeof(*tmp));
tmp->malloc = user_malloc;
tmp->free = user_free;
tmp->realloc = user_realloc;
tmp->array_size = __toku_rth_init_size;
tmp->table = (toku_rth_elt**)
tmp->malloc(tmp->array_size * sizeof(*tmp->table));
if (!tmp->table) { r = errno; goto died1; }
memset(tmp->table, 0, tmp->array_size * sizeof(*tmp->table));
tmp->malloc = user_malloc;
tmp->free = user_free;
tmp->realloc = user_realloc;
tmp->num_buckets = __toku_rth_init_size;
tmp->buckets = (toku_rth_elt*)
tmp->malloc(tmp->num_buckets * sizeof(*tmp->buckets));
if (!tmp->buckets) { r = ENOMEM; goto cleanup; }
memset(tmp->buckets, 0, tmp->num_buckets * sizeof(*tmp->buckets));
toku__invalidate_scan(tmp);
*ptable = tmp;
return 0;
tmp->iter_head.next_in_iteration = &tmp->iter_head;
tmp->iter_head.prev_in_iteration = &tmp->iter_head;
*prth = tmp;
r = 0;
cleanup:
if (r != 0) {
if (tmp) {
if (tmp->buckets) { user_free(tmp->buckets); }
user_free(tmp);
}
}
return r;
}
toku_rt_forest* toku_rth_find(toku_rth* table, DB_TXN* key) {
assert(table && key);
toku_rt_forest* toku_rth_find(toku_rth* rth, DB_TXN* key) {
assert(rth && key);
uint32 index = toku__rth_hash(table, key);
toku_rth_elt* element = table->table[index];
while (element && element->value.hash_key != key) element = element->next;
return element ? &element->value : NULL;
uint32 index = toku__rth_hash(rth, key);
toku_rth_elt* head = &rth->buckets[index];
toku_rth_elt* current = head->next_in_bucket;
while (current) {
if (current->value.hash_key == key) break;
current = current->next_in_bucket;
}
return current ? &current->value : NULL;
}
void toku_rth_start_scan(toku_rth* table) {
assert(table);
table->finger_index = 0;
table->finger_ptr = table->table[table->finger_index];
table->finger_start = TRUE;
table->finger_end = FALSE;
void toku_rth_start_scan(toku_rth* rth) {
assert(rth);
rth->iter_curr = &rth->iter_head;
rth->iter_is_valid = TRUE;
}
static inline toku_rth_elt* toku__rth_next(toku_rth* table) {
assert(table);
assert(!table->finger_end);
if (table->finger_ptr && !table->finger_start) {
table->finger_ptr = table->finger_ptr->next;
}
while (!table->finger_ptr && ++table->finger_index < table->array_size) {
table->finger_ptr = table->table[table->finger_index];
}
table->finger_start = FALSE;
table->finger_end = !table->finger_ptr;
return table->finger_ptr;
static inline toku_rth_elt* toku__rth_next(toku_rth* rth) {
assert(rth);
assert(rth->iter_is_valid);
rth->iter_curr = rth->iter_curr->next_in_iteration;
rth->iter_is_valid = rth->iter_curr != &rth->iter_head;
return rth->iter_curr;
}
toku_rt_forest* toku_rth_next(toku_rth* table) {
assert(table);
toku_rth_elt* next = toku__rth_next(table);
return next ? &next->value : NULL;
toku_rt_forest* toku_rth_next(toku_rth* rth) {
assert(rth);
toku_rth_elt* next = toku__rth_next(rth);
return rth->iter_curr != &rth->iter_head ? &next->value : NULL;
}
/* Element MUST exist. */
void toku_rth_delete(toku_rth* table, DB_TXN* key) {
assert(table && key);
toku__invalidate_scan(table);
void toku_rth_delete(toku_rth* rth, DB_TXN* key) {
assert(rth && key);
toku__invalidate_scan(rth);
/* Must have elements. */
assert(table->num_keys);
uint32 index = toku__rth_hash(table, key);
toku_rth_elt* element = table->table[index];
/* Elements of the right hash must exist. */
assert(element);
/* Case where it is the first element. */
if (element->value.hash_key == key) {
table->table[index] = element->next;
table->free(element);
table->num_keys--;
return;
assert(rth->num_keys);
uint32 index = toku__rth_hash(rth, key);
toku_rth_elt* head = &rth->buckets[index];
toku_rth_elt* prev = head;
toku_rth_elt* current = prev->next_in_bucket;
while (current != head) {
if (current->value.hash_key == key) break;
prev = current;
current = current->next_in_bucket;
}
toku_rth_elt* prev;
/* Case where it is not the first element. */
do {
assert(element);
prev = element;
element = element->next;
} while (element->value.hash_key != key);
/* Must be found. */
assert(element);
prev->next = element->next;
table->free(element);
table->num_keys--;
assert(current != head);
current->prev_in_iteration->next_in_iteration = current->next_in_iteration;
current->next_in_iteration->prev_in_iteration = current->prev_in_iteration;
prev->next_in_bucket = current->next_in_bucket;
rth->free(current);
rth->num_keys--;
return;
}
/* Will allow you to insert it over and over. You need to keep track. */
int toku_rth_insert(toku_rth* table, DB_TXN* key) {
assert(table && key);
toku__invalidate_scan(table);
int toku_rth_insert(toku_rth* rth, DB_TXN* key) {
int r = ENOSYS;
assert(rth && key);
toku__invalidate_scan(rth);
uint32 index = toku__rth_hash(table, key);
uint32 index = toku__rth_hash(rth, key);
/* Allocate a new one. */
toku_rth_elt* element = (toku_rth_elt*)table->malloc(sizeof(*element));
if (!element) return errno;
toku_rth_elt* element = (toku_rth_elt*)rth->malloc(sizeof(*element));
if (!element) { r = ENOMEM; goto cleanup; }
memset(element, 0, sizeof(*element));
element->value.hash_key = key;
element->next = table->table[index];
table->table[index] = element;
table->num_keys++;
return 0;
element->value.hash_key = key;
element->next_in_iteration = rth->iter_head.next_in_iteration;
element->prev_in_iteration = &rth->iter_head;
element->next_in_iteration->prev_in_iteration = element;
element->prev_in_iteration->next_in_iteration = element;
element->next_in_bucket = rth->buckets[index].next_in_bucket;
rth->buckets[index].next_in_bucket = element;
rth->num_keys++;
r = 0;
cleanup:
return r;
}
void toku_rth_close(toku_rth* table) {
assert(table);
void toku_rth_close(toku_rth* rth) {
assert(rth);
toku_rth_elt* element;
toku_rth_elt* head = &rth->iter_head;
toku_rth_elt* next = NULL;
toku_rth_start_scan(table);
next = toku__rth_next(table);
while (next) {
toku_rth_start_scan(rth);
next = toku__rth_next(rth);
while (next != head) {
element = next;
next = toku__rth_next(table);
table->free(element);
next = toku__rth_next(rth);
rth->free(element);
}
table->free(table->table);
table->free(table);
rth->free(rth->buckets);
rth->free(rth);
}
......@@ -28,18 +28,19 @@ struct __toku_rt_forest {
typedef struct __toku_rth_elt toku_rth_elt;
struct __toku_rth_elt {
toku_rt_forest value;
toku_rth_elt* next;
toku_rth_elt* next_in_bucket;
toku_rth_elt* next_in_iteration;
toku_rth_elt* prev_in_iteration;
};
typedef struct __toku_rth toku_rth;
struct __toku_rth {
toku_rth_elt** table;
toku_rth_elt* buckets;
uint32 num_buckets;
uint32 num_keys;
uint32 array_size;
uint32 finger_index;
toku_rth_elt* finger_ptr;
BOOL finger_start;
BOOL finger_end;
toku_rth_elt iter_head;
toku_rth_elt* iter_curr;
BOOL iter_is_valid;
/** The user malloc function */
void* (*malloc) (size_t);
/** The user free function */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment