summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/api_data.py4
-rw-r--r--dist/api_err.py4
-rw-r--r--dist/s_string.ok2
-rw-r--r--examples/c/ex_backup.c6
-rw-r--r--src/config/config_def.c13
-rw-r--r--src/conn/api_strerror.c2
-rw-r--r--src/conn/conn_log.c3
-rw-r--r--src/docs/error-handling.dox3
-rw-r--r--src/include/connection.h1
-rw-r--r--src/include/extern.h1
-rw-r--r--src/include/wiredtiger.in9
-rw-r--r--src/log/log.c39
-rw-r--r--src/txn/txn_recover.c18
-rw-r--r--src/utilities/util_main.c51
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{&nbsp;&nbsp;&nbsp;&nbsp;prealloc, pre-allocate log files., a boolean
* flag; default \c true.}
+ * @config{&nbsp;&nbsp;&nbsp;&nbsp;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,