Commit 10b1d60d authored by Dave Wells's avatar Dave Wells Committed by Yoni Fogel

fix [t:2426], add test

git-svn-id: file:///svn/toku/tokudb@18290 c7de825b-a66e-492c-adef-691d508d4ae1
parent f1612526
......@@ -169,6 +169,8 @@ static int lc_create(TOKULOGCURSOR *lc, const char *log_dir) {
return failresult;
}
static int lc_scan_from_beginning_of_file_to_find_last(TOKULOGCURSOR lc);
int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir) {
TOKULOGCURSOR cursor;
int r = lc_create(&cursor, log_dir);
......@@ -394,12 +396,22 @@ int toku_logcursor_last(TOKULOGCURSOR lc, struct log_entry **le) {
}
while (1) {
// seek to end
r = fseek(lc->cur_fp, 0, SEEK_END);
assert(0==r);
r = fseek(lc->cur_fp, 0, SEEK_END); assert(r==0);
// read backward
r = toku_log_fread_backward(lc->cur_fp, &(lc->entry));
if (r==0)
if (r==0) // got a good entry
break;
if (r>0) {
// got an error,
// probably a corrupted last log entry due to a crash
// try scanning forward from the beginning to find the last good entry
r = lc_scan_from_beginning_of_file_to_find_last(lc);
assert(r==0);
// try reading again
r = toku_log_fread_backward(lc->cur_fp, &(lc->entry));
if (r==0) // got a good entry
break;
}
// move to previous file
r = lc_close_cur_logfile(lc);
if (r!=0)
......@@ -432,3 +444,29 @@ toku_logcursor_log_exists(const TOKULOGCURSOR lc) {
return r;
}
// return a logcursor with the cur_fp pointing to the end of the last good entry
static int lc_scan_from_beginning_of_file_to_find_last(TOKULOGCURSOR lc) {
struct log_entry le;
unsigned int version=0;
int r = 0;
r = fseek(lc->cur_fp, 0, SEEK_SET); assert(r==0);
r = toku_read_logmagic(lc->cur_fp, &version); assert(r==0);
fpos_t last_good_pos;
r = fgetpos(lc->cur_fp, &last_good_pos); assert(r==0);
while (1) {
if ( lc->entry_valid ) {
toku_log_free_log_entry_resources(&le);
lc->entry_valid = FALSE;
}
r = toku_log_fread(lc->cur_fp, &le);
if ( r!=0 ) break;
r = fgetpos(lc->cur_fp, &last_good_pos); assert(r==0);
}
// now have position of last good entry - set cur_fp and return
r = fsetpos(lc->cur_fp, &last_good_pos); assert(r==0);
return 0;
}
......@@ -424,22 +424,23 @@ generate_log_reader (void) {
fprintf(cf, " };\n");
fprintf(cf, " return DB_BADFORMAT;\n"); // Should read past the record using the len field.
fprintf(cf, "}\n\n");
fprintf2(cf, hf, "// Return 0 if there is something to read, return -1 if nothing to read, abort if an error.\n");
//fprintf2(cf, hf, "// Return 0 if there is something to read, return -1 if nothing to read, abort if an error.\n");
fprintf2(cf, hf, "// Return 0 if there is something to read, -1 if nothing to read, >0 on error\n");
fprintf2(cf, hf, "int toku_log_fread_backward (FILE *infile, struct log_entry *le)");
fprintf(hf, ";\n");
fprintf(cf, "{\n");
fprintf(cf, " {\n long pos = ftell(infile);\n if (pos<=12) return -1;\n }\n");
fprintf(cf, " int r = fseek(infile, -4, SEEK_CUR); assert(r==0);\n");
//fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " int r = fseek(infile, -4, SEEK_CUR); \n");// assert(r==0);\n");
fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " u_int32_t len;\n");
fprintf(cf, " r = toku_fread_u_int32_t_nocrclen(infile, &len); assert(r==0);\n");
//fprintf(cf, " if (r!=0) return r;\n");
fprintf(cf, " r = fseek(infile, -(int)len, SEEK_CUR) ; assert(r==0);\n");
//fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " r = toku_log_fread(infile, le); assert(r==0);\n");
//fprintf(cf, " if (r!=0) return r;\n");
fprintf(cf, " r = fseek(infile, -(int)len, SEEK_CUR); assert(r==0);\n");
//fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " r = toku_fread_u_int32_t_nocrclen(infile, &len); \n");// assert(r==0);\n");
fprintf(cf, " if (r!=0) return 1;\n");
fprintf(cf, " r = fseek(infile, -(int)len, SEEK_CUR) ; \n");// assert(r==0);\n");
fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " r = toku_log_fread(infile, le); \n");// assert(r==0);\n");
fprintf(cf, " if (r!=0) return 1;\n");
fprintf(cf, " r = fseek(infile, -(int)len, SEEK_CUR); \n");// assert(r==0);\n");
fprintf(cf, " if (r!=0) return errno;\n");
fprintf(cf, " return 0;\n");
fprintf(cf, "}\n\n");
......
// test recovery of "hello" comments
#include "test.h"
#include "includes.h"
#define TESTDIR "dir." __FILE__
static const int magic_begin_end_checkpoint_sz = 77; // leave this many bytes in file
static int
run_test(void) {
int r;
int trim = 1;
struct stat st;
while ( 1 ) {
// setup the test dir
system("rm -rf " TESTDIR);
r = toku_os_mkdir(TESTDIR, S_IRWXU); assert(r == 0);
// create the log
TOKULOGGER logger;
BYTESTRING hello = { strlen("hello"), "hello" };
BYTESTRING world = { strlen("world"), "world" };
BYTESTRING there = { strlen("there"), "there" };
r = toku_logger_create(&logger); assert(r == 0);
r = toku_logger_open(TESTDIR, logger); assert(r == 0);
LSN beginlsn;
// all logs must contain a valid checkpoint
r = toku_log_begin_checkpoint(logger, &beginlsn, TRUE, 0); assert(r == 0);
r = toku_log_end_checkpoint(logger, NULL, TRUE, beginlsn.lsn, 0); assert(r == 0);
r = toku_log_comment(logger, NULL, TRUE, 0, hello); assert(r == 0);
r = toku_log_comment(logger, NULL, TRUE, 0, world); assert(r == 0);
r = toku_log_begin_checkpoint(logger, &beginlsn, TRUE, 0); assert(r == 0);
r = toku_log_end_checkpoint(logger, NULL, TRUE, beginlsn.lsn, 0); assert(r == 0);
r = toku_log_comment(logger, NULL, TRUE, 0, hello); assert(r == 0);
r = toku_log_comment(logger, NULL, TRUE, 0, there); assert(r == 0);
r = toku_logger_close(&logger); assert(r == 0);
// redirect stderr
int devnul = open(DEV_NULL_FILE, O_WRONLY);
assert(devnul>=0);
r = toku_dup2(devnul, fileno(stderr)); assert(r==fileno(stderr));
r = close(devnul); assert(r==0);
char fname[256];
sprintf(fname, "%s/%s", TESTDIR, "log000000000000.tokulog");
r = toku_stat(fname, &st); assert(r==0);
if ( st.st_size - trim > magic_begin_end_checkpoint_sz )
truncate(fname, st.st_size - trim);
else
break;
// run recovery
r = tokudb_recover(TESTDIR, TESTDIR, 0, 0, NULL, NULL, 0);
assert(r == 0);
trim += 1;
}
return 0;
}
int
test_main(int UU(argc), const char *UU(argv[])) {
int r;
r = run_test();
return r;
}
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