Commit d3640b34 authored by Yoni Fogel's avatar Yoni Fogel

Addresses #307

Added test cases for the hashtable.
Now has 100% line and branch coverage of hashtable except for asserts.

git-svn-id: file:///svn/tokudb@2077 c7de825b-a66e-492c-adef-691d508d4ae1
parent 729a8221
...@@ -203,6 +203,7 @@ static int __toku_lt_selfread(toku_lock_tree* tree, DB_TXN* txn, ...@@ -203,6 +203,7 @@ static int __toku_lt_selfread(toku_lock_tree* tree, DB_TXN* txn,
toku_rt_forest* forest = toku_rth_find(tree->rth, txn); toku_rt_forest* forest = toku_rth_find(tree->rth, txn);
if (!forest) { if (!forest) {
/* Neither selfread nor selfwrite exist. */
r = toku_rth_insert(tree->rth, txn); r = toku_rth_insert(tree->rth, txn);
if (r!=0) return r; if (r!=0) return r;
forest = toku_rth_find(tree->rth, txn); forest = toku_rth_find(tree->rth, txn);
...@@ -1147,20 +1148,19 @@ static int __toku_lt_border_delete(toku_lock_tree* tree, toku_range_tree* rt) { ...@@ -1147,20 +1148,19 @@ static int __toku_lt_border_delete(toku_lock_tree* tree, toku_range_tree* rt) {
return 0; return 0;
} }
/*
TODO: delete selfread and selfwrite from txn and/or local list
*/
int toku_lt_unlock(toku_lock_tree* tree, DB_TXN* txn) { int toku_lt_unlock(toku_lock_tree* tree, DB_TXN* txn) {
assert(tree && txn);
int r; int r;
toku_range_tree *selfwrite; toku_range_tree *selfwrite = __toku_lt_ifexist_selfwrite(tree, txn);
toku_range_tree *selfread = __toku_lt_ifexist_selfread (tree, txn);
r = __toku_lt_free_contents(tree, __toku_lt_ifexist_selfread(tree, txn), r = __toku_lt_free_contents(tree, selfread, tree->mainread);
tree->mainread);
if (r!=0) return __toku_lt_panic(tree); if (r!=0) return __toku_lt_panic(tree);
selfwrite = __toku_lt_ifexist_selfwrite(tree, txn);
r = __toku_lt_border_delete(tree, selfwrite); r = __toku_lt_border_delete(tree, selfwrite);
if (r!=0) return __toku_lt_panic(tree); if (r!=0) return __toku_lt_panic(tree);
if (selfread || selfwrite) toku_rth_delete(tree->rth, txn);
return 0; return 0;
} }
...@@ -57,27 +57,27 @@ typedef struct { ...@@ -57,27 +57,27 @@ typedef struct {
BOOL duplicates; BOOL duplicates;
toku_range_tree* mainread; /**< See design document */ toku_range_tree* mainread; /**< See design document */
toku_range_tree* borderwrite; /**< See design document */ toku_range_tree* borderwrite; /**< See design document */
toku_rt_hashtable* rth; toku_rth* rth;
/** A temporary area where we store the results of various find on /** A temporary area where we store the results of various find on
the range trees that this lock tree owns */ the range trees that this lock tree owns */
toku_range* buf; toku_range* buf;
u_int32_t buflen; /**< The length of buf */ u_int32_t buflen; /**< The length of buf */
/** The maximum amount of memory to be used for DBT payloads. */ /** The maximum amount of memory to be used for DBT payloads. */
size_t payload_capacity; size_t payload_capacity;
/** The current amount of memory used for DBT payloads. */ /** The current amount of memory used for DBT payloads. */
size_t payload_used; size_t payload_used;
/** The key compare function */ /** The key compare function */
int (*compare_fun)(DB*,const DBT*,const DBT*); int (*compare_fun)(DB*,const DBT*,const DBT*);
/** The data compare function */ /** The data compare function */
int (*dup_compare)(DB*,const DBT*,const DBT*); int (*dup_compare)(DB*,const DBT*,const DBT*);
/** The panic function */ /** The panic function */
int (*panic)(DB*); int (*panic)(DB*);
/** The user malloc function */ /** The user malloc function */
void* (*malloc) (size_t); void* (*malloc) (size_t);
/** The user free function */ /** The user free function */
void (*free) (void*); void (*free) (void*);
/** The user realloc function */ /** The user realloc function */
void* (*realloc)(void*, size_t); void* (*realloc)(void*, size_t);
} toku_lock_tree; } toku_lock_tree;
......
...@@ -17,22 +17,22 @@ ...@@ -17,22 +17,22 @@
/* TODO: reallocate the hash table if it grows too big. Perhaps, use toku_get_prime in newbrt/primes.c */ /* TODO: reallocate the hash table 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 uint32 __toku_rth_hash(toku_rt_hashtable* table, DB_TXN* key) { static inline uint32 __toku_rth_hash(toku_rth* table, DB_TXN* key) {
assert(table);
size_t tmp = (size_t)key; size_t tmp = (size_t)key;
return tmp % table->array_size; return tmp % table->array_size;
} }
static inline void __toku_invalidate_scan(toku_rt_hashtable* table) { static inline void __toku_invalidate_scan(toku_rth* table) {
table->finger_end = TRUE; table->finger_end = TRUE;
} }
int toku_rth_create(toku_rt_hashtable** ptable, int toku_rth_create(toku_rth** ptable,
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; int r;
toku_rt_hashtable* tmp = (toku_rt_hashtable*)user_malloc(sizeof(*tmp)); toku_rth* tmp = (toku_rth*)user_malloc(sizeof(*tmp));
if (0) { died1: user_free(tmp); return r; } if (0) { died1: user_free(tmp); return r; }
if (!tmp) return errno; if (!tmp) return errno;
...@@ -50,7 +50,7 @@ int toku_rth_create(toku_rt_hashtable** ptable, ...@@ -50,7 +50,7 @@ int toku_rth_create(toku_rt_hashtable** ptable,
return 0; return 0;
} }
toku_rt_forest* toku_rth_find(toku_rt_hashtable* table, DB_TXN* key) { toku_rt_forest* toku_rth_find(toku_rth* table, DB_TXN* key) {
assert(table && key); assert(table && key);
uint32 index = __toku_rth_hash(table, key); uint32 index = __toku_rth_hash(table, key);
...@@ -59,14 +59,14 @@ toku_rt_forest* toku_rth_find(toku_rt_hashtable* table, DB_TXN* key) { ...@@ -59,14 +59,14 @@ toku_rt_forest* toku_rth_find(toku_rt_hashtable* table, DB_TXN* key) {
return element ? &element->value : NULL; return element ? &element->value : NULL;
} }
void toku_rth_start_scan(toku_rt_hashtable* table) { void toku_rth_start_scan(toku_rth* table) {
assert(table); assert(table);
table->finger_index = 0; table->finger_index = 0;
table->finger_ptr = table->table[table->finger_index]; table->finger_ptr = table->table[table->finger_index];
table->finger_end = FALSE; table->finger_end = FALSE;
} }
toku_rth_elt* __toku_rth_next(toku_rt_hashtable* table) { static inline toku_rth_elt* __toku_rth_next(toku_rth* table) {
assert(table); assert(table);
assert(!table->finger_end); assert(!table->finger_end);
...@@ -78,48 +78,67 @@ toku_rth_elt* __toku_rth_next(toku_rt_hashtable* table) { ...@@ -78,48 +78,67 @@ toku_rth_elt* __toku_rth_next(toku_rt_hashtable* table) {
return table->finger_ptr; return table->finger_ptr;
} }
toku_rt_forest* toku_rth_next(toku_rt_hashtable* table) { toku_rt_forest* toku_rth_next(toku_rth* table) {
assert(table); assert(table);
toku_rth_elt* next = __toku_rth_next(table); toku_rth_elt* next = __toku_rth_next(table);
return next ? &next->value : NULL; return next ? &next->value : NULL;
} }
int toku_rth_delete(toku_rt_hashtable* table, DB_TXN* key) { /* Element MUST exist. */
void toku_rth_delete(toku_rth* table, DB_TXN* key) {
assert(table && key); assert(table && key);
__toku_invalidate_scan(table); __toku_invalidate_scan(table);
/* No elements. */ /* Must have elements. */
if (!table->num_keys) return EDOM; assert(table->num_keys);
uint32 index = __toku_rth_hash(table, key); uint32 index = __toku_rth_hash(table, key);
toku_rth_elt* element = table->table[index]; toku_rth_elt* element = table->table[index];
/* No elements of the right hash. */ /* Elements of the right hash must exist. */
if (!element) return EDOM; assert(element);
/* Case where it is the first element. */ /* Case where it is the first element. */
if (element->key == key) { if (element->key == key) {
table->table[index] = element->next; table->table[index] = element->next;
goto recycle; table->free(element);
table->num_keys--;
return;
} }
toku_rth_elt* prev; toku_rth_elt* prev;
/* Case where it is not the first element. */ /* Case where it is not the first element. */
do { do {
assert(element);
prev = element; prev = element;
element = element->next; element = element->next;
} while (element && element->key != key); } while (element->key != key);
/* Not found. */ /* Must be found. */
if (!element) return EDOM; assert(element);
prev->next = element->next; prev->next = element->next;
goto recycle; table->free(element);
recycle:
element->next = table->free_list;
table->free_list = element;
table->num_keys--; table->num_keys--;
return 0; return;
} }
void toku_rth_close(toku_rt_hashtable* table) { /* 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);
uint32 index = __toku_rth_hash(table, key);
/* Allocate a new one. */
toku_rth_elt* element = (toku_rth_elt*)table->malloc(sizeof(*element));
if (!element) return errno;
memset(&element->value, 0, sizeof(toku_rt_forest));
element->key = key;
element->next = table->table[index];
table->table[index] = element;
table->num_keys++;
return 0;
}
void toku_rth_close(toku_rth* table) {
assert(table);
toku_rth_elt* element; toku_rth_elt* element;
toku_rth_elt* next = NULL; toku_rth_elt* next = NULL;
...@@ -131,39 +150,6 @@ void toku_rth_close(toku_rt_hashtable* table) { ...@@ -131,39 +150,6 @@ void toku_rth_close(toku_rt_hashtable* table) {
table->free(element); table->free(element);
} }
next = table->free_list;
while (next) {
element = next;
next = next->next;
table->free(element);
}
table->free(table->table); table->free(table->table);
table->free(table); table->free(table);
} }
/* Will allow you to insert it over and over. You need to keep track. */
int toku_rth_insert(toku_rt_hashtable* table, DB_TXN* key) {
assert(table && key);
__toku_invalidate_scan(table);
uint32 index = __toku_rth_hash(table, key);
/* Recycle */
toku_rth_elt* element;
if (table->free_list) {
element = table->free_list;
table->free_list = table->free_list->next;
}
else {
/* Allocate a new one. */
element = (toku_rth_elt*)table->malloc(sizeof(*element));
if (!element) return errno;
}
memset(&element->value, 0, sizeof(toku_rt_forest));
element->key = key;
element->next = table->table[index];
table->table[index] = element;
table->num_keys++;
return 0;
}
...@@ -29,36 +29,35 @@ struct __toku_rth_elt { ...@@ -29,36 +29,35 @@ struct __toku_rth_elt {
toku_rth_elt* next; toku_rth_elt* next;
}; };
typedef struct __toku_rt_hashtable toku_rt_hashtable; typedef struct __toku_rth toku_rth;
struct __toku_rt_hashtable { struct __toku_rth {
toku_rth_elt** table; toku_rth_elt** table;
uint32 num_keys; uint32 num_keys;
uint32 array_size; uint32 array_size;
uint32 finger_index; uint32 finger_index;
toku_rth_elt* finger_ptr; toku_rth_elt* finger_ptr;
BOOL finger_end; BOOL finger_end;
toku_rth_elt* free_list;
/** The user malloc function */ /** The user malloc function */
void* (*malloc) (size_t); void* (*malloc) (size_t);
/** The user free function */ /** The user free function */
void (*free) (void*); void (*free) (void*);
/** The user realloc function */ /** The user realloc function */
void* (*realloc)(void*, size_t); void* (*realloc)(void*, size_t);
}; };
int toku_rth_create(toku_rt_hashtable** ptable, int toku_rth_create(toku_rth** ptable,
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));
toku_rt_forest* toku_rth_find(toku_rt_hashtable* table, DB_TXN* key); toku_rt_forest* toku_rth_find (toku_rth* table, DB_TXN* key);
void toku_rth_start_scan(toku_rt_hashtable* table); void toku_rth_start_scan (toku_rth* table);
toku_rt_forest* toku_rth_next(toku_rt_hashtable* table); toku_rt_forest* toku_rth_next (toku_rth* table);
int toku_rth_delete(toku_rt_hashtable* table, DB_TXN* key); void toku_rth_delete (toku_rth* table, DB_TXN* key);
void toku_rth_close(toku_rt_hashtable* table); void toku_rth_close (toku_rth* table);
int toku_rth_insert(toku_rt_hashtable* table, DB_TXN* key); int toku_rth_insert (toku_rth* table, DB_TXN* key);
...@@ -112,3 +112,14 @@ void init_point(toku_point* point, toku_lock_tree* tree) { ...@@ -112,3 +112,14 @@ void init_point(toku_point* point, toku_lock_tree* tree) {
memset(point, 0, sizeof(toku_point)); memset(point, 0, sizeof(toku_point));
point->lt = tree; point->lt = tree;
} }
int mallocced = 0;
int failon = -1;
void* fail_malloc(size_t size) {
if (++mallocced == failon) {
errno = ENOMEM;
return NULL;
}
return malloc(size);
}
/* We are going to test whether create and close properly check their input. */
#include "test.h"
toku_rth* rth;
int main(int argc, const char *argv[]) {
int r;
parse_args(argc, argv);
rth = NULL;
for (failon = 1; failon <= 2; failon++) {
mallocced = 0;
r = toku_rth_create(&rth, fail_malloc, toku_free, toku_realloc);
CKERR2(r, ENOMEM);
assert(rth==NULL);
}
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
toku_rth_close(rth);
rth = NULL;
size_t i;
size_t iterations = 512 << 2;
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = 1; i < iterations; i++) {
r = toku_rth_insert(rth, (DB_TXN*)i);
CKERR(r);
}
toku_rt_forest* f;
for (i = 1; i < iterations; i++) {
f = toku_rth_find(rth, (DB_TXN*)i);
assert(f);
}
f = toku_rth_find(rth, (DB_TXN*)i);
assert(!f);
for (i = iterations - 1; i >= 1; i--) {
toku_rth_delete(rth, (DB_TXN*)i);
}
toku_rth_close(rth);
rth = NULL;
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = 1; i < iterations; i++) {
r = toku_rth_insert(rth, (DB_TXN*)i);
CKERR(r);
}
for (i = 1; i < iterations; i++) {
toku_rth_delete(rth, (DB_TXN*)i);
}
toku_rth_close(rth);
rth = NULL;
r = toku_rth_create(&rth, toku_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
for (i = iterations - 1; i >= 1; i--) {
r = toku_rth_insert(rth, (DB_TXN*)i);
CKERR(r);
}
toku_rth_close(rth);
rth = NULL;
failon = 3;
mallocced = 0;
r = toku_rth_create(&rth, fail_malloc, toku_free, toku_realloc);
CKERR(r);
assert(rth);
r = toku_rth_insert(rth, (DB_TXN*)1);
CKERR2(r, ENOMEM);
toku_rth_close(rth);
rth = NULL;
return 0;
}
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