diff --git a/newbrt/log-internal.h b/newbrt/log-internal.h index d974cc0190e..7b10c360354 100644 --- a/newbrt/log-internal.h +++ b/newbrt/log-internal.h @@ -141,6 +141,7 @@ static inline int toku_logsizeof_BYTESTRING (BYTESTRING bs) { return 4+bs.len; } +#if 0 static inline int toku_logsizeof_LOGGEDBRTHEADER (LOGGEDBRTHEADER bs) { int in_both = 4+4+4+8+8+4+8; in_both += 8; // for the number of block headers @@ -152,6 +153,7 @@ static inline int toku_logsizeof_LOGGEDBRTHEADER (LOGGEDBRTHEADER bs) { static inline int toku_logsizeof_INTPAIRARRAY (INTPAIRARRAY pa) { return 4+(4+4)*pa.size; } +#endif static inline char *fixup_fname(BYTESTRING *f) { assert(f->len>0); diff --git a/newbrt/logcursor.c b/newbrt/logcursor.c index 5bbcb4d3928..58a3c98900e 100644 --- a/newbrt/logcursor.c +++ b/newbrt/logcursor.c @@ -5,8 +5,10 @@ #include "includes.h" +enum lc_direction { LC_FORWARD, LC_BACKWARD, LC_FIRST, LC_LAST }; + struct toku_logcursor { - char *logdir; + char *logdir; // absolute directory name char **logfiles; int n_logfiles; int cur_logfiles_index; @@ -14,8 +16,27 @@ struct toku_logcursor { BOOL is_open; struct log_entry entry; BOOL entry_valid; + LSN cur_lsn; + enum lc_direction last_direction; }; +#define LC_LSN_ERROR (-1) + +static void lc_print_logcursor (TOKULOGCURSOR lc) __attribute__((unused)); +static void lc_print_logcursor (TOKULOGCURSOR lc) { + printf("lc = %p\n", lc); + printf(" logdir = %s\n", lc->logdir); + printf(" logfiles = %p\n", lc->logfiles); + for (int lf=0;lfn_logfiles;lf++) { + printf(" logfile[%d] = %p (%s)\n", lf, lc->logfiles[lf], lc->logfiles[lf]); + } + printf(" n_logfiles = %d\n", lc->n_logfiles); + printf(" cur_logfiles_index = %d\n", lc->cur_logfiles_index); + printf(" cur_fp = %p\n", lc->cur_fp); + printf(" cur_lsn = %lu\n", lc->cur_lsn.lsn); + printf(" last_direction = %d\n", lc->last_direction); +} + static int lc_close_cur_logfile(TOKULOGCURSOR lc) { int r=0; if ( lc->is_open ) { @@ -28,6 +49,7 @@ static int lc_close_cur_logfile(TOKULOGCURSOR lc) { static int lc_open_logfile(TOKULOGCURSOR lc, int index) { int r=0; assert( !lc->is_open ); + if( index == -1 || index >= lc->n_logfiles) return DB_NOTFOUND; lc->cur_fp = fopen(lc->logfiles[index], "r"); if ( lc->cur_fp == NULL ) return DB_NOTFOUND; @@ -36,13 +58,25 @@ static int lc_open_logfile(TOKULOGCURSOR lc, int index) { r = toku_read_logmagic(lc->cur_fp, &version); if (r!=0) return DB_BADFORMAT; - if (version != 1) + if (version != TOKU_LOG_VERSION) return DB_BADFORMAT; // mark as open lc->is_open = TRUE; return r; } +static int lc_check_lsn(TOKULOGCURSOR lc, int dir) { + int r=0; + LSN lsn = toku_log_entry_get_lsn(&(lc->entry)); + if (((dir == LC_FORWARD) && ( lsn.lsn != lc->cur_lsn.lsn + 1 )) || + ((dir == LC_BACKWARD) && ( lsn.lsn != lc->cur_lsn.lsn - 1 ))) { + fprintf(stderr, "Bad LSN : direction = %d, lsn.lsn = %"PRIu64", cur_lsn.lsn=%"PRIu64"\n", dir, lsn.lsn, lc->cur_lsn.lsn); + return LC_LSN_ERROR; + } + lc->cur_lsn.lsn = lsn.lsn; + return r; +} + // toku_logcursor_create() // - returns a pointer to a logcursor int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir) { @@ -51,16 +85,38 @@ int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir) { // malloc a cursor TOKULOGCURSOR cursor = (TOKULOGCURSOR) toku_malloc(sizeof(struct toku_logcursor)); - if ( NULL==cursor ) - return ENOMEM; + if ( cursor == NULL ) { + failresult = ENOMEM; + goto fail; + } // find logfiles in logdir cursor->is_open = FALSE; cursor->cur_logfiles_index = 0; cursor->entry_valid = FALSE; - cursor->logdir = (char *) toku_malloc(strlen(log_dir)+1); - if ( NULL==cursor->logdir ) - return ENOMEM; - strcpy(cursor->logdir, log_dir); + // cursor->logdir must be an absolute path + if ( log_dir[0]=='/' ) { + cursor->logdir = (char *) toku_malloc(strlen(log_dir)+1); + if ( cursor->logdir == NULL ) { + failresult = ENOMEM; + goto fail; + } + sprintf(cursor->logdir, "%s", log_dir); + } + else { + char *cwd = getcwd(NULL, 0); + if ( cwd == NULL ) { + failresult = -1; + goto fail; + } + cursor->logdir = (char *) toku_malloc(strlen(cwd)+strlen(log_dir)+2); + if ( cursor->logdir == NULL ) { + toku_free(cwd); + failresult = ENOMEM; + goto fail; + } + sprintf(cursor->logdir, "%s/%s", cwd, log_dir); + toku_free(cwd); + } cursor->logfiles = NULL; cursor->n_logfiles = 0; r = toku_logger_find_logfiles(cursor->logdir, &(cursor->logfiles), &(cursor->n_logfiles)); @@ -68,6 +124,8 @@ int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir) { failresult=r; goto fail; } + cursor->cur_lsn.lsn=0; + cursor->last_direction=LC_FIRST; *lc = cursor; return r; fail: @@ -76,6 +134,50 @@ int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir) { return failresult; } +int toku_logcursor_create_for_file(TOKULOGCURSOR *lc, const char *log_dir, const char *log_file) { + int r=0; + int failresult=0; + + TOKULOGCURSOR cursor; + r = toku_logcursor_create(&cursor, log_dir); + if (r!=0) + return r; + + int idx; + int found_it=0; + int fullnamelen = strlen(cursor->logdir) + strlen(log_file) + 3; + char *log_file_fullname = toku_malloc(fullnamelen); + if ( log_file_fullname == NULL ) { + failresult = ENOMEM; + goto fail; + } + sprintf(log_file_fullname, "%s/%s", cursor->logdir, log_file); + for(idx=0;idxn_logfiles;idx++) { + if ( strcmp(log_file_fullname, cursor->logfiles[idx]) == 0 ) { + found_it = 1; + break; + } + } + if (found_it==0) { + failresult = DB_NOTFOUND; + goto fail; + } + // replace old logfile structure with single file version + int lf; + for(lf=0;lfn_logfiles;lf++) { + toku_free(cursor->logfiles[lf]); + } + cursor->n_logfiles=1; + cursor->logfiles[0] = log_file_fullname; + *lc = cursor; + return r; +fail: + toku_free(log_file_fullname); + toku_logcursor_destroy(&cursor); + *lc = NULL; + return failresult; +} + int toku_logcursor_destroy(TOKULOGCURSOR *lc) { int r=0; if ( (*lc)->entry_valid ) { @@ -99,7 +201,13 @@ int toku_logcursor_next(TOKULOGCURSOR lc, struct log_entry **le) { if ( lc->entry_valid ) { toku_log_free_log_entry_resources(&(lc->entry)); lc->entry_valid = FALSE; - } else if ( !lc->entry_valid ) { + if (lc->last_direction == LC_BACKWARD) { + struct log_entry junk; + r = toku_log_fread(lc->cur_fp, &junk); + assert(r == 0); + toku_log_free_log_entry_resources(&junk); + } + } else { r = toku_logcursor_first(lc, le); return r; } @@ -126,6 +234,10 @@ int toku_logcursor_next(TOKULOGCURSOR lc, struct log_entry **le) { return r; } } + r = lc_check_lsn(lc, LC_FORWARD); + if (r!=0) + return r; + lc->last_direction = LC_FORWARD; lc->entry_valid = TRUE; *le = &(lc->entry); return r; @@ -136,7 +248,13 @@ int toku_logcursor_prev(TOKULOGCURSOR lc, struct log_entry **le) { if ( lc->entry_valid ) { toku_log_free_log_entry_resources(&(lc->entry)); lc->entry_valid = FALSE; - } else if ( !lc->entry_valid ) { + if (lc->last_direction == LC_FORWARD) { + struct log_entry junk; + r = toku_log_fread_backward(lc->cur_fp, &junk); + assert(r == 0); + toku_log_free_log_entry_resources(&junk); + } + } else { r = toku_logcursor_last(lc, le); return r; } @@ -163,6 +281,10 @@ int toku_logcursor_prev(TOKULOGCURSOR lc, struct log_entry **le) { return r; } } + r = lc_check_lsn(lc, LC_BACKWARD); + if (r!=0) + return r; + lc->last_direction = LC_BACKWARD; lc->entry_valid = TRUE; *le = &(lc->entry); return r; @@ -188,6 +310,10 @@ int toku_logcursor_first(TOKULOGCURSOR lc, struct log_entry **le) { r = toku_log_fread(lc->cur_fp, &(lc->entry)); if (r!=0) return r; + r = lc_check_lsn(lc, LC_FIRST); + if (r!=0) + return r; + lc->last_direction = LC_FIRST; lc->entry_valid = TRUE; *le = &(lc->entry); return r; @@ -217,6 +343,10 @@ int toku_logcursor_last(TOKULOGCURSOR lc, struct log_entry **le) { r = toku_log_fread_backward(lc->cur_fp, &(lc->entry)); if (r!=0) return r; + r = lc_check_lsn(lc, LC_LAST); + if (r!=0) + return r; + lc->last_direction = LC_LAST; lc->entry_valid = TRUE; *le = &(lc->entry); return r; diff --git a/newbrt/logcursor.h b/newbrt/logcursor.h index 4a53dca30a5..da4efb5342c 100644 --- a/newbrt/logcursor.h +++ b/newbrt/logcursor.h @@ -13,11 +13,14 @@ typedef struct toku_logcursor *TOKULOGCURSOR; // All routines return 0 on success // toku_logcursor_create() -// - returns a pointer to a logcursor +// - creates a logcursor (lc) // - following toku_logcursor_create() // if toku_logcursor_next() is called, it returns the first entry in the log // if toku_logcursor_prev() is called, it returns the last entry in the log int toku_logcursor_create(TOKULOGCURSOR *lc, const char *log_dir); +// toku_logcursor_create_for_file() +// - creates a logcusor (lc) that only knows about the file log_file +int toku_logcursor_create_for_file(TOKULOGCURSOR *lc, const char *log_dir, const char *log_file); // toku_logcursor_destroy() // - frees all resources associated with the logcursor, including the log_entry // associated with the latest cursor action diff --git a/newbrt/logger.c b/newbrt/logger.c index 73bad726e96..699788f91b9 100644 --- a/newbrt/logger.c +++ b/newbrt/logger.c @@ -48,7 +48,25 @@ int toku_logger_create (TOKULOGGER *resultp) { int toku_logger_open (const char *directory, TOKULOGGER logger) { if (logger->is_open) return EINVAL; if (logger->is_panicked) return EINVAL; + int r; + TOKULOGCURSOR logcursor; + struct log_entry *le; + logger->lsn.lsn=0; + // In searching existing logfiles for last LSN, have chosen to + // ignore errors that may occur. In the event of a return error, + // revert to using LSN=0 + r = toku_logcursor_create(&logcursor, directory); + if (r==0) { + r = toku_logcursor_last(logcursor, &le); + if (r==0) + logger->lsn = toku_log_entry_get_lsn(le); + toku_logcursor_destroy(&logcursor); + } + //printf("starting after LSN=%lu\n", logger->lsn.lsn); + logger->written_lsn = logger->lsn; + logger->fsynced_lsn = logger->lsn; + long long nexti; r = toku_logger_find_next_unused_log_file(directory, &nexti); if (r!=0) return r; @@ -57,10 +75,6 @@ int toku_logger_open (const char *directory, TOKULOGGER logger) { logger->next_log_file_number = nexti; open_logfile(logger); - logger->lsn.lsn = 0; // WRONG!!! This should actually be calculated by looking at the log file. - logger->written_lsn.lsn = 0; - logger->fsynced_lsn.lsn = 0; - logger->is_open = 1; if (!logger->write_log_files) toku_set_func_fsync(toku_logger_fsync_null); diff --git a/newbrt/recover.c b/newbrt/recover.c index 6a577f85181..17d9b205510 100644 --- a/newbrt/recover.c +++ b/newbrt/recover.c @@ -58,6 +58,7 @@ struct backward_scan_state { int n_live_txns; LSN min_live_txn; }; + static struct backward_scan_state initial_bss = {BS_INIT,{0},0,{0}}; static void @@ -176,12 +177,10 @@ internal_toku_recover_fopen_or_fcreate (int flags, int mode, char *fixedfname, F static void toku_recover_fopen (LSN UU(lsn), TXNID UU(txnid), BYTESTRING fname, FILENUM filenum) { char *fixedfname = fixup_fname(&fname); - toku_free_BYTESTRING(fname); internal_toku_recover_fopen_or_fcreate(0, 0, fixedfname, filenum); } -static int toku_recover_backward_fopen (struct logtype_fopen *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->fname); +static int toku_recover_backward_fopen (struct logtype_fopen *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -190,44 +189,14 @@ static int toku_recover_backward_fopen (struct logtype_fopen *l, struct backward static void toku_recover_fcreate (LSN UU(lsn), TXNID UU(txnid), FILENUM filenum, BYTESTRING fname,u_int32_t mode) { char *fixedfname = fixup_fname(&fname); - toku_free_BYTESTRING(fname); create_dir_from_file(fixedfname); internal_toku_recover_fopen_or_fcreate(O_CREAT|O_TRUNC, mode, fixedfname, filenum); } -static int toku_recover_backward_fcreate (struct logtype_fcreate *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->fname); +static int toku_recover_backward_fcreate (struct logtype_fcreate *UU(l), struct backward_scan_state *UU(bs)) { return 0; } -#if 0 -static void -toku_recover_enqrootentry (LSN lsn __attribute__((__unused__)), FILENUM filenum, TXNID xid, u_int32_t typ, BYTESTRING key, BYTESTRING val) { - struct cf_pair *pair = NULL; - int r = find_cachefile(filenum, &pair); - if (r!=0) { - // if we didn't find a cachefile, then we don't have to do anything. - return; - } - struct brt_cmd cmd; - DBT keydbt, valdbt; - cmd.type=(enum brt_cmd_type) typ; - cmd.xid =xid; - cmd.u.id.key = toku_fill_dbt(&keydbt, key.data, key.len); - cmd.u.id.val = toku_fill_dbt(&valdbt, val.data, val.len); - r = toku_brt_root_put_cmd(pair->brt, &cmd, null_tokulogger); - assert(r==0); - toku_free(key.data); - toku_free(val.data); -} - -static int toku_recover_backward_enqrootentry (struct logtype_enqrootentry *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->key); - toku_free_BYTESTRING(l->data); - return 0; -} -#endif - static void toku_recover_enq_insert (LSN lsn __attribute__((__unused__)), FILENUM filenum, TXNID xid, BYTESTRING key, BYTESTRING val) { struct cf_pair *pair = NULL; @@ -250,13 +219,9 @@ toku_recover_enq_insert (LSN lsn __attribute__((__unused__)), FILENUM filenum, T assert(r==0); xids_destroy(&cmd.xids); xids_destroy(&root); - toku_free(key.data); - toku_free(val.data); } -static int toku_recover_backward_enq_insert (struct logtype_enq_insert *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->key); - toku_free_BYTESTRING(l->value); +static int toku_recover_backward_enq_insert (struct logtype_enq_insert *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -282,13 +247,9 @@ toku_recover_enq_delete_both (LSN lsn __attribute__((__unused__)), FILENUM filen assert(r==0); xids_destroy(&cmd.xids); xids_destroy(&root); - toku_free(key.data); - toku_free(val.data); } -static int toku_recover_backward_enq_delete_both (struct logtype_enq_delete_both *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->key); - toku_free_BYTESTRING(l->value); +static int toku_recover_backward_enq_delete_both (struct logtype_enq_delete_both *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -314,13 +275,9 @@ toku_recover_enq_delete_any (LSN lsn __attribute__((__unused__)), FILENUM filenu assert(r==0); xids_destroy(&cmd.xids); xids_destroy(&root); - toku_free(key.data); - toku_free(val.data); } -static int toku_recover_backward_enq_delete_any (struct logtype_enq_delete_any *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->key); - toku_free_BYTESTRING(l->value); +static int toku_recover_backward_enq_delete_any (struct logtype_enq_delete_any *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -332,11 +289,9 @@ toku_recover_fclose (LSN UU(lsn), BYTESTRING UU(fname), FILENUM filenum) { r = toku_close_brt(pair->brt, 0, 0); assert(r==0); pair->brt=0; - toku_free_BYTESTRING(fname); } -static int toku_recover_backward_fclose (struct logtype_fclose *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->fname); +static int toku_recover_backward_fclose (struct logtype_fclose *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -363,7 +318,6 @@ static int toku_recover_backward_begin_checkpoint (struct logtype_begin_checkpoi abort(); } - static int toku_recover_end_checkpoint (LSN UU(lsn), TXNID UU(txnid)) { return 0; } @@ -391,8 +345,7 @@ static int toku_recover_fassociate (LSN UU(lsn), FILENUM UU(filenum), BYTESTRING static int toku_recover_backward_fassociate (struct logtype_fassociate *l, struct backward_scan_state *UU(bs)) { char *fixedfname = fixup_fname(&l->fname); - toku_free_BYTESTRING(l->fname); - internal_toku_recover_fopen_or_fcreate(0, 0, fixedfname, l->filenum); + internal_toku_recover_fopen_or_fcreate(0, 0, fixedfname, l->filenum); return 0; } @@ -445,13 +398,11 @@ static int toku_recover_backward_xbegin (struct logtype_xbegin *l, struct backwa abort(); } -static int toku_recover_timestamp (LSN UU(lsn), u_int64_t UU(timestamp), BYTESTRING comment) { - toku_free_BYTESTRING(comment); +static int toku_recover_timestamp (LSN UU(lsn), u_int64_t UU(timestamp), BYTESTRING UU(comment)) { return 0; } -static int toku_recover_backward_timestamp (struct logtype_timestamp *l, struct backward_scan_state *UU(bs)) { - toku_free_BYTESTRING(l->comment); +static int toku_recover_backward_timestamp (struct logtype_timestamp *UU(l), struct backward_scan_state *UU(bs)) { return 0; } @@ -495,9 +446,6 @@ static int toku_delete_rolltmp_files (const char *log_dir) { int tokudb_recover(const char *data_dir, const char *log_dir) { int failresult = 0; int r; - int entrycount=0; - char **logfiles; - int lockfd; { @@ -514,117 +462,61 @@ int tokudb_recover(const char *data_dir, const char *log_dir) { } } - r = toku_delete_rolltmp_files(log_dir); - if (r!=0) { failresult=r; goto fail; } - - int n_logfiles; - r = toku_logger_find_logfiles(log_dir, &logfiles, &n_logfiles); - if (r!=0) { failresult=r; goto fail; } - int i; - toku_recover_init(); char org_wd[1000]; { char *wd=getcwd(org_wd, sizeof(org_wd)); assert(wd!=0); //printf("%s:%d org_wd=\"%s\"\n", __FILE__, __LINE__, org_wd); } - char data_wd[1000]; - { - r=chdir(data_dir); assert(r==0); - char *wd=getcwd(data_wd, sizeof(data_wd)); - assert(wd!=0); - //printf("%s:%d data_wd=\"%s\"\n", __FILE__, __LINE__, data_wd); + + r = toku_delete_rolltmp_files(log_dir); + if (r!=0) { failresult=r; goto fail; } + + TOKULOGCURSOR logcursor; + r = toku_logcursor_create(&logcursor, log_dir); + assert(r == 0); + + toku_recover_init(); + + r = chdir(data_dir); + assert(r == 0); + + struct log_entry *le; + + struct backward_scan_state bs = initial_bss; + while (1) { + r = toku_logcursor_prev(logcursor, &le); + if (0) printf("%s:%d r=%d cmd=%c\n", __FUNCTION__, __LINE__, r, r==0 ? le->cmd:'?'); + if (r != 0) + break; + logtype_dispatch_assign(le, toku_recover_backward_, r, &bs); + if (r != 0) + break; } - LSN lastlsn = ZERO_LSN; - FILE *f = NULL; - for (i=0; icmd:'?'); + if (r != 0) + break; + logtype_dispatch_args(le, toku_recover_); } - i--; - // We got to the end of the last log - if (f) { r=fclose(f); assert(r==0); } - // Now we go forward from this point - while (n_logfiles-i-1cmd == LT_timestamp); assert(le->u.timestamp.comment.len == 5 && memcmp(le->u.timestamp.comment.data, "hello", 5) == 0); @@ -62,7 +64,9 @@ test_main (int argc __attribute__((__unused__)), r = toku_logcursor_next(lc, &le); assert(r == 0 && le->cmd == LT_timestamp); assert(le->u.timestamp.comment.len == 5 && memcmp(le->u.timestamp.comment.data, "world", 5) == 0); - printf("%"PRId64"\n", le->u.timestamp.timestamp - t); + if (verbose) + printf("%"PRId64"\n", le->u.timestamp.timestamp - t); + assert(le->u.timestamp.timestamp - t >= 10*1000000); r = toku_logcursor_next(lc, &le); assert(r != 0); @@ -70,5 +74,27 @@ test_main (int argc __attribute__((__unused__)), r = toku_logcursor_destroy(&lc); assert(r == 0 && lc == NULL); + // verify the log backwards + r = toku_logcursor_create(&lc, dname); + assert(r == 0 && lc != NULL); + + r = toku_logcursor_prev(lc, &le); + assert(r == 0 && le->cmd == LT_timestamp); + assert(le->u.timestamp.comment.len == 5 && memcmp(le->u.timestamp.comment.data, "world", 5) == 0); + t = le->u.timestamp.timestamp; + + r = toku_logcursor_prev(lc, &le); + assert(r == 0 && le->cmd == LT_timestamp); + assert(le->u.timestamp.comment.len == 5 && memcmp(le->u.timestamp.comment.data, "hello", 5) == 0); + if (verbose) + printf("%"PRId64"\n", t - le->u.timestamp.timestamp); + assert(t - le->u.timestamp.timestamp >= 10*1000000); + + r = toku_logcursor_prev(lc, &le); + assert(r != 0); + + r = toku_logcursor_destroy(&lc); + assert(r == 0 && lc == NULL); + return 0; } diff --git a/newbrt/tests/test_logcursor.c b/newbrt/tests/test_logcursor.c index 9b8ae9d8eab..744d45ff659 100644 --- a/newbrt/tests/test_logcursor.c +++ b/newbrt/tests/test_logcursor.c @@ -6,50 +6,116 @@ #include "includes.h" int test_0 (); +int test_1 (); +static void usage() { + printf("test_logcursors [OPTIONS]\n"); + printf("[-v]\n"); + printf("[-q]\n"); +} + +int test_main(int argc, const char *argv[]) { + int i; + for (i=1; icmd); - r = toku_logcursor_next(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_next(cursor, &entry); printf("Entry = %c\n", entry->cmd); - printf("r=%d\n", r); - r = toku_logcursor_destroy(&cursor); + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); - r = toku_logcursor_create(&cursor, dbdir); - if ( r!=0 ) return r; - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - printf("r=%d\n", r); - r = toku_logcursor_destroy(&cursor); + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_first(cursor, &entry); if (verbose) printf("First Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); - r = toku_logcursor_create(&cursor, dbdir); - if ( r!=0 ) return r; - r = toku_logcursor_next(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_next(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_next(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - r = toku_logcursor_prev(cursor, &entry); printf("Entry = %c\n", entry->cmd); - if ( r == DB_NOTFOUND ) printf("PASS\n"); else printf("FAIL\n"); + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); - r = toku_logcursor_destroy(&cursor); + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_last(cursor, &entry); if (verbose) printf("Last Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); + + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); assert(r==DB_NOTFOUND); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); + + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); assert(r==DB_NOTFOUND); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); + + r = toku_logcursor_create(&cursor, dbdir); if (verbose) printf("create returns %d\n", r); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_next(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); assert(r==0); + r = toku_logcursor_prev(cursor, &entry); if (verbose) printf("Entry = %c\n", entry->cmd); + if ( verbose) { + if ( r == DB_NOTFOUND ) printf("PASS\n"); + else printf("FAIL\n"); + } + assert(r==DB_NOTFOUND); + r = toku_logcursor_destroy(&cursor); if (verbose) printf("destroy returns %d\n", r); assert(r==0); return 0; } +// test per-file version +int test_1 () { + int r=0; + char dbdir[100] = "./dir.test_logcursor"; + char logfile[100] = "log000000000000.tokulog"; + struct toku_logcursor *cursor; + struct log_entry *entry; + + r = toku_logcursor_create_for_file(&cursor, dbdir, logfile); + if (verbose) printf("create returns %d\n", r); + assert(r==0); + + r = toku_logcursor_last(cursor, &entry); + if (verbose) printf("entry = %c\n", entry->cmd); + assert(r==0); + assert(entry->cmd =='C'); + + r = toku_logcursor_destroy(&cursor); + if (verbose) printf("destroy returns %d\n", r); + assert(r==0); + + return 0; +}