recover-x2.c 7.33 KB
Newer Older
1 2
/* Transaction consistency:  
 *  fork a process:
3 4 5 6 7
 *   Open two tables, A and B
 *   begin transaction U
 *   begin transaction V
 *   store U.A into A using U
 *   store V.B into B using V
8
 *   checkpoint
9 10 11 12 13
 *   store U.C into A using U
 *   store V.D into B using V
 *   commit U
 *   maybe commit V
 *   abort the process abruptly
14 15
 *  wait for the process to finish
 *   open the environment doing recovery
16
 *   check to see if both rows are present in A and maybe present in B
17 18 19 20 21
 */
#include <sys/stat.h>
#include <sys/wait.h>
#include "test.h"

22
const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN;
23 24 25 26 27 28 29 30 31 32 33 34
char *namea="a.db";
char *nameb="b.db";

static void
put (DB_TXN *txn, DB *db, char *key, char *data) {
    DBT k = {.data = key,  .size=1+strlen(key) };
    DBT d = {.data = data, .size=1+strlen(data)};
    int r = db->put(db, txn, &k, &d, 0);
    CKERR(r);
}
   
static void
35
do_x2_shutdown (BOOL do_commit) {
36 37 38 39 40 41 42 43 44 45 46 47 48
    int r;
    system("rm -rf " ENVDIR);
    toku_os_mkdir(ENVDIR, S_IRWXU+S_IRWXG+S_IRWXO);
    DB_ENV *env;
    DB *dba, *dbb; // Use two DBs so that BDB doesn't get a lock conflict
    r = db_env_create(&env, 0);                                                         CKERR(r);
    r = env->open(env, ENVDIR, envflags, S_IRWXU+S_IRWXG+S_IRWXO);                      CKERR(r);
    r = db_create(&dba, env, 0);                                                        CKERR(r);
    r = dba->open(dba, NULL, namea, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
    r = db_create(&dbb, env, 0);                                                        CKERR(r);
    r = dba->open(dbb, NULL, nameb, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
    DB_TXN *txnU, *txnV;
    r = env->txn_begin(env, NULL, &txnU, 0);                                            CKERR(r);
Dave Wells's avatar
Dave Wells committed
49
    r = env->txn_begin(env, NULL, &txnV, 0);                                            CKERR(r);
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    put(txnU, dba, "u.a", "u.a.data");
    put(txnV, dbb, "v.b", "v.b.data");
    r = env->txn_checkpoint(env, 0, 0, 0);                                              CKERR(r);
    put(txnU, dba, "u.c", "u.c.data");
    put(txnV, dbb, "v.d", "v.d.data");
    r = txnU->commit(txnU, 0);                                                          CKERR(r);
    if (do_commit) {
	r = txnV->commit(txnV, 0);                                                      CKERR(r);
    }
    abort();
}

static void
checkcurs (DBC *curs, int cursflags, char *key, char *val, BOOL expect_it) {
    DBT k={.size=0}, v={.size=0};
    int r = curs->c_get(curs, &k, &v, cursflags);
    if (expect_it) {
	assert(r==0);
	printf("Got %s expected %s\n", (char*)k.data, key);
	assert(strcmp(k.data, key)==0);
	assert(strcmp(v.data, val)==0);
    } else {
	printf("Expected nothing, got r=%d\n", r);
	assert(r!=0);
    }
}

static void
78
do_x2_recover (BOOL did_commit) {
79 80 81
    DB_ENV *env;
    int r;
    r = db_env_create(&env, 0);                                                             CKERR(r);
82
    r = env->open(env, ENVDIR, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);                          CKERR(r);
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
    DB_TXN *txn;
    r = env->txn_begin(env, NULL, &txn, 0);                                                 CKERR(r);
    {
	DB *dba;
	r = db_create(&dba, env, 0);                                                        CKERR(r);
	r = dba->open(dba, NULL, namea, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
	DBC *c;
	r = dba->cursor(dba, txn, &c, 0);                                                   CKERR(r);
	checkcurs(c, DB_FIRST, "u.a", "u.a.data", TRUE);
	checkcurs(c, DB_NEXT,  "u.c", "u.c.data", TRUE);
	checkcurs(c, DB_NEXT,  NULL,  NULL,       FALSE);
	r = c->c_close(c);                                                                  CKERR(r);	
	r = dba->close(dba, 0);                                                             CKERR(r);
    }
    {
	DB *dbb;
	r = db_create(&dbb, env, 0);                                                        CKERR(r);
	r = dbb->open(dbb, NULL, nameb, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
	DBC *c;
	r = dbb->cursor(dbb, txn, &c, 0);                                                   CKERR(r);
	checkcurs(c, DB_FIRST, "v.b", "v.b.data", did_commit);
	checkcurs(c, DB_NEXT,  "v.d", "v.d.data", did_commit);
	checkcurs(c, DB_NEXT,  NULL,  NULL,       FALSE);
	r = c->c_close(c);                                                                  CKERR(r);	
	r = dbb->close(dbb, 0);                                                             CKERR(r);
    }
 
    r = txn->commit(txn, 0);                                                                CKERR(r);
    r = env->close(env, 0);                                                                 CKERR(r);
    exit(0);
}

const char *cmd;

static void
118
do_test_internal (BOOL commit) {
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
    pid_t pid;
    if (0 == (pid=fork())) {
	int r=execl(cmd, verbose ? "-v" : "-q", commit ? "--commit" : "--abort", NULL);
	assert(r==-1);
	printf("execl failed: %d (%s)\n", errno, strerror(errno));
	assert(0);
    }
    {
	int r;
	int status;
	r = waitpid(pid, &status, 0);
	//printf("signaled=%d sig=%d\n", WIFSIGNALED(status), WTERMSIG(status));
	assert(WIFSIGNALED(status) && WTERMSIG(status)==SIGABRT);
    }
    // Now find out what happend
    
    if (0 == (pid = fork())) {
Dave Wells's avatar
Dave Wells committed
136
	int r=execl(cmd, verbose ? "-v" : "-q", commit ? "--recover-committed" : "--recover-aborted", NULL);
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
	assert(r==-1);
	printf("execl failed: %d (%s)\n", errno, strerror(errno));
	assert(0);
    }
    {
	int r;
	int status;
	r = waitpid(pid, &status, 0);
	//printf("recovery exited=%d\n", WIFEXITED(status));
	assert(WIFEXITED(status) && WEXITSTATUS(status)==0);
    }
}

static void
do_test (void) {
    do_test_internal(TRUE);
    do_test_internal(FALSE);
}

Dave Wells's avatar
Dave Wells committed
156
BOOL do_commit=FALSE, do_abort=FALSE, do_recover_committed=FALSE,  do_recover_aborted=FALSE;
157 158

static void
159
x2_parse_args (int argc, char *argv[]) {
160 161 162 163 164 165 166 167 168 169 170 171 172
    int resultcode;
    cmd = argv[0];
    argc--; argv++;
    while (argc>0) {
	if (strcmp(argv[0], "-v") == 0) {
	    verbose++;
	} else if (strcmp(argv[0],"-q")==0) {
	    verbose--;
	    if (verbose<0) verbose=0;
	} else if (strcmp(argv[0],"--abort")==0) {
	    do_abort=1;
	} else if (strcmp(argv[0],"--commit")==0) {
	    do_commit=1;
Dave Wells's avatar
Dave Wells committed
173 174
	} else if (strcmp(argv[0],"--recover-committed")==0) {
	    do_recover_committed=1;
175 176 177 178 179
	} else if (strcmp(argv[0],"--recover-aborted")==0) {
	    do_recover_aborted=1;
	} else if (strcmp(argv[0], "-h")==0) {
	    resultcode=0;
	do_usage:
Dave Wells's avatar
Dave Wells committed
180
	    fprintf(stderr, "Usage:\n%s [-v|-q]* [-h] {--abort | --commit | --recover-committed | --recover-aborted } \n", cmd);
181 182 183 184 185 186 187 188 189 190 191 192 193
	    exit(resultcode);
	} else {
	    fprintf(stderr, "Unknown arg: %s\n", argv[0]);
	    resultcode=1;
	    goto do_usage;
	}
	argc--;
	argv++;
    }
    {
	int n_specified=0;
	if (do_commit)            n_specified++;
	if (do_abort)             n_specified++;
194
	if (do_recover_committed) n_specified++;
195 196
	if (do_recover_aborted)   n_specified++;
	if (n_specified>1) {
Dave Wells's avatar
Dave Wells committed
197
	    printf("Specify only one of --commit or --abort or --recover-committed or --recover-aborted\n");
198 199 200 201 202 203 204
	    resultcode=1;
	    goto do_usage;
	}
    }
}

int
205 206
test_main (int argc, char *argv[]) {
    x2_parse_args(argc, argv);
207 208 209 210
    if (do_commit) {
	do_x2_shutdown (TRUE);
    } else if (do_abort) {
	do_x2_shutdown (FALSE);
Dave Wells's avatar
Dave Wells committed
211
    } else if (do_recover_committed) {
212
	do_x2_recover(TRUE);
213
    } else if (do_recover_aborted) {
214
	do_x2_recover(FALSE);
215 216 217 218 219
    } else {
	do_test();
    }
    return 0;
}