Commit 518cebbb authored by Dave Wells's avatar Dave Wells Committed by Yoni Fogel

now randomly aborts before, during, or after the last checkpoint

git-svn-id: file:///svn/toku/tokudb@16217 c7de825b-a66e-492c-adef-691d508d4ae1
parent 2c913f13
/* -*- mode: C; c-basic-offset: 4 -*_ */
/* -*- mode: C; c-basic-offset: 4 -*- */
#ident "Copyright (c) 2009 Tokutek Inc. All rights reserved."
#ident "$Id$"
......@@ -7,23 +7,24 @@
#include <db.h>
#include <sys/stat.h>
#include <stdlib.h>
//#include "checkpoint_test.h"
static const int OPER_PER_STEP = 3;
//static const int NUM_DICTIONARIES = 100;
static const int NUM_DICTIONARIES = 3;
static const char *table = "tbl";
static const int ROWS_PER_TABLE = 10;
DB_ENV *env;
DB** db_array;
DB* states;
static const int percent_do_op = 20;
char *state_db_name="states.db";
#define CREATED 0
#define OPEN 1
#define CLOSED 2
#define DELETED 3
DB* db_array;
DB* states;
static void put_state(int db_num, int state) {
int r;
DB_TXN* txn;
......@@ -41,11 +42,9 @@ static void put_state(int db_num, int state) {
static int get_state(int db_num) {
int r;
DBT key, val;
// int key_data = db_num;
memset(&val, 0, sizeof(val));
r = states->get(states, 0,
// dbt_init(&key, &key_data, sizeof(key_data)),
dbt_init(&key, &db_num, sizeof(db_num)),
&val,
0);
......@@ -54,59 +53,76 @@ static int get_state(int db_num) {
return state;
}
static int crash_timer;
static void crash_it(void);
static void set_crash_timer(void) {
crash_timer = random() % (3 * NUM_DICTIONARIES);
}
static void update_crash_timer(void) {
if ( --crash_timer == 0 ) {
if ( verbose ) {
printf("%s : crash\n", __FILE__);
fflush(stdout);
}
crash_it();
}
}
static void env_startup(int recovery_flags);
static int64_t generate_val(int64_t key);
static void insert_n(DB *db, DB_TXN *txn, int firstkey, int n);
static void verify_dbremove(DB* db);
static int verify_identical_dbts(const DBT *dbt1, const DBT *dbt2);
static void verify_sequential_rows(DB* compare_db, int64_t firstkey, int64_t numkeys);
static void crash_it(void);
static void do_create(DB* db, char* name, int* next_state) {
static DB* do_create(char* name, int* next_state) {
DB* db;
if ( verbose ) printf("%s : do_create(%s)\n", __FILE__, name);
int r;
r = db_create(&db, env, 0);
DB_TXN* txn;
r = db_create(&db, env, 0);
CKERR(r);
r = db->open(db, NULL, name, NULL, DB_BTREE, DB_AUTO_COMMIT | DB_CREATE, 0666);
r = db->open(db, NULL, name, NULL, DB_BTREE, DB_CREATE, 0666);
CKERR(r);
DB_TXN* txn;
r = env->txn_begin(env, NULL, &txn, 0);
r = env->txn_begin(env, NULL, &txn, 0);
CKERR(r);
insert_n(db, txn, 0, ROWS_PER_TABLE);
r = txn->commit(txn, 0);
r = txn->commit(txn, 0);
CKERR(r);
*next_state = CREATED;
return db;
}
static void do_open(DB* db, char* name, int* next_state) {
static DB* do_open(char* name, int* next_state) {
DB* db;
if ( verbose ) printf("%s : do_open(%s)\n", __FILE__, name);
int r;
r = db_create(&db, env, 0);
CKERR(r);
r = db->open(db, NULL, name, NULL, DB_UNKNOWN, DB_AUTO_COMMIT, 0666);
r = db->open(db, NULL, name, NULL, DB_UNKNOWN, 0, 0666);
CKERR(r);
*next_state = OPEN;
return db;
}
static void do_close(DB* db, char *name UU(), int* next_state) {
static void do_close(DB* db, char* name, int* next_state) {
if ( verbose ) printf("%s : do_close(%s)\n", __FILE__, name);
if (!db) printf("db == NULL\n");
int r = db->close(db, 0);
printf("do_closed\n");
CKERR(r);
*next_state = CLOSED;
}
static void do_delete(DB* db UU(), char* name, int* next_state) {
static void do_delete(char* name, int* next_state) {
if ( verbose ) printf("%s : do_delete(%s)\n", __FILE__, name);
int r = env->dbremove(env, NULL, name, NULL, 0);
CKERR(r);
*next_state = DELETED;
}
static const int percent_do_op = 10;
static int do_random_fileop(DB* db, int i, int state) {
static int do_random_fileop(int i, int state) {
DB* db = db_array[i];
int rval = random() % 100;
// if ( verbose ) printf("%s : %s : DB '%d', state '%d, rval '%d'\n", __FILE__, __FUNCTION__, i, state, rval);
......@@ -117,37 +133,52 @@ static int do_random_fileop(DB* db, int i, int state) {
sprintf(fname, "%s%d.db", table, i);
if ( rval < percent_do_op ) {
// if ( verbose ) printf("%s : rval = %d\n", __FILE__, rval);
switch ( state ) {
case CREATED:
do_close(db, fname, &next_state);
db_array[i] = db = 0;
if ( r < (percent_do_op / 2) ) {
do_delete(db, fname, &next_state);
do_delete(fname, &next_state);
}
break;
case OPEN:
do_close(db, fname, &next_state);
db_array[i] = db = 0;
if ( rval < (percent_do_op / 2) ) {
do_delete(db, fname, &next_state);
do_delete(fname, &next_state);
}
break;
case CLOSED:
if ( rval < (percent_do_op / 2) ) {
do_open(db, fname, &next_state);
db = do_open(fname, &next_state);
db_array[i] = db;
}
else {
do_delete(db, fname, &next_state);
do_delete(fname, &next_state);
}
break;
case DELETED:
do_create(db, fname, &next_state);
db = do_create(fname, &next_state);
db_array[i] = db;
break;
}
}
return next_state;
}
char *state_db_name="states.db";
static void do_random_fileops(void)
{
int r, i, state, next_state;
DB_TXN *txn;
for (i=0;i<NUM_DICTIONARIES;i++) {
r = env->txn_begin(env, NULL, &txn, 0);
state = get_state(i);
next_state = do_random_fileop(i, state);
put_state(i, next_state);
r = txn->commit(txn, 0);
update_crash_timer();
}
}
static void run_test(int iter, int crash){
u_int32_t recovery_flags = DB_INIT_LOG | DB_INIT_TXN;
......@@ -185,14 +216,15 @@ static void run_test(int iter, int crash){
r = db_create(&states, env, 0); CKERR(r);
r = states->open(states, NULL, state_db_name, NULL, DB_UNKNOWN, 0, 0666); CKERR(r);
if ( verbose ) printf("%s : === ITERATION %6d ===\n", __FILE__, iter);
// verify previous results
if ( verbose ) printf("%s : verify previous results\n", __FILE__);
int state = DELETED, next_state;
int state = DELETED;
DB* db;
char fname[100];
if ( iter > 0 ) {
for (i=0;i<NUM_DICTIONARIES;i++) {
db = &db_array[i];
sprintf(fname, "%s%d.db", table, i);
state = get_state(i);
switch (state) {
......@@ -201,6 +233,7 @@ static void run_test(int iter, int crash){
// open the table
r = db_create(&db, env, 0); CKERR(r);
r = db->open(db, NULL, fname, NULL, DB_UNKNOWN, 0, 0666); CKERR(r);
db_array[i] = db;
verify_sequential_rows(db, 0, ROWS_PER_TABLE);
// leave table open
if (verbose) printf("%s : verified open/created db[%d]\n", __FILE__, i);
......@@ -212,10 +245,14 @@ static void run_test(int iter, int crash){
verify_sequential_rows(db, 0, ROWS_PER_TABLE);
// close table
r = db->close(db, 0); CKERR(r);
db_array[i] = db = NULL;
if (verbose) printf("%s : verified closed db[%d]\n", __FILE__, i);
break;
case DELETED:
verify_dbremove(db);
r = db_create(&db, env, 0); CKERR(r);
r = db->open(db, NULL, fname, NULL, DB_UNKNOWN, 0, 0666);
if ( r == 0 ) assert(1);
db_array[i] = db = NULL;
if (verbose) printf("%s : verified db[%d] removed\n", __FILE__, i);
break;
default:
......@@ -227,56 +264,71 @@ static void run_test(int iter, int crash){
if ( verbose ) printf("%s : previous results verified\n", __FILE__);
// for each of the dictionaries, perform a fileop some percentage of time (set in do_random_fileop).
DB_TXN* txn;
// before checkpoint
if ( verbose ) printf("%s : before checkpoint\n", __FILE__);
for (i=0;i<NUM_DICTIONARIES;i++) {
db = &db_array[i];
r = env->txn_begin(env, NULL, &txn, 0);
state = get_state(i);
next_state = do_random_fileop(db, i, state);
put_state(i, next_state);
// TODO : change to mix of commit and abort
r = txn->commit(txn, 0);
// before checkpoint #1
if ( verbose ) printf("%s : before checkpoint #1\n", __FILE__);
crash_timer = NUM_DICTIONARIES + 1; // won't go off
do_random_fileops();
// during checkpoint #1
if ( verbose ) printf("%s : during checkpoint #1\n", __FILE__);
crash_timer = NUM_DICTIONARIES + 1; // won't go off
if ( iter & 1 )
db_env_set_checkpoint_callback((void (*)(void*))do_random_fileops, NULL);
else
db_env_set_checkpoint_callback2((void (*)(void*))do_random_fileops, NULL);
// checkpoint
r = env->txn_checkpoint(env, 0, 0, 0); CKERR(r);
db_env_set_checkpoint_callback(NULL, NULL);
db_env_set_checkpoint_callback2(NULL, NULL);
// randomly fail sometime during the next 3 phases
// 1) before the next checkpoint
// 2) during the next checkpoint
// 3) after the next (final) checkpoint
if ( iter > 10 ) {
set_crash_timer();
}
else {
crash_timer = ( 3 * NUM_DICTIONARIES ) + 1; // won't go off
}
// before checkpoint #2
if ( verbose ) printf("%s : before checkpoint #2\n", __FILE__);
do_random_fileops();
// during checkpoint
if ( verbose ) printf("%s : during checkpoint\n", __FILE__);
for (i=0;i<NUM_DICTIONARIES;i++) {
db = &db_array[i];
r = env->txn_begin(env, NULL, &txn, 0);
state = get_state(i);
next_state = do_random_fileop(db, i, state);
put_state(i, next_state);
// TODO : change to mix of commit and abort
r = txn->commit(txn, 0);
}
if ( verbose ) printf("%s : during checkpoint #2\n", __FILE__);
if ( iter & 1 )
db_env_set_checkpoint_callback((void (*)(void*))do_random_fileops, NULL);
else
db_env_set_checkpoint_callback2((void (*)(void*))do_random_fileops, NULL);
// checkpoint
r = env->txn_checkpoint(env, 0, 0, 0); CKERR(r);
db_env_set_checkpoint_callback(NULL, NULL);
db_env_set_checkpoint_callback2(NULL, NULL);
// after checkpoint
if ( verbose ) printf("%s : after checkpoint\n", __FILE__);
for (i=0;i<NUM_DICTIONARIES;i++) {
db = &db_array[i];
r = env->txn_begin(env, NULL, &txn, 0);
state = get_state(i);
next_state = do_random_fileop(db, i, state);
put_state(i, next_state);
// TODO : change to mix of commit and abort
r = txn->commit(txn, 0);
}
if ( verbose ) printf("%s : after checkpoint #2\n", __FILE__);
do_random_fileops();
// close the states table before we crash
r = states->close(states, 0); CKERR(r);
crash = crash;
if (iter > 100 )
if (iter > 10 ) {
if ( verbose ) printf("%s : crash\n", __FILE__);
crash_it();
}
if ( verbose ) printf("%s : done\n", __FILE__);
r = env->txn_checkpoint(env, 0, 0, 0); CKERR(r);
r = env->close(env, 0);
assert((r == 0) || (r == EINVAL)); // OK to have open transactions prior to close
}
// ------------ infrastructure ----------
......@@ -352,15 +404,6 @@ static void insert_n(DB *db, DB_TXN *txn, int firstkey, int n) {
}
}
static void verify_dbremove(DB* db) {
// DBC *cursor;
// DB_TXN *txn;
// int r;
// r = db->cursor(db, txn, &cursor, 0);
// assert(r == EINVAL);
db = db;
}
static int verify_identical_dbts(const DBT *dbt1, const DBT *dbt2) {
int r = 0;
if (dbt1->size != dbt2->size) r = 1;
......
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