diff options
-rw-r--r-- | dist/api_data.py | 4 | ||||
-rw-r--r-- | dist/api_err.py | 4 | ||||
-rw-r--r-- | dist/s_string.ok | 2 | ||||
-rw-r--r-- | examples/c/ex_backup.c | 6 | ||||
-rw-r--r-- | src/config/config_def.c | 13 | ||||
-rw-r--r-- | src/conn/api_strerror.c | 2 | ||||
-rw-r--r-- | src/conn/conn_log.c | 3 | ||||
-rw-r--r-- | src/docs/error-handling.dox | 3 | ||||
-rw-r--r-- | src/include/connection.h | 1 | ||||
-rw-r--r-- | src/include/extern.h | 1 | ||||
-rw-r--r-- | src/include/wiredtiger.in | 9 | ||||
-rw-r--r-- | src/log/log.c | 39 | ||||
-rw-r--r-- | src/txn/txn_recover.c | 18 | ||||
-rw-r--r-- | src/utilities/util_main.c | 51 |
14 files changed, 114 insertions, 42 deletions
diff --git a/dist/api_data.py b/dist/api_data.py index 82335e3f831..d6e861ceda3 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -550,6 +550,10 @@ common_wiredtiger_open = [ Config('prealloc', 'true', r''' pre-allocate log files.''', type='boolean'), + Config('recover', 'on', r''' + run recovery or error if recovery needs to run after an + unclean shutdown.''', + choices=['error','on']), ]), Config('mmap', 'true', r''' Use memory mapping to access files when possible''', diff --git a/dist/api_err.py b/dist/api_err.py index 6c893c9af82..a1f5593abd4 100644 --- a/dist/api_err.py +++ b/dist/api_err.py @@ -47,6 +47,10 @@ errors = [ interface, no further WiredTiger calls are required.'''), Error('WT_RESTART', -31805, 'restart the operation (internal)', undoc=True), + Error('WT_RUN_RECOVERY', -31806, + 'recovery must be run to continue', ''' + This error is generated when wiredtiger_open is configured + to return an error if recovery is required to use the database.'''), ] # Update the #defines in the wiredtiger.in file. diff --git a/dist/s_string.ok b/dist/s_string.ok index 82ce7680df4..66439faf161 100644 --- a/dist/s_string.ok +++ b/dist/s_string.ok @@ -283,6 +283,7 @@ RNG ROCKSDB RPC RUNDIR +RVv Radu Recno Recurse @@ -911,7 +912,6 @@ qsort quartile qup rS -rVv rbrace rbracket rdlock diff --git a/examples/c/ex_backup.c b/examples/c/ex_backup.c index b9b53002f34..f58f28dbd93 100644 --- a/examples/c/ex_backup.c +++ b/examples/c/ex_backup.c @@ -72,18 +72,18 @@ compare_backups(int i) */ if (i == 0) (void)snprintf(buf, sizeof(buf), - "../../wt -r -h %s dump logtest > %s.%d", + "../../wt -R -h %s dump logtest > %s.%d", home, full_out, i); else (void)snprintf(buf, sizeof(buf), - "../../wt -r -h %s.%d dump logtest > %s.%d", + "../../wt -R -h %s.%d dump logtest > %s.%d", home_full, i, full_out, i); ret = system(buf); /* * Now run dump on the incremental directory. */ (void)snprintf(buf, sizeof(buf), - "../../wt -r -h %s.%d dump logtest > %s.%d", + "../../wt -R -h %s.%d dump logtest > %s.%d", home_incr, i, incr_out, i); ret = system(buf); diff --git a/src/config/config_def.c b/src/config/config_def.c index 052fbf3d0b4..091c0c27aae 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -318,6 +318,7 @@ static const WT_CONFIG_CHECK confchk_log_subconfigs[] = { { "file_max", "int", "min=100KB,max=2GB", NULL }, { "path", "string", NULL, NULL }, { "prealloc", "boolean", NULL, NULL }, + { "recover", "string", "choices=[\"error\",\"on\"]", NULL }, { NULL, NULL, NULL, NULL } }; @@ -690,7 +691,7 @@ static const WT_CONFIG_ENTRY config_entries[] = { "eviction=(threads_max=1,threads_min=1),eviction_dirty_target=80," "eviction_target=80,eviction_trigger=95,exclusive=0,extensions=," "file_extend=,hazard_max=1000,log=(archive=,compressor=,enabled=0" - ",file_max=100MB,path=,prealloc=),lsm_manager=(merge=," + ",file_max=100MB,path=,prealloc=,recover=on),lsm_manager=(merge=," "worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0," "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB" ",name=,reserve=0,size=500MB),statistics=none," @@ -708,7 +709,7 @@ static const WT_CONFIG_ENTRY config_entries[] = { "eviction=(threads_max=1,threads_min=1),eviction_dirty_target=80," "eviction_target=80,eviction_trigger=95,exclusive=0,extensions=," "file_extend=,hazard_max=1000,log=(archive=,compressor=,enabled=0" - ",file_max=100MB,path=,prealloc=),lsm_manager=(merge=," + ",file_max=100MB,path=,prealloc=,recover=on),lsm_manager=(merge=," "worker_thread_max=4),lsm_merge=,mmap=,multiprocess=0," "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB" ",name=,reserve=0,size=500MB),statistics=none," @@ -725,8 +726,8 @@ static const WT_CONFIG_ENTRY config_entries[] = { "direct_io=,error_prefix=,eviction=(threads_max=1,threads_min=1)," "eviction_dirty_target=80,eviction_target=80,eviction_trigger=95," "extensions=,file_extend=,hazard_max=1000,log=(archive=," - "compressor=,enabled=0,file_max=100MB,path=,prealloc=)," - "lsm_manager=(merge=,worker_thread_max=4),lsm_merge=,mmap=," + "compressor=,enabled=0,file_max=100MB,path=,prealloc=,recover=on)" + ",lsm_manager=(merge=,worker_thread_max=4),lsm_merge=,mmap=," "multiprocess=0,session_max=100,session_scratch_max=2MB," "shared_cache=(chunk=10MB,name=,reserve=0,size=500MB)," "statistics=none,statistics_log=(on_close=0," @@ -742,8 +743,8 @@ static const WT_CONFIG_ENTRY config_entries[] = { "direct_io=,error_prefix=,eviction=(threads_max=1,threads_min=1)," "eviction_dirty_target=80,eviction_target=80,eviction_trigger=95," "extensions=,file_extend=,hazard_max=1000,log=(archive=," - "compressor=,enabled=0,file_max=100MB,path=,prealloc=)," - "lsm_manager=(merge=,worker_thread_max=4),lsm_merge=,mmap=," + "compressor=,enabled=0,file_max=100MB,path=,prealloc=,recover=on)" + ",lsm_manager=(merge=,worker_thread_max=4),lsm_merge=,mmap=," "multiprocess=0,session_max=100,session_scratch_max=2MB," "shared_cache=(chunk=10MB,name=,reserve=0,size=500MB)," "statistics=none,statistics_log=(on_close=0," diff --git a/src/conn/api_strerror.c b/src/conn/api_strerror.c index 396ae7a3e0f..4b2f6f12f7c 100644 --- a/src/conn/api_strerror.c +++ b/src/conn/api_strerror.c @@ -32,6 +32,8 @@ __wiredtiger_error(int error) return ("WT_PANIC: WiredTiger library panic"); case WT_RESTART: return ("WT_RESTART: restart the operation (internal)"); + case WT_RUN_RECOVERY: + return ("WT_RUN_RECOVERY: recovery must be run to continue"); } return (NULL); } diff --git a/src/conn/conn_log.c b/src/conn/conn_log.c index 11abc7c1e2b..36d4d539d92 100644 --- a/src/conn/conn_log.c +++ b/src/conn/conn_log.c @@ -98,6 +98,9 @@ __logmgr_config(WT_SESSION_IMPL *session, const char **cfg, int *runp) FLD_SET(conn->log_flags, WT_CONN_LOG_PREALLOC); conn->log_prealloc = 1; } + WT_RET(__wt_config_gets_def(session, cfg, "log.recover", 0, &cval)); + if (cval.len != 0 && WT_STRING_MATCH("error", cval.str, cval.len)) + FLD_SET(conn->log_flags, WT_CONN_LOG_RECOVER_ERR); WT_RET(__logmgr_sync_cfg(session, cfg)); return (0); diff --git a/src/docs/error-handling.dox b/src/docs/error-handling.dox index cf268f80500..d1291e38ff0 100644 --- a/src/docs/error-handling.dox +++ b/src/docs/error-handling.dox @@ -49,6 +49,9 @@ This error indicates an operation did not find a value to return. This includes @par <code>WT_PANIC</code> This error indicates an underlying problem that requires the application exit and restart. The application can exit immediately when \c WT_PANIC is returned from a WiredTiger interface, no further WiredTiger calls are required. +@par <code>WT_RUN_RECOVERY</code> +This error is generated when wiredtiger_open is configured to return an error if recovery is required to use the database. + @if IGNORE_BUILT_BY_API_ERR_END @endif diff --git a/src/include/connection.h b/src/include/connection.h index dd97ea50ce9..ff5e401fadd 100644 --- a/src/include/connection.h +++ b/src/include/connection.h @@ -310,6 +310,7 @@ struct __wt_connection_impl { #define WT_CONN_LOG_ENABLED 0x02 /* Logging is enabled */ #define WT_CONN_LOG_EXISTED 0x04 /* Log files found */ #define WT_CONN_LOG_PREALLOC 0x08 /* Pre-allocation is enabled */ +#define WT_CONN_LOG_RECOVER_ERR 0x10 /* Error if recovery required */ uint32_t log_flags; /* Global logging configuration */ WT_CONDVAR *log_cond; /* Log server wait mutex */ WT_SESSION_IMPL *log_session; /* Log server session */ diff --git a/src/include/extern.h b/src/include/extern.h index 7716336bff1..40493b4aab4 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -304,6 +304,7 @@ extern void __wt_cache_dump(WT_SESSION_IMPL *session); extern int __wt_evict(WT_SESSION_IMPL *session, WT_REF *ref, int exclusive); extern void __wt_evict_page_clean_update(WT_SESSION_IMPL *session, WT_REF *ref); extern int __wt_log_ckpt(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn); +extern int __wt_log_needs_recovery(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn, int *rec); extern void __wt_log_written_reset(WT_SESSION_IMPL *session); extern int __wt_log_get_all_files(WT_SESSION_IMPL *session, char ***filesp, u_int *countp, uint32_t *maxid, int active_only); extern void __wt_log_files_free(WT_SESSION_IMPL *session, char **files, u_int count); diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 80e0975d7e6..08cdb7d2a5d 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -1973,6 +1973,9 @@ struct __wt_connection { * are created relative to the database home., a string; default empty.} * @config{ prealloc, pre-allocate log files., a boolean * flag; default \c true.} + * @config{ recover, run recovery + * or error if recovery needs to run after an unclean shutdown., a string\, + * chosen from the following options: \c "error"\, \c "on"; default \c on.} * @config{ ),,} * @config{lsm_manager = (, configure database wide options for LSM tree * management., a set of related configuration options defined below.} @@ -2618,6 +2621,12 @@ const char *wiredtiger_version(int *majorp, int *minorp, int *patchp); /*! Restart the operation (internal). */ #define WT_RESTART -31805 /*! @endcond */ +/*! + * Recovery must be run to continue. + * This error is generated when wiredtiger_open is configured to return an error + * if recovery is required to use the database. + */ +#define WT_RUN_RECOVERY -31806 /* * Error return section: END * DO NOT EDIT: automatically built by dist/api_err.py. diff --git a/src/log/log.c b/src/log/log.c index 38c953d7835..f6c8602faff 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -36,6 +36,45 @@ __wt_log_ckpt(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn) } /* + * __wt_log_needs_recovery -- + * Return 0 if we encounter a clean shutdown and 1 if recovery + * must be run in the given variable. + */ +int +__wt_log_needs_recovery(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn, int *rec) +{ + WT_CONNECTION_IMPL *conn; + WT_CURSOR *c; + WT_DECL_RET; + WT_LOG *log; + + conn = S2C(session); + log = conn->log; + c = NULL; + /* + * Default is to run recovery always. + */ + *rec = 1; + + if (log == NULL) + return (0); + WT_RET(__wt_curlog_open(session, "log:", NULL, &c)); + c->set_key(c, ckp_lsn->file, ckp_lsn->offset, 0); + WT_ERR(c->search(c)); + /* + * If the checkpoint LSN we're given is the last record, + * then recovery is not needed. + */ + if ((ret = c->next(c)) == WT_NOTFOUND) { + *rec = 0; + ret = 0; + } +err: if (c != NULL) + (void)c->close(c); + return (ret); +} + +/* * __wt_log_written_reset -- * Interface to reset the amount of log written during this * checkpoint period. Called from the checkpoint code. diff --git a/src/txn/txn_recover.c b/src/txn/txn_recover.c index 71f5df9dda2..de7504c0a8b 100644 --- a/src/txn/txn_recover.c +++ b/src/txn/txn_recover.c @@ -412,7 +412,7 @@ __wt_txn_recover(WT_SESSION_IMPL *session) WT_RECOVERY r; struct WT_RECOVERY_FILE *metafile; char *config; - int was_backup; + int needs_rec, was_backup; conn = S2C(session); WT_CLEAR(r); @@ -483,14 +483,26 @@ __wt_txn_recover(WT_SESSION_IMPL *session) WT_ERR(__wt_verbose(session, WT_VERB_RECOVERY, "Main recovery loop: starting at %u/%" PRIuMAX, r.ckpt_lsn.file, (uintmax_t)r.ckpt_lsn.offset)); + WT_ERR(__wt_log_needs_recovery( + session, &r.ckpt_lsn, &needs_rec)); + /* + * Check if the database was shut down cleanly. If not + * return an error if the user does not want automatic + * recovery. + */ + if (needs_rec && FLD_ISSET(conn->log_flags, WT_CONN_LOG_RECOVER_ERR)) + WT_ERR(WT_RUN_RECOVERY); + /* + * Always run recovery even if it was a clean shutdown. + * We can consider skipping it in the future. + */ if (WT_IS_INIT_LSN(&r.ckpt_lsn)) WT_ERR(__wt_log_scan(session, NULL, WT_LOGSCAN_FIRST | WT_LOGSCAN_RECOVER, __txn_log_recover, &r)); else WT_ERR(__wt_log_scan(session, &r.ckpt_lsn, - WT_LOGSCAN_RECOVER, - __txn_log_recover, &r)); + WT_LOGSCAN_RECOVER, __txn_log_recover, &r)); conn->next_file_id = r.max_fileid; diff --git a/src/utilities/util_main.c b/src/utilities/util_main.c index 9eef7bb4554..19afc9b520d 100644 --- a/src/utilities/util_main.c +++ b/src/utilities/util_main.c @@ -11,11 +11,15 @@ const char *home = "."; /* Home directory */ const char *progname; /* Program name */ /* Global arguments */ -const char *usage_prefix = "[-Vv] [-r] [-C config] [-h home]"; +const char *usage_prefix = "[-Vv] [-R] [-C config] [-h home]"; int verbose; /* Verbose flag */ static const char *command; /* Command name */ +#define REC_ERROR "log=(recover=error)" +#define REC_LOGOFF "log=(enabled=false)" +#define REC_RECOVER "log=(recover=on)" + static int usage(void); int @@ -54,15 +58,14 @@ main(int argc, char *argv[]) cmd_config = config = NULL; /* - * We default to turning recovery off by setting the config string - * to disable logging. Commands that should recover, if the - * underlying database was originally using logging, will set the - * rec_config to NULL. That will run recovery if needed when - * wiredtiger_open is called. + * We default to returning an error if recovery needs to be run. + * Generally we expect this to be run after a clean shutdown. + * The printlog command disables logging entirely. If recovery is + * needed, the user can specify -R to run recovery. */ - rec_config = "log=(enabled=false)"; + rec_config = REC_ERROR; /* Check for standard options. */ - while ((ch = __wt_getopt(progname, argc, argv, "C:h:rVv")) != EOF) + while ((ch = __wt_getopt(progname, argc, argv, "C:h:RVv")) != EOF) switch (ch) { case 'C': /* wiredtiger_open config */ cmd_config = __wt_optarg; @@ -70,8 +73,8 @@ main(int argc, char *argv[]) case 'h': /* home directory */ home = __wt_optarg; break; - case 'r': /* recovery */ - rec_config = NULL; + case 'R': /* recovery */ + rec_config = REC_RECOVER; break; case 'V': /* version */ printf("%s\n", wiredtiger_version(NULL, NULL, NULL)); @@ -101,23 +104,20 @@ main(int argc, char *argv[]) func = util_backup; break; case 'c': - if (strcmp(command, "compact") == 0) { + if (strcmp(command, "compact") == 0) func = util_compact; - rec_config = NULL; - } else if (strcmp(command, "copyright") == 0) { + else if (strcmp(command, "copyright") == 0) { util_copyright(); return (EXIT_SUCCESS); } else if (strcmp(command, "create") == 0) { func = util_create; config = "create"; - rec_config = NULL; } break; case 'd': - if (strcmp(command, "drop") == 0) { + if (strcmp(command, "drop") == 0) func = util_drop; - rec_config = NULL; - } else if (strcmp(command, "dump") == 0) + else if (strcmp(command, "dump") == 0) func = util_dump; break; case 'l': @@ -126,24 +126,21 @@ main(int argc, char *argv[]) else if (strcmp(command, "load") == 0) { func = util_load; config = "create"; - rec_config = NULL; } else if (strcmp(command, "loadtext") == 0) { func = util_loadtext; config = "create"; - rec_config = NULL; } break; case 'p': if (strcmp(command, "printlog") == 0) func = util_printlog; + rec_config = REC_LOGOFF; break; case 'r': if (strcmp(command, "read") == 0) func = util_read; - else if (strcmp(command, "rename") == 0) { + else if (strcmp(command, "rename") == 0) func = util_rename; - rec_config = NULL; - } break; case 's': if (strcmp(command, "salvage") == 0) @@ -154,20 +151,16 @@ main(int argc, char *argv[]) } break; case 'u': - if (strcmp(command, "upgrade") == 0) { + if (strcmp(command, "upgrade") == 0) func = util_upgrade; - rec_config = NULL; - } break; case 'v': if (strcmp(command, "verify") == 0) func = util_verify; break; case 'w': - if (strcmp(command, "write") == 0) { + if (strcmp(command, "write") == 0) func = util_write; - rec_config = NULL; - } break; default: break; @@ -230,7 +223,7 @@ usage(void) "global options:\n" "\t" "-C\twiredtiger_open configuration\n" "\t" "-h\tdatabase directory\n" - "\t" "-r\trun recovery if configured\n" + "\t" "-R\trun recovery if configured\n" "\t" "-V\tdisplay library version and exit\n" "\t" "-v\tverbose\n"); fprintf(stderr, |