mirror of
https://github.com/MariaDB/server.git
synced 2025-02-02 03:51:50 +01:00
Improve cachetable testing
git-svn-id: file:///svn/tokudb@297 c7de825b-a66e-492c-adef-691d508d4ae1
This commit is contained in:
parent
7077a1f50f
commit
7201ffd9e0
6 changed files with 229 additions and 19 deletions
|
@ -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
|
||||
|
||||
|
|
18
newbrt/brt.c
18
newbrt/brt.c
|
@ -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);
|
||||
r = cachetable_unpin(brt->cf, off, 0);
|
||||
assert(r == 0);
|
||||
return result;
|
||||
{
|
||||
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 {
|
||||
|
|
161
newbrt/cachetable-test2.c
Normal file
161
newbrt/cachetable-test2.c
Normal file
|
@ -0,0 +1,161 @@
|
|||
#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
|
||||
|
|
Loading…
Add table
Reference in a new issue