Commit 3b23ec42 authored by Rich Prohaska's avatar Rich Prohaska

merge new cachetable tests. addresses #1075

git-svn-id: file:///svn/tokudb@5797 c7de825b-a66e-492c-adef-691d508d4ae1
parent f0493df4
...@@ -627,7 +627,7 @@ int toku_cachetable_unpin(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash, ...@@ -627,7 +627,7 @@ int toku_cachetable_unpin(CACHEFILE cachefile, CACHEKEY key, u_int32_t fullhash,
} }
} }
note_hash_count(count); note_hash_count(count);
return 0; return -1;
} }
// effect: Move an object from one key to another key. // effect: Move an object from one key to another key.
......
...@@ -33,8 +33,8 @@ FORMAT=-Wmissing-format-attribute ...@@ -33,8 +33,8 @@ FORMAT=-Wmissing-format-attribute
endif endif
CFLAGS = -Wall -Wextra -Wcast-align -Wbad-function-cast -Wmissing-noreturn $(FORMAT) $(OPTFLAGS) -g3 -ggdb3 $(GCOV_FLAGS) $(PROF_FLAGS) -Werror $(FPICFLAGS) $(SHADOW) $(VISIBILITY) CFLAGS = -Wall -Wextra -Wcast-align -Wbad-function-cast -Wmissing-noreturn $(FORMAT) $(OPTFLAGS) -g3 -ggdb3 $(GCOV_FLAGS) $(PROF_FLAGS) -Werror $(FPICFLAGS) $(SHADOW) $(VISIBILITY)
LDFLAGS = $(OPTFLAGS) -g $(GCOV_FLAGS) $(PROF_FLAGS) LDFLAGS = $(OPTFLAGS) -g $(GCOV_FLAGS) $(PROF_FLAGS) -lpthread
CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_XOPEN_SOURCE=500 -I.. CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -I..
# Add -Wconversion # Add -Wconversion
...@@ -63,6 +63,12 @@ REGRESSION_TESTS = \ ...@@ -63,6 +63,12 @@ REGRESSION_TESTS = \
brt-test5 \ brt-test5 \
cachetable-test \ cachetable-test \
cachetable-test2 \ cachetable-test2 \
cachetable-put-test \
cachetable-unpin-test \
cachetable-rename-test \
cachetable-fd-test \
cachetable-count-pinned-test \
cachetable-checkpoint-test \
fifo-test \ fifo-test \
list-test \ list-test \
keyrange \ keyrange \
......
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
const int item_size = 1;
int n_flush, n_write_me, n_keep_me, n_fetch;
void flush(CACHEFILE cf, CACHEKEY key, void *value, long size, BOOL write_me, BOOL keep_me, LSN modified_lsn, BOOL rename_p) {
cf = cf; modified_lsn = modified_lsn; rename_p = rename_p;
assert(key == (CACHEKEY)(long)value);
assert(size == item_size);
n_flush++;
if (write_me) n_write_me++;
if (keep_me) n_keep_me++;
}
int fetch() {
n_fetch++;
return 0;
}
// put n items into the cachetable, maybe mark them dirty, do a checkpoint, and
// verify that all of the items have been written and are clean.
void cachetable_checkpoint_test(int n, int dirty) {
const int test_limit = n;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE f1;
r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
// insert items into the cachetable. all should be dirty
int i;
for (i=0; i<n; i++) {
u_int32_t hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
r = toku_cachetable_unpin(f1, i, hi, dirty, item_size);
assert(r == 0);
void *v;
int its_dirty;
long long its_pin;
long its_size;
r = toku_cachetable_get_key_state(ct, i, f1, &v, &its_dirty, &its_pin, &its_size);
if (r != 0)
continue;
assert(its_dirty == CACHETABLE_DIRTY);
assert(its_pin == 0);
assert(its_size == item_size);
}
// the checkpoint should cause n writes, but since n <= the cachetable size,
// all items should be kept in the cachetable
n_flush = n_write_me = n_keep_me = n_fetch = 0;
r = toku_cachetable_checkpoint(ct);
assert(r == 0);
assert(n_flush == n && n_write_me == n && n_keep_me == n);
// after the checkpoint, all of the items should be clean
for (i=0; i<n; i++) {
u_int32_t hi = toku_cachetable_hash(f1, i);
void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
if (r != 0)
continue;
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, item_size);
assert(r == 0);
int its_dirty;
long long its_pin;
long its_size;
r = toku_cachetable_get_key_state(ct, i, f1, &v, &its_dirty, &its_pin, &its_size);
if (r != 0)
continue;
assert(its_dirty == CACHETABLE_CLEAN);
assert(its_pin == 0);
assert(its_size == item_size);
}
// a subsequent checkpoint should cause n flushes, but no writes since all
// of the items are clean
n_flush = n_write_me = n_keep_me = n_fetch = 0;
r = toku_cachetable_checkpoint(ct);
assert(r == 0);
assert(n_flush == n && n_write_me == 0 && n_keep_me == n);
r = toku_cachefile_close(&f1, NULL_LOGGER); assert(r == 0 && f1 == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
for (i=0; i<8; i++) {
cachetable_checkpoint_test(i, CACHETABLE_CLEAN);
cachetable_checkpoint_test(i, CACHETABLE_DIRTY);
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
void flush() {
}
int fetch() {
return 0;
}
void cachetable_count_pinned_test(int n) {
const int test_limit = 2*n;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE f1;
r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
int i;
for (i=1; i<=n; i++) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
}
for (i=n; i>0; i--) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
if (i-1) assert(toku_cachetable_assert_all_unpinned(ct));
assert(toku_cachefile_count_pinned(f1, 0) == i-1);
}
assert(toku_cachetable_assert_all_unpinned(ct) == 0);
assert(toku_cachefile_count_pinned(f1, 1) == 0);
toku_cachetable_verify(ct);
r = toku_cachefile_close(&f1, NULL_LOGGER); assert(r == 0 && f1 == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
cachetable_count_pinned_test(8);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
void cachetable_fd_test() {
const int test_limit = 1;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE cf;
r = toku_cachetable_openf(&cf, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
int fd1 = toku_cachefile_fd(cf); assert(fd1 >= 0);
// test set to good fd succeeds
char fname2[] = __FILE__ "test2.data";
unlink(fname2);
int fd2 = open(fname2, O_RDWR + O_CREAT); assert(fd2 >= 0 && fd1 != fd2);
r = toku_cachefile_set_fd(cf, fd2, fname2); assert(r == 0);
assert(toku_cachefile_fd(cf) == fd2);
// test set to bogus fd fails
int fd3 = open("/dev/null", O_RDWR); assert(fd3 >= 0);
r = close(fd3); assert(r == 0);
r = toku_cachefile_set_fd(cf, fd3, "/dev/null"); assert(r != 0);
assert(toku_cachefile_fd(cf) == fd2);
r = toku_cachefile_close(&cf, NULL_LOGGER); assert(r == 0 && cf == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
cachetable_fd_test();
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
void flush() {
}
int fetch() {
return 0;
}
void test_cachetable_flush(int n) {
const int test_limit = 2*n;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE f1;
r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
char fname2[] = __FILE__ "test2.dat";
unlink(fname2);
CACHEFILE f2;
r = toku_cachetable_openf(&f2, ct, fname2, O_RDWR|O_CREAT, 0777); assert(r == 0);
// insert keys 0..n-1
int i;
for (i=0; i<n; i++) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
hi = toku_cachetable_hash(f2, i);
r = toku_cachetable_put(f2, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
}
toku_cachetable_verify(ct);
// verify keys exists
for (i=0; i<n; i++) {
u_int32_t hi;
void *v;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
assert(r == 0 && v == (void *)(long)i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
hi = toku_cachetable_hash(f2, i);
r = toku_cachetable_maybe_get_and_pin(f2, i, hi, &v);
assert(r == 0 && v == (void *)(long)i);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
}
// flush
r = toku_cachefile_flush(f1); assert(r == 0);
toku_cachefile_verify(f1);
// verify keys do not exist in f1 but do exist in f2
for (i=0; i<n; i++) {
u_int32_t hi;
void *v;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
assert(r != 0);
hi = toku_cachetable_hash(f2, i);
r = toku_cachetable_maybe_get_and_pin(f2, i, hi, &v);
assert(r == 0);
r = toku_cachetable_unpin(f2, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
}
r = toku_cachefile_close(&f1, NULL_LOGGER); assert(r == 0 && f1 == 0);
r = toku_cachefile_close(&f2, NULL_LOGGER); assert(r == 0 && f2 == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
test_cachetable_flush(8);
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
void flush() {
}
int fetch() {
return 0;
}
void cachetable_put_test(int n) {
const int test_limit = 2*n;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE f1;
r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
int i;
for (i=1; i<=n; i++) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == -1);
assert(toku_cachefile_count_pinned(f1, 0) == i);
// the second put returns an error put increments the pin count, so we have
// to unpin it here
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
}
for (i=n; i>0; i--) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i-1);
}
assert(toku_cachefile_count_pinned(f1, 1) == 0);
toku_cachetable_verify(ct);
CACHEKEY k = n+1;
r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1);
assert(r != 0);
r = toku_cachefile_close(&f1, NULL_LOGGER); assert(r == 0 && f1 == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
cachetable_put_test(8);
return 0;
}
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2007, 2008 Tokutek Inc. All rights reserved."
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include <pthread.h>
#include "toku_assert.h"
#include "memory.h"
#include "cachetable.h"
#include "test.h"
// this mutex is used by some of the tests to serialize access to some
// global data, especially between the test thread and the cachetable
// writeback threads
pthread_mutex_t test_mutex;
static inline void test_mutex_init() {
int r = pthread_mutex_init(&test_mutex, 0); assert(r == 0);
}
static inline void test_mutex_destroy() {
int r = pthread_mutex_destroy(&test_mutex); assert(r == 0);
}
static inline void test_mutex_lock() {
int r = pthread_mutex_lock(&test_mutex); assert(r == 0);
}
static inline void test_mutex_unlock() {
int r = pthread_mutex_unlock(&test_mutex); assert(r == 0);
}
enum { KEYLIMIT = 4, TRIALLIMIT=256000 };
static CACHEKEY keys[KEYLIMIT];
static void* vals[KEYLIMIT];
static int n_keys=0;
static void r_flush (CACHEFILE f __attribute__((__unused__)),
CACHEKEY k, void *value,
long size __attribute__((__unused__)),
BOOL write_me __attribute__((__unused__)),
BOOL keep_me,
LSN modified_lsn __attribute__((__unused__)),
BOOL rename_p __attribute__((__unused__))) {
int i;
//printf("Flush\n");
if (keep_me) return;
test_mutex_lock();
for (i=0; i<n_keys; i++) {
if (keys[i]==k) {
assert(vals[i]==value);
if (!keep_me) {
if (verbose) printf("%s: %d/%d %llx\n", __FUNCTION__, i, n_keys, k);
keys[i]=keys[n_keys-1];
vals[i]=vals[n_keys-1];
n_keys--;
test_mutex_unlock();
return;
}
}
}
fprintf(stderr, "Whoops\n");
abort();
test_mutex_unlock();
}
static int r_fetch (CACHEFILE f __attribute__((__unused__)),
CACHEKEY key __attribute__((__unused__)),
u_int32_t fullhash __attribute__((__unused__)),
void**value __attribute__((__unused__)),
long *sizep __attribute__((__unused__)),
void*extraargs __attribute__((__unused__)),
LSN *modified_lsn __attribute__((__unused__))) {
// fprintf(stderr, "Whoops, this should never be called");
return -42;
}
static void test_rename (void) {
CACHETABLE t;
CACHEFILE f;
int i;
int r;
test_mutex_init();
const char fname[] = __FILE__ "rename.dat";
r=toku_create_cachetable(&t, KEYLIMIT, ZERO_LSN, NULL_LOGGER); assert(r==0);
unlink(fname);
r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, 0777);
assert(r==0);
for (i=0; i<TRIALLIMIT; i++) {
int ra = random()%3;
if (ra<=1) {
// Insert something
CACHEKEY nkey = random();
long nval = random();
if (verbose) printf("n_keys=%d Insert %08llx\n", n_keys, nkey);
u_int32_t hnkey = toku_cachetable_hash(f, nkey);
r = toku_cachetable_put(f, nkey, hnkey,
(void*)nval, 1,
r_flush, r_fetch, 0);
assert(r==0);
test_mutex_lock();
while (n_keys >= KEYLIMIT) {
test_mutex_unlock();
pthread_yield();
test_mutex_lock();
}
assert(n_keys<KEYLIMIT);
keys[n_keys] = nkey;
vals[n_keys] = (void*)nval;
n_keys++;
test_mutex_unlock();
r = toku_cachetable_unpin(f, nkey, hnkey, CACHETABLE_DIRTY, 1);
assert(r==0);
} else if (ra==2 && n_keys>0) {
// Rename something
int objnum = random()%n_keys;
CACHEKEY nkey = random();
test_mutex_lock();
CACHEKEY okey = keys[objnum];
test_mutex_unlock();
void *current_value;
long current_size;
if (verbose) printf("Rename %llx to %llx\n", okey, nkey);
r = toku_cachetable_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &current_value, &current_size, r_flush, r_fetch, 0);
if (r == -42) continue;
assert(r==0);
r = toku_cachetable_rename(f, okey, nkey);
assert(r==0);
test_mutex_lock();
// assert(objnum < n_keys && keys[objnum] == okey);
// get_and_pin may reorganize the keys[], so we need to find it again
int j;
for (j=0; j < n_keys; j++)
if (keys[j] == okey)
break;
assert(j < n_keys);
keys[j]=nkey;
test_mutex_unlock();
r = toku_cachetable_unpin(f, nkey, toku_cachetable_hash(f, nkey), CACHETABLE_DIRTY, 1);
}
}
// test rename fails if old key does not exist in the cachetable
CACHEKEY okey, nkey;
while (1) {
okey = random();
void *v;
r = toku_cachetable_maybe_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &v);
if (r != 0)
break;
r = toku_cachetable_unpin(f, okey, toku_cachetable_hash(f, okey), CACHETABLE_CLEAN, 1);
assert(r == 0);
}
nkey = random();
r = toku_cachetable_rename(f, okey, nkey);
assert(r != 0);
r = toku_cachefile_close(&f, 0);
assert(r == 0);
r = toku_cachetable_close(&t);
assert(r == 0);
test_mutex_destroy();
assert(n_keys == 0);
}
int main (int argc, const char *argv[]) {
// defaults
int do_malloc_fail = 0;
// parse args
int i;
for (i=1; i<argc; i++) {
const char *arg = argv[i];
if (strcmp(arg, "-v") == 0) {
verbose++;
continue;
}
if (strcmp(arg, "-malloc-fail") == 0) {
do_malloc_fail = 1;
continue;
}
}
// run tests
for (i=0; i<1; i++)
test_rename();
return 0;
}
...@@ -6,12 +6,71 @@ ...@@ -6,12 +6,71 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <malloc.h>
#include <errno.h>
#include <pthread.h>
#include "toku_assert.h" #include "toku_assert.h"
#include "memory.h" #include "memory.h"
#include "cachetable.h" #include "cachetable.h"
#include "test.h" #include "test.h"
// this mutex is used by some of the tests to serialize access to some
// global data, especially between the test thread and the cachetable
// writeback threads
pthread_mutex_t test_mutex;
static inline void test_mutex_init() {
int r = pthread_mutex_init(&test_mutex, 0); assert(r == 0);
}
static inline void test_mutex_destroy() {
int r = pthread_mutex_destroy(&test_mutex); assert(r == 0);
}
static inline void test_mutex_lock() {
int r = pthread_mutex_lock(&test_mutex); assert(r == 0);
}
static inline void test_mutex_unlock() {
int r = pthread_mutex_unlock(&test_mutex); assert(r == 0);
}
// hook my_malloc_always_fails into malloc to control malloc and verify
// the correct recovery from malloc failures
#define DO_MALLOC_HOOK 1
#if DO_MALLOC_HOOK
static void *my_malloc_always_fails(size_t n, const __malloc_ptr_t p) {
n = n; p = p;
return 0;
}
#endif
// verify that cachetable creation and close works
void test_cachetable_create() {
CACHETABLE ct = 0;
int r;
r = toku_create_cachetable(&ct, 0, ZERO_LSN, NULL_LOGGER);
assert(r == 0);
r = toku_cachetable_close(&ct);
assert(r == 0 && ct == 0);
}
// verify that cachetable create with no memory returns ENOMEM
void test_cachetable_create_no_memory() {
void *(*orig_malloc_hook)(size_t, const __malloc_ptr_t) = __malloc_hook;
__malloc_hook = my_malloc_always_fails;
CACHETABLE ct = 0;
int r;
r = toku_create_cachetable(&ct, 0, ZERO_LSN, NULL_LOGGER);
assert(r == ENOMEM);
__malloc_hook = orig_malloc_hook;
}
static const int test_object_size = 1; static const int test_object_size = 1;
struct item { struct item {
...@@ -19,14 +78,16 @@ struct item { ...@@ -19,14 +78,16 @@ struct item {
char *something; char *something;
}; };
static int expect_n_flushes=0; static volatile int expect_n_flushes=0;
static CACHEKEY flushes[100]; static volatile CACHEKEY flushes[100];
static void expect1(CACHEKEY key) { static void expect1(CACHEKEY key) {
expect_n_flushes=1; expect_n_flushes=1;
flushes[0]=key; flushes[0]=key;
if (verbose) printf("%s:%d %lld\n", __FUNCTION__, 0, key);
} }
static void expectN(CACHEKEY key) { static void expectN(CACHEKEY key) {
if (verbose) printf("%s:%d %lld\n", __FUNCTION__, expect_n_flushes, key);
flushes[expect_n_flushes++]=key; flushes[expect_n_flushes++]=key;
} }
...@@ -36,6 +97,8 @@ static void flush (CACHEFILE f, CACHEKEY key, void*value, long size __attribute_ ...@@ -36,6 +97,8 @@ static void flush (CACHEFILE f, CACHEKEY key, void*value, long size __attribute_
struct item *it = value; struct item *it = value;
int i; int i;
if (keep_me) return;
if (verbose) printf("Flushing %lld (it=>key=%lld)\n", key, it->key); if (verbose) printf("Flushing %lld (it=>key=%lld)\n", key, it->key);
assert(expect_f==f); assert(expect_f==f);
...@@ -74,6 +137,8 @@ static int fetch (CACHEFILE f, CACHEKEY key, u_int32_t fullhash __attribute__((_ ...@@ -74,6 +137,8 @@ static int fetch (CACHEFILE f, CACHEKEY key, u_int32_t fullhash __attribute__((_
return 0; return 0;
} }
// verify that a sequence of cachetable operations causes a particular sequence of
// callbacks
static void test0 (void) { static void test0 (void) {
void* t3=(void*)23; void* t3=(void*)23;
...@@ -128,12 +193,14 @@ static void test0 (void) { ...@@ -128,12 +193,14 @@ static void test0 (void) {
expect1(2); /* 2 is the oldest unpinned item. */ expect1(2); /* 2 is the oldest unpinned item. */
r=toku_cachetable_put(f, 6, h6, make_item(6), test_object_size, flush, fetch, t3); /* 6P 5U 4P 3U 1P */ r=toku_cachetable_put(f, 6, h6, make_item(6), test_object_size, flush, fetch, t3); /* 6P 5U 4P 3U 1P */
assert(r==0); assert(r==0);
while (expect_n_flushes != 0) pthread_yield();
assert(expect_n_flushes==0); assert(expect_n_flushes==0);
expect1(3); expect1(3);
r=toku_cachetable_put(f, 7, h7, make_item(7), test_object_size, flush, fetch, t3); r=toku_cachetable_put(f, 7, h7, make_item(7), test_object_size, flush, fetch, t3);
assert(r==0); assert(r==0);
while (expect_n_flushes != 0) pthread_yield();
assert(expect_n_flushes==0); assert(expect_n_flushes==0);
r=toku_cachetable_unpin(f, 7, h7, CACHETABLE_DIRTY, test_object_size); /* 7U 6P 5U 4P 1P */ r=toku_cachetable_unpin(f, 7, h7, CACHETABLE_DIRTY, test_object_size); /* 7U 6P 5U 4P 1P */
assert(r==0); assert(r==0);
...@@ -159,6 +226,7 @@ static void test0 (void) { ...@@ -159,6 +226,7 @@ static void test0 (void) {
assert(did_fetch==2); /* Expect that 2 is fetched in. */ assert(did_fetch==2); /* Expect that 2 is fetched in. */
assert(((struct item *)item_v)->key==2); assert(((struct item *)item_v)->key==2);
assert(strcmp(((struct item *)item_v)->something,"something")==0); assert(strcmp(((struct item *)item_v)->something,"something")==0);
while (expect_n_flushes != 0) pthread_yield();
assert(expect_n_flushes==0); assert(expect_n_flushes==0);
} }
...@@ -234,14 +302,17 @@ static void test_nested_pin (void) { ...@@ -234,14 +302,17 @@ static void test_nested_pin (void) {
assert(r==0); assert(r==0);
assert(vv2==vv); assert(vv2==vv);
r = toku_cachetable_unpin(f, 1, f1hash, 0, test_object_size); r = toku_cachetable_unpin(f, 1, f1hash, 0, test_object_size);
r = toku_cachetable_put(f, 2, toku_cachetable_hash(f, 2), &i1, test_object_size, flush_n, fetch_n, f2); assert(r==0);
u_int32_t f2hash = toku_cachetable_hash(f, 2);
r = toku_cachetable_put(f, 2, f2hash, &i1, test_object_size, flush_n, fetch_n, f2);
assert(r==0); // The other one is pinned, but now the cachetable fails gracefully: It allows the pin to happen assert(r==0); // The other one is pinned, but now the cachetable fails gracefully: It allows the pin to happen
r = toku_cachetable_unpin(f, 1, f1hash, 0, test_object_size); r = toku_cachetable_unpin(f, 1, f1hash, 0, test_object_size);
assert(r==0); assert(r==0);
r = toku_cachetable_unpin(f, 2, f2hash, 0, test_object_size);
assert(r==0);
// sleep(1);
r = toku_cachefile_close(&f, 0); assert(r==0); r = toku_cachefile_close(&f, 0); assert(r==0);
r = toku_cachetable_close(&t); assert(r==0); r = toku_cachetable_close(&t); assert(r==0);
} }
...@@ -254,6 +325,7 @@ static void null_flush (CACHEFILE cf __attribute__((__unused__)), ...@@ -254,6 +325,7 @@ static void null_flush (CACHEFILE cf __attribute__((__unused__)),
LSN modified_lsn __attribute__((__unused__)), LSN modified_lsn __attribute__((__unused__)),
BOOL rename_p __attribute__((__unused__))) { BOOL rename_p __attribute__((__unused__))) {
} }
static int add123_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) { static int add123_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) {
assert(fullhash==toku_cachetable_hash(cf,key)); assert(fullhash==toku_cachetable_hash(cf,key));
assert((long)extraargs==123); assert((long)extraargs==123);
...@@ -261,6 +333,7 @@ static int add123_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void ** ...@@ -261,6 +333,7 @@ static int add123_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **
written_lsn->lsn = 0; written_lsn->lsn = 0;
return 0; return 0;
} }
static int add222_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) { static int add222_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **value, long *sizep __attribute__((__unused__)), void*extraargs, LSN *written_lsn) {
assert(fullhash==toku_cachetable_hash(cf,key)); assert(fullhash==toku_cachetable_hash(cf,key));
assert((long)extraargs==222); assert((long)extraargs==222);
...@@ -269,7 +342,6 @@ static int add222_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void ** ...@@ -269,7 +342,6 @@ static int add222_fetch (CACHEFILE cf, CACHEKEY key, u_int32_t fullhash, void **
return 0; return 0;
} }
static void test_multi_filehandles (void) { static void test_multi_filehandles (void) {
CACHETABLE t; CACHETABLE t;
CACHEFILE f1,f2,f3; CACHEFILE f1,f2,f3;
...@@ -300,9 +372,17 @@ static void test_multi_filehandles (void) { ...@@ -300,9 +372,17 @@ static void test_multi_filehandles (void) {
r = toku_cachetable_maybe_get_and_pin(f1, 2, toku_cachetable_hash(f1, 2), &v); assert(r==0); r = toku_cachetable_maybe_get_and_pin(f1, 2, toku_cachetable_hash(f1, 2), &v); assert(r==0);
assert((unsigned long)v==125); assert((unsigned long)v==125);
r = toku_cachetable_unpin(f1, 1, toku_cachetable_hash(f1, 1), CACHETABLE_CLEAN, 0); assert(r==0);
r = toku_cachetable_unpin(f1, 2, toku_cachetable_hash(f1, 2), CACHETABLE_CLEAN, 0); assert(r==0);
r = toku_cachefile_close(&f1, 0); assert(r==0); r = toku_cachefile_close(&f1, 0); assert(r==0);
r = toku_cachetable_unpin(f2, 1, toku_cachetable_hash(f2, 1), CACHETABLE_CLEAN, 0); assert(r==0);
r = toku_cachetable_unpin(f2, 2, toku_cachetable_hash(f2, 2), CACHETABLE_CLEAN, 0); assert(r==0);
r = toku_cachefile_close(&f2, 0); assert(r==0); r = toku_cachefile_close(&f2, 0); assert(r==0);
r = toku_cachetable_unpin(f3, 2, toku_cachetable_hash(f3, 2), CACHETABLE_CLEAN, 0); assert(r==0);
r = toku_cachefile_close(&f3, 0); assert(r==0); r = toku_cachefile_close(&f3, 0); assert(r==0);
r = toku_cachetable_close(&t); assert(r==0); r = toku_cachetable_close(&t); assert(r==0);
} }
...@@ -425,8 +505,10 @@ static CACHEKEY test_size_flush_key; ...@@ -425,8 +505,10 @@ static CACHEKEY test_size_flush_key;
static void test_size_flush_callback(CACHEFILE f, CACHEKEY key, void *value, long size, BOOL do_write, BOOL keep, LSN modified_lsn __attribute__((__unused__)), BOOL rename_p __attribute__((__unused__))) { static void test_size_flush_callback(CACHEFILE f, CACHEKEY key, void *value, long size, BOOL do_write, BOOL keep, LSN modified_lsn __attribute__((__unused__)), BOOL rename_p __attribute__((__unused__))) {
if (test_size_debug && verbose) printf("test_size_flush %p %lld %p %ld %d %d\n", f, key, value, size, do_write, keep); if (test_size_debug && verbose) printf("test_size_flush %p %lld %p %ld %d %d\n", f, key, value, size, do_write, keep);
if (keep) {
assert(do_write != 0); assert(do_write != 0);
test_size_flush_key = key; test_size_flush_key = key;
}
} }
static void test_size_resize() { static void test_size_resize() {
...@@ -513,9 +595,13 @@ static void test_size_flush() { ...@@ -513,9 +595,13 @@ static void test_size_flush() {
r = toku_cachetable_put(f, key, hkey, value, size, test_size_flush_callback, 0, 0); r = toku_cachetable_put(f, key, hkey, value, size, test_size_flush_callback, 0, 0);
assert(r == 0); assert(r == 0);
int n_entries; int n_entries, hash_size; long size_current, size_limit;
toku_cachetable_get_state(t, &n_entries, 0, 0, 0); toku_cachetable_get_state(t, &n_entries, &hash_size, &size_current, &size_limit);
int min2(int a, int b) { return a < b ? a : b; } int min2(int a, int b) { return a < b ? a : b; }
while (n_entries != min2(i+1, n)) {
pthread_yield();
toku_cachetable_get_state(t, &n_entries, 0, 0, 0);
}
assert(n_entries == min2(i+1, n)); assert(n_entries == min2(i+1, n));
void *entry_value; int dirty; long long pinned; long entry_size; void *entry_value; int dirty; long long pinned; long entry_size;
...@@ -542,109 +628,37 @@ static void test_size_flush() { ...@@ -542,109 +628,37 @@ static void test_size_flush() {
assert(r == 0); assert(r == 0);
} }
enum { KEYLIMIT = 4, TRIALLIMIT=64 }; int main (int argc, const char *argv[]) {
static CACHEKEY keys[KEYLIMIT]; // defaults
static void* vals[KEYLIMIT]; int do_malloc_fail = 0;
static int n_keys=0;
static void r_flush (CACHEFILE f __attribute__((__unused__)), // parse args
CACHEKEY k, void *value,
long size __attribute__((__unused__)),
BOOL write_me __attribute__((__unused__)),
BOOL keep_me,
LSN modified_lsn __attribute__((__unused__)),
BOOL rename_p __attribute__((__unused__))) {
int i; int i;
//printf("Flush\n"); for (i=1; i<argc; i++) {
for (i=0; i<n_keys; i++) { const char *arg = argv[i];
if (keys[i]==k) { if (strcmp(arg, "-v") == 0) {
assert(vals[i]==value); verbose++;
if (!keep_me) { continue;
keys[i]=keys[n_keys-1];
vals[i]=vals[n_keys-1];
n_keys--;
return;
} }
if (strcmp(arg, "-malloc-fail") == 0) {
do_malloc_fail = 1;
continue;
} }
} }
fprintf(stderr, "Whoops\n");
abort();
}
static int r_fetch (CACHEFILE f __attribute__((__unused__)),
CACHEKEY key __attribute__((__unused__)),
u_int32_t fullhash __attribute__((__unused__)),
void**value __attribute__((__unused__)),
long *sizep __attribute__((__unused__)),
void*extraargs __attribute__((__unused__)),
LSN *modified_lsn __attribute__((__unused__))) {
fprintf(stderr, "Whoops, this should never be called");
return 0;
}
static void test_rename (void) {
CACHETABLE t;
CACHEFILE f;
int i;
int r;
const char fname[] = __FILE__ "rename.dat";
r=toku_create_cachetable(&t, KEYLIMIT, ZERO_LSN, NULL_LOGGER); assert(r==0);
unlink(fname);
r = toku_cachetable_openf(&f, t, fname, O_RDWR|O_CREAT, 0777);
assert(r==0);
for (i=0; i<TRIALLIMIT; i++) { // run tests
int ra = random()%3; test_multi_filehandles();
if (ra<=1) { test_cachetable_create();
// Insert something if (do_malloc_fail)
CACHEKEY nkey = random(); test_cachetable_create_no_memory(); // fails with valgrind
long nval = random(); for (i=0; i<1; i++) {
//printf("n_keys=%d Insert %08llx\n", n_keys, nkey);
u_int32_t hnkey = toku_cachetable_hash(f, nkey);
r = toku_cachetable_put(f, nkey, hnkey,
(void*)nval, 1,
r_flush, r_fetch, 0);
assert(r==0);
assert(n_keys<KEYLIMIT);
keys[n_keys] = nkey;
vals[n_keys] = (void*)nval;
n_keys++;
r = toku_cachetable_unpin(f, nkey, hnkey, CACHETABLE_DIRTY, 1);
assert(r==0);
} else if (ra==2 && n_keys>0) {
// Rename something
int objnum = random()%n_keys;
CACHEKEY okey = keys[objnum];
CACHEKEY nkey = random();
void *current_value;
long current_size;
keys[objnum]=nkey;
//printf("Rename %llx to %llx\n", okey, nkey);
r = toku_cachetable_get_and_pin(f, okey, toku_cachetable_hash(f, okey), &current_value, &current_size, r_flush, r_fetch, 0);
assert(r==0);
r = toku_cachetable_rename(f, okey, nkey);
assert(r==0);
r = toku_cachetable_unpin(f, nkey, toku_cachetable_hash(f, nkey), CACHETABLE_DIRTY, 1);
}
}
r = toku_cachefile_close(&f, 0);
assert(r == 0);
r = toku_cachetable_close(&t);
assert(r == 0);
assert(n_keys == 0);
}
int main (int argc, const char *argv[]) {
default_parse_args(argc, argv);
test_rename();
test0(); test0();
test_nested_pin(); test_nested_pin();
test_multi_filehandles (); test_multi_filehandles ();
test_dirty(); test_dirty();
test_size_resize(); test_size_resize();
test_size_flush(); test_size_flush();
}
toku_malloc_cleanup(); toku_malloc_cleanup();
if (verbose) printf("ok\n"); if (verbose) printf("ok\n");
return 0; return 0;
......
...@@ -9,14 +9,37 @@ ...@@ -9,14 +9,37 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
#include <pthread.h>
#include "test.h" #include "test.h"
// this mutex is used by some of the tests to serialize access to some
// global data, especially between the test thread and the cachetable
// writeback threads
pthread_mutex_t test_mutex;
static inline void test_mutex_init() {
int r = pthread_mutex_init(&test_mutex, 0); assert(r == 0);
}
static inline void test_mutex_destroy() {
int r = pthread_mutex_destroy(&test_mutex); assert(r == 0);
}
static inline void test_mutex_lock() {
int r = pthread_mutex_lock(&test_mutex); assert(r == 0);
}
static inline void test_mutex_unlock() {
int r = pthread_mutex_unlock(&test_mutex); assert(r == 0);
}
static const int test_object_size = 1; static const int test_object_size = 1;
static CACHETABLE ct; static CACHETABLE ct;
enum { N_PRESENT_LIMIT = 4, TRIALS=200, N_FILES=2 }; enum { N_PRESENT_LIMIT = 4, TRIALS=20000, N_FILES=2 };
static int n_present=0; static int n_present=0;
static struct present_items { static struct present_items {
CACHEKEY key; CACHEKEY key;
...@@ -34,33 +57,41 @@ static void print_ints(void) { ...@@ -34,33 +57,41 @@ static void print_ints(void) {
} }
static void item_becomes_present(CACHEFILE cf, CACHEKEY key) { static void item_becomes_present(CACHEFILE cf, CACHEKEY key) {
while (n_present >= N_PRESENT_LIMIT) pthread_yield();
test_mutex_lock();
assert(n_present<N_PRESENT_LIMIT); assert(n_present<N_PRESENT_LIMIT);
present_items[n_present].cf = cf; present_items[n_present].cf = cf;
present_items[n_present].key = key; present_items[n_present].key = key;
n_present++; n_present++;
test_mutex_unlock();
} }
static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) { static void item_becomes_not_present(CACHEFILE cf, CACHEKEY key) {
int i; int i;
//printf("Removing {%4lld %16p}: Initially: ", key, cf); print_ints(); //printf("Removing {%4lld %16p}: Initially: ", key, cf); print_ints();
test_mutex_lock();
assert(n_present<=N_PRESENT_LIMIT); assert(n_present<=N_PRESENT_LIMIT);
for (i=0; i<n_present; i++) { for (i=0; i<n_present; i++) {
if (present_items[i].cf==cf && present_items[i].key==key) { if (present_items[i].cf==cf && present_items[i].key==key) {
present_items[i]=present_items[n_present-1]; present_items[i]=present_items[n_present-1];
n_present--; n_present--;
test_mutex_unlock();
//printf(" Finally: "); print_ints(); //printf(" Finally: "); print_ints();
return; return;
} }
} }
printf("Whoops, %p,%lld was already not present\n", cf ,key); printf("Whoops, %p,%lld was already not present\n", cf ,key);
abort(); abort();
test_mutex_unlock();
} }
static void file_is_not_present(CACHEFILE cf) { static void file_is_not_present(CACHEFILE cf) {
int i; int i;
test_mutex_lock();
for (i=0; i<n_present; i++) { for (i=0; i<n_present; i++) {
assert(present_items[i].cf!=cf); assert(present_items[i].cf!=cf);
} }
test_mutex_unlock();
} }
...@@ -72,6 +103,7 @@ static void flush_forchain (CACHEFILE f __attribute__((__unused__)), ...@@ -72,6 +103,7 @@ static void flush_forchain (CACHEFILE f __attribute__((__unused__)),
BOOL keep_me __attribute__((__unused__)), BOOL keep_me __attribute__((__unused__)),
LSN modified_lsn __attribute__((__unused__)), LSN modified_lsn __attribute__((__unused__)),
BOOL rename_p __attribute__((__unused__))) { BOOL rename_p __attribute__((__unused__))) {
if (keep_me) return;
int *v = value; int *v = value;
//toku_cachetable_print_state(ct); //toku_cachetable_print_state(ct);
//printf("Flush %lld %d\n", key, (int)value); //printf("Flush %lld %d\n", key, (int)value);
...@@ -90,15 +122,25 @@ static int fetch_forchain (CACHEFILE f, CACHEKEY key, u_int32_t fullhash, void** ...@@ -90,15 +122,25 @@ static int fetch_forchain (CACHEFILE f, CACHEKEY key, u_int32_t fullhash, void**
static void verify_cachetable_against_present (void) { static void verify_cachetable_against_present (void) {
int i; int i;
for (i=0; i<n_present; i++) {
again:
test_mutex_lock();
int my_n_present = n_present;
struct present_items my_present_items[N_PRESENT_LIMIT];
for (i=0; i<n_present; i++)
my_present_items[i] = present_items[i];
test_mutex_unlock();
for (i=0; i<my_n_present; i++) {
void *v; void *v;
u_int32_t fullhash = toku_cachetable_hash(present_items[i].cf, present_items[i].key); u_int32_t fullhash = toku_cachetable_hash(my_present_items[i].cf, my_present_items[i].key);
int r=toku_cachetable_maybe_get_and_pin(present_items[i].cf, int r=toku_cachetable_maybe_get_and_pin(my_present_items[i].cf,
present_items[i].key, my_present_items[i].key,
toku_cachetable_hash(present_items[i].cf, present_items[i].key), toku_cachetable_hash(my_present_items[i].cf, my_present_items[i].key),
&v); &v);
if (r == -1) goto again;
assert(r==0); assert(r==0);
r = toku_cachetable_unpin(present_items[i].cf, present_items[i].key, fullhash, CACHETABLE_CLEAN, test_object_size); r = toku_cachetable_unpin(my_present_items[i].cf, my_present_items[i].key, fullhash, CACHETABLE_CLEAN, test_object_size);
} }
} }
...@@ -121,30 +163,37 @@ static void test_chaining (void) { ...@@ -121,30 +163,37 @@ static void test_chaining (void) {
int fnum = i%N_FILES; int fnum = i%N_FILES;
//printf("%s:%d Add %d\n", __FILE__, __LINE__, i); //printf("%s:%d Add %d\n", __FILE__, __LINE__, i);
u_int32_t fhash = toku_cachetable_hash(f[fnum], i); u_int32_t fhash = toku_cachetable_hash(f[fnum], i);
r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i); assert(r==0); r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i);
assert(r==0);
item_becomes_present(f[fnum], i); item_becomes_present(f[fnum], i);
r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size); assert(r==0); r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size);
assert(r==0);
//print_ints(); //print_ints();
} }
test_mutex_init();
for (trial=0; trial<TRIALS; trial++) { for (trial=0; trial<TRIALS; trial++) {
if (n_present>0) { if (n_present>0) {
// First touch some random ones // First touch some random ones
test_mutex_lock();
int whichone = random()%n_present; int whichone = random()%n_present;
CACHEFILE whichcf = present_items[whichone].cf;
CACHEKEY whichkey = present_items[whichone].key;
test_mutex_unlock();
void *value; void *value;
//printf("Touching %d (%lld, %p)\n", whichone, present_items[whichone].key, present_items[whichone].cf); //printf("Touching %d (%lld, %p)\n", whichone, whichkey, whichcf);
u_int32_t fhash = toku_cachetable_hash(present_items[whichone].cf, present_items[whichone].key); u_int32_t fhash = toku_cachetable_hash(whichcf, whichkey);
r = toku_cachetable_get_and_pin(present_items[whichone].cf, r = toku_cachetable_get_and_pin(whichcf,
present_items[whichone].key, whichkey,
fhash, fhash,
&value, &value,
NULL, NULL,
flush_forchain, flush_forchain,
fetch_forchain, fetch_forchain,
(void*)(long)present_items[whichone].key (void*)(long)whichkey
); );
assert(r==0); assert(r==0);
r = toku_cachetable_unpin(present_items[whichone].cf, r = toku_cachetable_unpin(whichcf,
present_items[whichone].key, whichkey,
fhash, fhash,
CACHETABLE_CLEAN, test_object_size); CACHETABLE_CLEAN, test_object_size);
assert(r==0); assert(r==0);
...@@ -153,13 +202,22 @@ static void test_chaining (void) { ...@@ -153,13 +202,22 @@ static void test_chaining (void) {
i += 1+ random()%100; i += 1+ random()%100;
int fnum = i%N_FILES; int fnum = i%N_FILES;
// i is always incrementing, so we need not worry about inserting a duplicate // 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]); // if i is a duplicate, cachetable_put will return -1
// printf("%s:%d Add {%ld,%p}\n", __FILE__, __LINE__, i, f[fnum]);
u_int32_t fhash = toku_cachetable_hash(f[fnum], i); u_int32_t fhash = toku_cachetable_hash(f[fnum], i);
r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i); assert(r==0); r = toku_cachetable_put(f[fnum], i, fhash, (void*)i, test_object_size, flush_forchain, fetch_forchain, (void*)i);
assert(r==0 || r==-1);
if (r==0) {
item_becomes_present(f[fnum], i); item_becomes_present(f[fnum], i);
//print_ints(); //print_ints();
//cachetable_print_state(ct); //cachetable_print_state(ct);
r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size); assert(r==0); }
r = toku_cachetable_unpin(f[fnum], i, fhash, CACHETABLE_CLEAN, test_object_size);
assert(r==0);
long long pinned;
r = toku_cachetable_get_key_state(ct, i, f[fnum], 0, 0, &pinned, 0);
assert(r==0);
assert(pinned == 0);
verify_cachetable_against_present(); verify_cachetable_against_present();
if (random()%10==0) { if (random()%10==0) {
...@@ -176,6 +234,7 @@ static void test_chaining (void) { ...@@ -176,6 +234,7 @@ static void test_chaining (void) {
r = toku_cachefile_close(&f[i], 0); assert(r==0); r = toku_cachefile_close(&f[i], 0); assert(r==0);
} }
r = toku_cachetable_close(&ct); assert(r==0); r = toku_cachetable_close(&ct); assert(r==0);
test_mutex_destroy();
} }
void __attribute__((__noreturn__)) usage (const char *progname) { void __attribute__((__noreturn__)) usage (const char *progname) {
......
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include "test.h"
#include "cachetable.h"
void flush() {
}
int fetch() {
return 0;
}
void cachetable_unpin_test(int n) {
const int test_limit = 2*n;
int r;
CACHETABLE ct;
r = toku_create_cachetable(&ct, test_limit, ZERO_LSN, NULL_LOGGER); assert(r == 0);
char fname1[] = __FILE__ "test1.dat";
unlink(fname1);
CACHEFILE f1;
r = toku_cachetable_openf(&f1, ct, fname1, O_RDWR|O_CREAT, 0777); assert(r == 0);
int i;
for (i=1; i<=n; i++) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_put(f1, i, hi, (void *)(long)i, 1, flush, fetch, 0);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
void *v;
r = toku_cachetable_maybe_get_and_pin(f1, i, hi, &v);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i);
}
for (i=n; i>0; i--) {
u_int32_t hi;
hi = toku_cachetable_hash(f1, i);
r = toku_cachetable_unpin(f1, i, hi, CACHETABLE_CLEAN, 1);
assert(r == 0);
assert(toku_cachefile_count_pinned(f1, 0) == i-1);
}
assert(toku_cachefile_count_pinned(f1, 1) == 0);
toku_cachetable_verify(ct);
CACHEKEY k = n+1;
r = toku_cachetable_unpin(f1, k, toku_cachetable_hash(f1, k), CACHETABLE_CLEAN, 1);
assert(r != 0);
r = toku_cachefile_close(&f1, NULL_LOGGER); assert(r == 0 && f1 == 0);
r = toku_cachetable_close(&ct); assert(r == 0 && ct == 0);
}
int main(int argc, const char *argv[]) {
int i;
for (i=1; i<argc; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose++;
continue;
}
}
cachetable_unpin_test(8);
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