Commit d2744a29 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 b3565057
...@@ -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;
}
This diff is collapsed.
...@@ -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