Commit abc8f71e 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 68e8036c
...@@ -4,8 +4,8 @@ ...@@ -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." #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 \file hash_rth.h
\brief Hash table \brief Hash rth
*/ */
...@@ -14,146 +14,156 @@ ...@@ -14,146 +14,156 @@
#include <errno.h> #include <errno.h>
#include <string.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; 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; 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) { static inline void toku__invalidate_scan(toku_rth* rth) {
table->finger_end = TRUE; 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_malloc) (size_t),
void (*user_free) (void*), void (*user_free) (void*),
void* (*user_realloc)(void*, size_t)) { void* (*user_realloc)(void*, size_t)) {
assert(ptable && user_malloc && user_free && user_realloc); int r = ENOSYS;
int r; assert(prth && user_malloc && user_free && user_realloc);
toku_rth* tmp = (toku_rth*)user_malloc(sizeof(*tmp)); toku_rth* tmp = NULL;
if (0) { died1: user_free(tmp); return r; } tmp = (toku_rth*)user_malloc(sizeof(*tmp));
if (!tmp) return errno; if (!tmp) { r = ENOMEM; goto cleanup; }
memset(tmp, 0, sizeof(*tmp)); memset(tmp, 0, sizeof(*tmp));
tmp->malloc = user_malloc; tmp->malloc = user_malloc;
tmp->free = user_free; tmp->free = user_free;
tmp->realloc = user_realloc; tmp->realloc = user_realloc;
tmp->array_size = __toku_rth_init_size; tmp->num_buckets = __toku_rth_init_size;
tmp->table = (toku_rth_elt**) tmp->buckets = (toku_rth_elt*)
tmp->malloc(tmp->array_size * sizeof(*tmp->table)); tmp->malloc(tmp->num_buckets * sizeof(*tmp->buckets));
if (!tmp->table) { r = errno; goto died1; } if (!tmp->buckets) { r = ENOMEM; goto cleanup; }
memset(tmp->table, 0, tmp->array_size * sizeof(*tmp->table)); memset(tmp->buckets, 0, tmp->num_buckets * sizeof(*tmp->buckets));
toku__invalidate_scan(tmp); toku__invalidate_scan(tmp);
*ptable = tmp; tmp->iter_head.next_in_iteration = &tmp->iter_head;
return 0; 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) { toku_rt_forest* toku_rth_find(toku_rth* rth, DB_TXN* key) {
assert(table && key); assert(rth && key);
uint32 index = toku__rth_hash(table, key); uint32 index = toku__rth_hash(rth, key);
toku_rth_elt* element = table->table[index]; toku_rth_elt* head = &rth->buckets[index];
while (element && element->value.hash_key != key) element = element->next; toku_rth_elt* current = head->next_in_bucket;
return element ? &element->value : NULL; 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) { void toku_rth_start_scan(toku_rth* rth) {
assert(table); assert(rth);
table->finger_index = 0; rth->iter_curr = &rth->iter_head;
table->finger_ptr = table->table[table->finger_index]; rth->iter_is_valid = TRUE;
table->finger_start = TRUE;
table->finger_end = FALSE;
} }
static inline toku_rth_elt* toku__rth_next(toku_rth* table) { static inline toku_rth_elt* toku__rth_next(toku_rth* rth) {
assert(table); assert(rth);
assert(!table->finger_end); assert(rth->iter_is_valid);
if (table->finger_ptr && !table->finger_start) { rth->iter_curr = rth->iter_curr->next_in_iteration;
table->finger_ptr = table->finger_ptr->next; rth->iter_is_valid = rth->iter_curr != &rth->iter_head;
} return rth->iter_curr;
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;
} }
toku_rt_forest* toku_rth_next(toku_rth* table) { toku_rt_forest* toku_rth_next(toku_rth* rth) {
assert(table); assert(rth);
toku_rth_elt* next = toku__rth_next(table); toku_rth_elt* next = toku__rth_next(rth);
return next ? &next->value : NULL; return rth->iter_curr != &rth->iter_head ? &next->value : NULL;
} }
/* Element MUST exist. */ /* Element MUST exist. */
void toku_rth_delete(toku_rth* table, DB_TXN* key) { void toku_rth_delete(toku_rth* rth, DB_TXN* key) {
assert(table && key); assert(rth && key);
toku__invalidate_scan(table); toku__invalidate_scan(rth);
/* Must have elements. */ /* Must have elements. */
assert(table->num_keys); assert(rth->num_keys);
uint32 index = toku__rth_hash(table, key); uint32 index = toku__rth_hash(rth, key);
toku_rth_elt* element = table->table[index]; toku_rth_elt* head = &rth->buckets[index];
toku_rth_elt* prev = head;
/* Elements of the right hash must exist. */ toku_rth_elt* current = prev->next_in_bucket;
assert(element);
/* Case where it is the first element. */ while (current != head) {
if (element->value.hash_key == key) { if (current->value.hash_key == key) break;
table->table[index] = element->next; prev = current;
table->free(element); current = current->next_in_bucket;
table->num_keys--;
return;
} }
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. */ /* Must be found. */
assert(element); assert(current != head);
prev->next = element->next; current->prev_in_iteration->next_in_iteration = current->next_in_iteration;
table->free(element); current->next_in_iteration->prev_in_iteration = current->prev_in_iteration;
table->num_keys--; prev->next_in_bucket = current->next_in_bucket;
rth->free(current);
rth->num_keys--;
return; return;
} }
/* Will allow you to insert it over and over. You need to keep track. */ /* Will allow you to insert it over and over. You need to keep track. */
int toku_rth_insert(toku_rth* table, DB_TXN* key) { int toku_rth_insert(toku_rth* rth, DB_TXN* key) {
assert(table && key); int r = ENOSYS;
toku__invalidate_scan(table); 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. */ /* Allocate a new one. */
toku_rth_elt* element = (toku_rth_elt*)table->malloc(sizeof(*element)); toku_rth_elt* element = (toku_rth_elt*)rth->malloc(sizeof(*element));
if (!element) return errno; if (!element) { r = ENOMEM; goto cleanup; }
memset(element, 0, sizeof(*element)); memset(element, 0, sizeof(*element));
element->value.hash_key = key; element->value.hash_key = key;
element->next = table->table[index]; element->next_in_iteration = rth->iter_head.next_in_iteration;
table->table[index] = element; element->prev_in_iteration = &rth->iter_head;
table->num_keys++; element->next_in_iteration->prev_in_iteration = element;
return 0; 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) { void toku_rth_close(toku_rth* rth) {
assert(table); assert(rth);
toku_rth_elt* element; toku_rth_elt* element;
toku_rth_elt* head = &rth->iter_head;
toku_rth_elt* next = NULL; toku_rth_elt* next = NULL;
toku_rth_start_scan(table); toku_rth_start_scan(rth);
next = toku__rth_next(table); next = toku__rth_next(rth);
while (next) { while (next != head) {
element = next; element = next;
next = toku__rth_next(table); next = toku__rth_next(rth);
table->free(element); rth->free(element);
} }
table->free(table->table); rth->free(rth->buckets);
table->free(table); rth->free(rth);
} }
...@@ -28,18 +28,19 @@ struct __toku_rt_forest { ...@@ -28,18 +28,19 @@ struct __toku_rt_forest {
typedef struct __toku_rth_elt toku_rth_elt; typedef struct __toku_rth_elt toku_rth_elt;
struct __toku_rth_elt { struct __toku_rth_elt {
toku_rt_forest value; 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; typedef struct __toku_rth toku_rth;
struct __toku_rth { struct __toku_rth {
toku_rth_elt** table; toku_rth_elt* buckets;
uint32 num_buckets;
uint32 num_keys; uint32 num_keys;
uint32 array_size; toku_rth_elt iter_head;
uint32 finger_index; toku_rth_elt* iter_curr;
toku_rth_elt* finger_ptr; BOOL iter_is_valid;
BOOL finger_start;
BOOL finger_end;
/** The user malloc function */ /** The user malloc function */
void* (*malloc) (size_t); void* (*malloc) (size_t);
/** The user free function */ /** 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