Commit 52509b72 authored by Bradley C. Kuszmaul's avatar Bradley C. Kuszmaul

Improve cachetable testing

git-svn-id: file:///svn/tokudb@297 c7de825b-a66e-492c-adef-691d508d4ae1
parent c9cbbcf2
......@@ -26,23 +26,28 @@ endif
default: bins
# Put these one-per-line so that if we insert a new one the svn diff can understand it better.
# Also keep them sorted.
BINS = \
benchmark-test \
REGRESSION_TESTS = \
ybt-test \
pma-test \
brt-serialize-test \
brt-test \
cachetable-test \
cachetable-test2 \
hashtest \
pma-test \
# This line intentially kept commented so I can have a \ on the end of the previous line
BINS = $(REGRESSION_TESTS) \
benchmark-test \
randbrt \
randdb4 \
ybt-test \
# This line intentially kept blank so I can have a \ on the end of the previous line
# This line intentially kept commented so I can have a \ on the end of the previous line
bins: $(BINS)
check: bins
$(DTOOL) ./ybt-test
$(DTOOL) ./pma-test
$(DTOOL) ./cachetable-test
$(DTOOL) ./cachetable-test2
$(DTOOL) ./brt-serialize-test
$(DTOOL) ./brt-test
$(DTOOL) ./hashtest
......@@ -85,6 +90,9 @@ brt-serialize-test: brt-serialize-test.o brt-serialize.o memory.o hashtable.o pm
cachetable-test.o: cachetable.h memory.h
cachetable-test: cachetable.o memory.o cachetable-test.o
cachetable-test2.o: cachetable.h memory.h
cachetable-test2: cachetable.o memory.o cachetable-test2.o
benchmark-test: benchmark-test.o ybt.o memory.o brt.o pma.o cachetable.o key.o hashtable.o brt-serialize.o primes.o
benchmark-test.o: brt.h ../include/db.h
......
......@@ -1314,7 +1314,6 @@ int brt_insert (BRT brt, DBT *key, DBT *val, DB* db) {
}
int brt_lookup_node (BRT brt, diskoff off, DBT *k, DBT *v, DB *db) {
int result;
void *node_v;
int r = cachetable_get_and_pin(brt->cf, off, &node_v,
brtnode_flush_callback, brtnode_fetch_callback, (void*)(long)brt->h->nodesize);
......@@ -1325,7 +1324,7 @@ int brt_lookup_node (BRT brt, diskoff off, DBT *k, DBT *v, DB *db) {
int childnum;
if (node->height==0) {
result = pma_lookup(node->u.l.buffer, k, v, db);
int result = pma_lookup(node->u.l.buffer, k, v, db);
//printf("%s:%d looked up something, got answerlen=%d\n", __FILE__, __LINE__, answerlen);
r = cachetable_unpin(brt->cf, off, 0);
assert(r == 0);
......@@ -1338,6 +1337,7 @@ int brt_lookup_node (BRT brt, diskoff off, DBT *k, DBT *v, DB *db) {
ITEMLEN hanswerlen;
int type;
if (toku_hash_find (node->u.n.htables[childnum], k->data, k->size, &hanswer, &hanswerlen, &type)==0) {
int result;
if (type == BRT_INSERT) {
//printf("Found %d bytes\n", *vallen);
ybt_set_value(v, hanswer, hanswerlen, &brt->sval);
......@@ -1345,18 +1345,22 @@ int brt_lookup_node (BRT brt, diskoff off, DBT *k, DBT *v, DB *db) {
result = 0;
} else if (type == BRT_DELETE) {
result = DB_NOTFOUND;
} else
} else {
assert(0);
result = -1; // Some versions of gcc complain
}
r = cachetable_unpin(brt->cf, off, 0);
assert(r == 0);
return result;
}
}
result = brt_lookup_node(brt, node->u.n.children[childnum], k, v, db);
{
int result = brt_lookup_node(brt, node->u.n.children[childnum], k, v, db);
r = cachetable_unpin(brt->cf, off, 0);
assert(r == 0);
return result;
}
}
......
......@@ -2,9 +2,9 @@
#include "cachetable.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct item {
......
#include "memory.h"
#include "cachetable.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
CACHETABLE ct;
enum { N_PRESENT_LIMIT = 4, TRIALS=200, N_FILES=2 };
int n_present=0;
struct present_items {
CACHEKEY key;
CACHEFILE cf;
} present_items[N_PRESENT_LIMIT];
static void print_ints(void) __attribute__((__unused__));
static void print_ints(void) {
int i;
for (i=0; i<n_present; i++) {
if (i==0) printf("{"); else printf(",");
printf("{%lld,%p}", present_items[i].key, present_items[i].cf);
}
printf("}\n");
}
static void item_becomes_present(CACHEFILE cf, CACHEKEY key) {
assert(n_present<N_PRESENT_LIMIT);
present_items[n_present].cf = cf;
present_items[n_present].key = key;
n_present++;
}
static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) {
int i;
//printf("Removing {%4lld %16p}: Initially: ", key, cf); print_ints();
assert(n_present<=N_PRESENT_LIMIT);
for (i=0; i<n_present; i++) {
if (present_items[i].cf==cf && present_items[i].key==key) {
present_items[i]=present_items[n_present-1];
n_present--;
//printf(" Finally: "); print_ints();
return;
}
}
printf("Whoops, %p,%lld was already not present\n", cf ,key);
abort();
}
static void file_is_not_present(CACHEFILE cf) {
int i;
for (i=0; i<n_present; i++) {
assert(present_items[i].cf!=cf);
}
}
static void flush_forchain (CACHEFILE f __attribute__((__unused__)), CACHEKEY key, void *value, int write_me __attribute__((__unused__)), int keep_me __attribute__((__unused__))) {
int *v = value;
//cachetable_print_state(ct);
//printf("Flush %lld %d\n", key, (int)value);
assert((int)v==(int)key);
item_becomes_not_present(f, key);
//print_ints();
}
static int fetch_forchain (CACHEFILE f __attribute__((__unused__)), CACHEKEY key, void**value, void*extraargs) {
assert((int)extraargs==(int)key);
*value = (void*)(int)key;
return 0;
}
void verify_cachetable_against_present (void) {
int i;
for (i=0; i<n_present; i++) {
void *v;
int r;
assert(cachetable_maybe_get_and_pin(present_items[i].cf,
present_items[i].key,
&v)==0);
r = cachetable_unpin(present_items[i].cf, present_items[i].key, 0);
}
}
void test_chaining (void) {
/* Make sure that the hash chain and the LRU list don't get confused. */
CACHEFILE f[N_FILES];
enum { FILENAME_LEN=100 };
char fname[N_FILES][FILENAME_LEN];
int r;
int i, trial;
r = create_cachetable(&ct, N_PRESENT_LIMIT); assert(r==0);
for (i=0; i<N_FILES; i++) {
int r = snprintf(fname[i], FILENAME_LEN, "cachetabletest2.%d.dat", i);
assert(r>0 && r<FILENAME_LEN);
unlink(fname[i]);
r = cachetable_openf(&f[i], ct, fname[i], O_RDWR|O_CREAT, 0777); assert(r==0);
}
for (i=0; i<N_PRESENT_LIMIT; i++) {
int fnum = i%N_FILES;
//printf("%s:%d Add %d\n", __FILE__, __LINE__, i);
r = cachetable_put(f[fnum], i, (void*)i, flush_forchain, fetch_forchain, (void*)i); assert(r==0);
item_becomes_present(f[fnum], i);
r = cachetable_unpin(f[fnum], i, 0); assert(r==0);
//print_ints();
}
for (trial=0; trial<TRIALS; trial++) {
if (n_present>0) {
// First touch some random ones
int whichone = random()%n_present;
void *value;
//printf("Touching %d (%lld, %p)\n", whichone, present_items[whichone].key, present_items[whichone].cf);
r = cachetable_get_and_pin(present_items[whichone].cf,
present_items[whichone].key,
&value,
flush_forchain,
fetch_forchain,
(void*)(int)present_items[whichone].key
);
assert(r==0);
r = cachetable_unpin(present_items[whichone].cf,
present_items[whichone].key,
0);
assert(r==0);
}
i += 1+ random()%100;
int fnum = i%N_FILES;
// i is always incrementing, so we need not worry about inserting a duplicate
//printf("%s:%d Add {%d,%p}\n", __FILE__, __LINE__, i, f[fnum]);
r = cachetable_put(f[fnum], i, (void*)i, flush_forchain, fetch_forchain, (void*)i); assert(r==0);
item_becomes_present(f[fnum], i);
//print_ints();
//cachetable_print_state(ct);
r = cachetable_unpin(f[fnum], i, 0); assert(r==0);
verify_cachetable_against_present();
if (random()%10==0) {
i = random()%N_FILES;
//printf("Close %d (%p), now n_present=%d\n", i, f[i], n_present);
//print_ints();
CACHEFILE oldcf=f[i];
r = cachefile_close(&f[i]); assert(r==0);
file_is_not_present(oldcf);
r = cachetable_openf(&f[i], ct, fname[i], O_RDWR, 0777); assert(r==0);
}
}
for (i=0; i<N_FILES; i++) {
r = cachefile_close(&f[i]); assert(r==0);
}
r = cachetable_close(&ct); assert(r==0);
}
int main (int argc __attribute__((__unused__)), char *argv[] __attribute__((__unused__))) {
test_chaining();
malloc_cleanup();
printf("ok\n");
return 0;
}
......@@ -53,6 +53,18 @@ struct cachefile {
struct fileid fileid;
};
void cachetable_print_state (CACHETABLE ct) {
int i;
for (i=0; i<ct->table_size; i++) {
PAIR p;
printf("t[%d]=", i);
for (p=ct->table[i]; p; p=p->hash_chain) {
printf(" {%lld, %p}", p->key, p->cachefile);
}
printf("\n");
}
}
int create_cachetable (CACHETABLE *result, int n_entries) {
TAGMALLOC(CACHETABLE, t);
int i;
......@@ -112,7 +124,7 @@ CACHEFILE remove_cf_from_list (CACHEFILE cf, CACHEFILE list) {
}
}
int cachefile_flush (CACHEFILE cf);
static int cachefile_flush_and_remove (CACHEFILE cf);
int cachefile_close (CACHEFILE *cfp) {
CACHEFILE cf = *cfp;
......@@ -120,7 +132,7 @@ int cachefile_close (CACHEFILE *cfp) {
cf->refcount--;
if (cf->refcount==0) {
int r;
if ((r = cachefile_flush(cf))) return r;
if ((r = cachefile_flush_and_remove(cf))) return r;
r = close(cf->fd);
cf->cachetable->cachefiles = remove_cf_from_list(cf, cf->cachetable->cachefiles);
toku_free(cf);
......@@ -337,7 +349,7 @@ int cachetable_maybe_get_and_pin (CACHEFILE cachefile, CACHEKEY key, void**value
*value = p->value;
p->pinned++;
lru_touch(t,p);
printf("%s:%d cachetable_maybe_get_and_pin(%lld)--> %p\n", __FILE__, __LINE__, key, *value);
//printf("%s:%d cachetable_maybe_get_and_pin(%lld)--> %p\n", __FILE__, __LINE__, key, *value);
return 0;
}
}
......@@ -374,7 +386,28 @@ int cachetable_flush (CACHETABLE t) {
return 0;
}
int cachefile_flush (CACHEFILE cf) {
static void assert_cachefile_is_flushed_and_removed (CACHEFILE cf) {
CACHETABLE t = cf->cachetable;
int i;
// Check it two ways
// First way: Look through all the hash chains
for (i=0; i<t->table_size; i++) {
PAIR p;
for (p=t->table[i]; p; p=p->hash_chain) {
assert(p->cachefile!=cf);
}
}
// Second way: Look through the LRU list.
{
PAIR p;
for (p=t->head; p; p=p->next) {
assert(p->cachefile!=cf);
}
}
}
static int cachefile_flush_and_remove (CACHEFILE cf) {
int i;
CACHETABLE t = cf->cachetable;
for (i=0; i<t->table_size; i++) {
......@@ -390,10 +423,10 @@ int cachefile_flush (CACHEFILE cf) {
}
}
}
assert_cachefile_is_flushed_and_removed(cf);
return 0;
}
/* Require that it all be flushed. */
int cachetable_close (CACHETABLE *tp) {
CACHETABLE t=*tp;
......
......@@ -18,6 +18,7 @@ typedef struct cachefile *CACHEFILE;
* Note: The cachetable should use a common pool of memory, flushing things across cachetables.
* (The first implementation doesn't)
* If you pin something twice, you must unpin it twice.
* n_entries says how many items can fit into the cache table at a time.
*/
int create_cachetable (CACHETABLE */*result*/, int /*n_entries*/);
......@@ -56,4 +57,7 @@ int cachefile_close (CACHEFILE*);
int cachefile_fd (CACHEFILE);
// Useful for debugging
void cachetable_print_state (CACHETABLE ct);
#endif
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