summaryrefslogtreecommitdiff
path: root/src/env/env_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/env/env_open.c')
-rw-r--r--src/env/env_open.c250
1 files changed, 160 insertions, 90 deletions
diff --git a/src/env/env_open.c b/src/env/env_open.c
index 7eddca3a..85189369 100644
--- a/src/env/env_open.c
+++ b/src/env/env_open.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -107,10 +107,16 @@ __env_open_pp(dbenv, db_home, flags, mode)
__db_errx(env, DB_STR("1589", "DB_PRIVATE is not "
"supported by 64-bit applications in "
"mixed-size-addressing mode"));
- return (EINVAL);
- }
+ return (EINVAL);
+ }
#endif
+ if (LF_ISSET(DB_PRIVATE) && PREFMAS_IS_SET(env)) {
+ __db_errx(env, DB_STR("1594", "DB_PRIVATE is not "
+ "supported in Replication Manager preferred master mode"));
+ return (EINVAL);
+ }
+
return (__env_open(dbenv, db_home, flags, mode));
}
@@ -129,12 +135,20 @@ __env_open(dbenv, db_home, flags, mode)
{
DB_THREAD_INFO *ip;
ENV *env;
- u_int32_t orig_flags;
- int register_recovery, ret, t_ret;
+ u_int32_t orig_flags, retry_flags;
+ int recovery_failed, register_recovery, ret, t_ret;
+ char *old_passwd;
+ size_t old_passwd_len;
+ u_int32_t old_encrypt_flags;
ip = NULL;
env = dbenv->env;
+ recovery_failed = 1;
register_recovery = 0;
+ retry_flags = 0;
+ old_passwd = NULL;
+ old_passwd_len = 0;
+ old_encrypt_flags = 0;
/* Initial configuration. */
if ((ret = __env_config(dbenv, db_home, &flags, mode)) != 0)
@@ -171,13 +185,27 @@ __env_open(dbenv, db_home, flags, mode)
dbenv->is_alive = __envreg_isalive;
}
- if ((ret =
- __envreg_register(env, &register_recovery, flags)) != 0)
+ /*
+ * Backup the current key, because it would be consumed by
+ * __envreg_register below
+ */
+ if (dbenv->passwd != NULL) {
+ if ((ret = __os_strdup(env, dbenv->passwd, &old_passwd)) != 0)
+ goto err;
+ old_passwd_len = dbenv->passwd_len;
+ (void)__env_get_encrypt_flags(dbenv, &old_encrypt_flags);
+ }
+
+ F_SET(dbenv, DB_ENV_NOPANIC);
+ ret = __envreg_register(env, &register_recovery, flags);
+ dbenv->flags = orig_flags;
+ if (ret != 0)
goto err;
if (register_recovery) {
if (!LF_ISSET(DB_RECOVER)) {
__db_errx(env, DB_STR("1567",
"The DB_RECOVER flag was not specified, and recovery is needed"));
+ recovery_failed = 0;
ret = DB_RUNRECOVERY;
goto err;
}
@@ -197,16 +225,27 @@ __env_open(dbenv, db_home, flags, mode)
* want to remove files left over for any reason, from any session.
*/
retry: if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))
+ if (
#ifdef HAVE_REPLICATION
- if ((ret = __rep_reset_init(env)) != 0 ||
- (ret = __env_remove_env(env)) != 0 ||
-#else
- if ((ret = __env_remove_env(env)) != 0 ||
+ (ret = __rep_reset_init(env)) != 0 ||
#endif
- (ret = __env_refresh(dbenv, orig_flags, 0)) != 0)
+ (ret = __env_remove_env(env)) != 0 ||
+ (ret = __env_refresh(dbenv,
+ orig_flags | retry_flags, 0)) != 0)
goto err;
- if ((ret = __env_attach_regions(dbenv, flags, orig_flags, 1)) != 0)
+ /* Restore the database key. */
+ if (LF_ISSET(DB_REGISTER) && old_passwd != NULL) {
+ ret = __env_set_encrypt(dbenv, old_passwd, old_encrypt_flags);
+ memset(old_passwd, 0xff, old_passwd_len - 1);
+ __os_free(env, old_passwd);
+ if (ret != 0)
+ goto err;
+ }
+
+ DB_ASSERT(env, ret == 0);
+ if ((ret = __env_attach_regions(dbenv,
+ flags, orig_flags | retry_flags, 1)) != 0)
goto err;
/*
@@ -216,8 +255,18 @@ retry: if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))
*/
if (LF_ISSET(DB_FAILCHK) && !register_recovery) {
ENV_ENTER(env, ip);
- if ((ret = __env_failchk_int(dbenv)) != 0)
+ /*
+ * Set the thread state so that any waiting for a potentially
+ * dead thread will call is_alive() in order to avoid hanging.
+ */
+ FAILCHK_THREAD(env, ip);
+ ret = __env_failchk_int(dbenv);
+ if (ret != 0) {
+ __db_err(env, ret,
+ DB_STR("1595",
+ "failchk crash after clean registry"));
goto err;
+ }
ENV_LEAVE(env, ip);
}
@@ -230,12 +279,12 @@ err: if (ret != 0)
* processes can now proceed.
*
* If recovery failed, unregister now and let another process
- * clean up.
+ * clean up and run recovery.
*/
if (ret == 0 && (t_ret = __envreg_xunlock(env)) != 0)
ret = t_ret;
if (ret != 0)
- (void)__envreg_unregister(env, 1);
+ (void)__envreg_unregister(env, recovery_failed);
}
/*
@@ -247,7 +296,11 @@ err: if (ret != 0)
*/
if (ret == DB_RUNRECOVERY && !register_recovery &&
!LF_ISSET(DB_RECOVER) && LF_ISSET(DB_REGISTER)) {
+ if (FLD_ISSET(dbenv->verbose, DB_VERB_REGISTER))
+ __db_msg(env, DB_STR("1596",
+ "env_open DB_REGISTER w/o RECOVER panic: trying w/recovery"));
LF_SET(DB_RECOVER);
+ retry_flags = DB_ENV_NOPANIC;
goto retry;
}
@@ -304,6 +357,9 @@ __env_open_arg(dbenv, flags)
"replication requires transaction support"));
return (EINVAL);
}
+ if ((ret =
+ __log_set_config_int(dbenv, DB_LOG_BLOB, 1, 1)) != 0)
+ return (ret);
}
if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
if ((ret = __db_fcchk(env,
@@ -349,30 +405,6 @@ __env_open_arg(dbenv, flags)
}
#endif
-#ifdef HAVE_MUTEX_FCNTL
- /*
- * !!!
- * We need a file descriptor for fcntl(2) locking. We use the file
- * handle from the REGENV file for this purpose.
- *
- * Since we may be using shared memory regions, e.g., shmget(2), and
- * not a mapped-in regular file, the backing file may be only a few
- * bytes in length. So, this depends on the ability to call fcntl to
- * lock file offsets much larger than the actual physical file. I
- * think that's safe -- besides, very few systems actually need this
- * kind of support, SunOS is the only one still in wide use of which
- * I'm aware.
- *
- * The error case is if an application lacks spinlocks and wants to be
- * threaded. That doesn't work because fcntl will lock the underlying
- * process, including all its threads.
- */
- if (F_ISSET(env, ENV_THREAD)) {
- __db_errx(env, DB_STR("1578",
- "architecture lacks fast mutexes: applications cannot be threaded"));
- return (EINVAL);
- }
-#endif
return (ret);
}
@@ -506,7 +538,7 @@ __env_close_pp(dbenv, flags)
{
DB_THREAD_INFO *ip;
ENV *env;
- int rep_check, ret, t_ret;
+ int ret, t_ret;
u_int32_t close_flags, flags_orig;
env = dbenv->env;
@@ -517,65 +549,75 @@ __env_close_pp(dbenv, flags)
* Validate arguments, but as a DB_ENV handle destructor, we can't
* fail.
*/
- if (flags != 0 && flags != DB_FORCESYNC &&
- (t_ret = __db_ferr(env, "DB_ENV->close", 0)) != 0 && ret == 0)
- ret = t_ret;
+#undef OKFLAGS
+#define OKFLAGS (DB_FORCESYNC | DB_FORCESYNCENV)
+
+ ret = __db_fchk(env, "DB_ENV->close", flags, OKFLAGS);
#define DBENV_FORCESYNC 0x00000001
#define DBENV_CLOSE_REPCHECK 0x00000010
- if (flags == DB_FORCESYNC)
+ if (LF_ISSET(DB_FORCESYNC))
close_flags |= DBENV_FORCESYNC;
+ if (LF_ISSET(DB_FORCESYNCENV))
+ F_SET(env, ENV_FORCESYNCENV);
+
+ /*
+ * Call __env_close() to clean up resources even though the open
+ * didn't fully succeed.
+ * */
+ if (!F_ISSET(env, ENV_OPEN_CALLED))
+ goto do_close;
/*
* If the environment has panic'd, all we do is try and discard
* the important resources.
*/
if (PANIC_ISSET(env)) {
+ /*
+ * Temporarily set no panic so we do not trigger the
+ * LAST_PANIC_CHECK_BEFORE_IO check in __os_physwrite thus
+ * allowing the unregister to happen correctly.
+ */
+ flags_orig = dbenv->flags;
+ F_SET(dbenv, DB_ENV_NOPANIC);
+ ENV_ENTER(env, ip);
/* clean up from registry file */
- if (dbenv->registry != NULL) {
- /*
- * Temporarily set no panic so we do not trigger the
- * LAST_PANIC_CHECK_BEFORE_IO check in __os_physwr
- * thus allowing the unregister to happen correctly.
- */
- flags_orig = F_ISSET(dbenv, DB_ENV_NOPANIC);
- F_SET(dbenv, DB_ENV_NOPANIC);
+ if (dbenv->registry != NULL)
(void)__envreg_unregister(env, 0);
- dbenv->registry = NULL;
- if (!flags_orig)
- F_CLR(dbenv, DB_ENV_NOPANIC);
- }
/* Close all underlying threads and sockets. */
- if (IS_ENV_REPLICATED(env))
- (void)__repmgr_close(env);
+ (void)__repmgr_close(env);
/* Close all underlying file handles. */
(void)__file_handle_cleanup(env);
+ ENV_LEAVE(env, ip);
+
+ dbenv->flags = flags_orig;
+ (void)__env_region_cleanup(env);
- PANIC_CHECK(env);
+ return (__env_panic_msg(env));
}
ENV_ENTER(env, ip);
- rep_check = IS_ENV_REPLICATED(env) ? 1 : 0;
- if (rep_check) {
#ifdef HAVE_REPLICATION_THREADS
- /*
- * Shut down Replication Manager threads first of all. This
- * must be done before __env_rep_enter to avoid a deadlock that
- * could occur if repmgr's background threads try to do a rep
- * operation that needs __rep_lockout.
- */
- if ((t_ret = __repmgr_close(env)) != 0 && ret == 0)
- ret = t_ret;
+ /*
+ * Shut down Replication Manager threads first of all. This
+ * must be done before __env_rep_enter to avoid a deadlock that
+ * could occur if repmgr's background threads try to do a rep
+ * operation that needs __rep_lockout.
+ */
+ if ((t_ret = __repmgr_close(env)) != 0 && ret == 0)
+ ret = t_ret;
#endif
+ if (IS_ENV_REPLICATED(env)) {
if ((t_ret = __env_rep_enter(env, 0)) != 0 && ret == 0)
ret = t_ret;
+ if (ret == 0)
+ close_flags |= DBENV_CLOSE_REPCHECK;
}
- if (rep_check)
- close_flags |= DBENV_CLOSE_REPCHECK;
+do_close:
if ((t_ret = __env_close(dbenv, close_flags)) != 0 && ret == 0)
ret = t_ret;
@@ -640,8 +682,11 @@ __env_close(dbenv, flags)
t_ret = dbp->alt_close(dbp, close_flags);
else
t_ret = __db_close(dbp, NULL, close_flags);
- if (t_ret != 0 && ret == 0)
- ret = t_ret;
+ if (t_ret != 0) {
+ if (ret == 0)
+ ret = t_ret;
+ break;
+ }
}
/*
@@ -661,10 +706,8 @@ __env_close(dbenv, flags)
#endif
/* If we're registered, clean up. */
- if (dbenv->registry != NULL) {
+ if (dbenv->registry != NULL)
(void)__envreg_unregister(env, 0);
- dbenv->registry = NULL;
- }
/* Check we've closed all underlying file handles. */
if ((t_ret = __file_handle_cleanup(env)) != 0 && ret == 0)
@@ -680,6 +723,9 @@ __env_close(dbenv, flags)
if (dbenv->db_md_dir != NULL)
__os_free(env, dbenv->db_md_dir);
dbenv->db_md_dir = NULL;
+ if (dbenv->db_blob_dir != NULL)
+ __os_free(env, dbenv->db_blob_dir);
+ dbenv->db_blob_dir = NULL;
if (dbenv->db_data_dir != NULL) {
for (p = dbenv->db_data_dir; *p != NULL; ++p)
__os_free(env, *p);
@@ -761,9 +807,7 @@ __env_refresh(dbenv, orig_flags, rep_check)
ret = t_ret;
}
- /* Discard the DB_ENV, ENV handle mutexes. */
- if ((t_ret = __mutex_free(env, &dbenv->mtx_db_env)) != 0 && ret == 0)
- ret = t_ret;
+ /* Discard the ENV handle mutex. */
if ((t_ret = __mutex_free(env, &env->mtx_env)) != 0 && ret == 0)
ret = t_ret;
@@ -936,17 +980,38 @@ __file_handle_cleanup(env)
ENV *env;
{
DB_FH *fhp;
+ DB_MPOOL *dbmp;
+ u_int i;
- if (TAILQ_FIRST(&env->fdlist) == NULL)
+ if (TAILQ_EMPTY(&env->fdlist))
return (0);
- __db_errx(env, DB_STR("1581",
- "File handles still open at environment close"));
+ __db_errx(env,
+ DB_STR("1581", "File handles still open at environment close"));
while ((fhp = TAILQ_FIRST(&env->fdlist)) != NULL) {
- __db_errx(env, DB_STR_A("1582", "Open file handle: %s", "%s"),
- fhp->name);
- (void)__os_closehandle(env, fhp);
+ __db_errx(env,
+ DB_STR_A("1582", "Open file handle: %s", "%s"), fhp->name);
+ if (__os_closehandle(env, fhp) != 0)
+ break;
}
+ if (env->lockfhp != NULL)
+ env->lockfhp = NULL;
+ /* Invalidate saved pointers to the regions' files: all are closed. */
+ if (env->reginfo != NULL)
+ env->reginfo->fhp = NULL;
+ if (env->lg_handle != NULL)
+ env->lg_handle->reginfo.fhp = NULL;
+ if (env->lk_handle != NULL)
+ env->lk_handle->reginfo.fhp = NULL;
+#ifdef HAVE_MUTEX_SUPPORT
+ if (env->mutex_handle != NULL)
+ env->mutex_handle->reginfo.fhp = NULL;
+#endif
+ if (env->tx_handle != NULL)
+ env->tx_handle->reginfo.fhp = NULL;
+ if ((dbmp = env->mp_handle) != NULL && dbmp->reginfo != NULL)
+ for (i = 0; i < env->dbenv->mp_ncache; ++i)
+ dbmp->reginfo[i].fhp = NULL;
return (EINVAL);
}
@@ -1109,11 +1174,9 @@ __env_attach_regions(dbenv, flags, orig_flags, retry_ok)
goto err;
/*
- * Initialize the handle mutexes.
+ * Initialize the handle mutex.
*/
if ((ret = __mutex_alloc(env,
- MTX_ENV_HANDLE, DB_MUTEX_PROCESS_ONLY, &dbenv->mtx_db_env)) != 0 ||
- (ret = __mutex_alloc(env,
MTX_ENV_HANDLE, DB_MUTEX_PROCESS_ONLY, &env->mtx_env)) != 0)
goto err;
@@ -1125,8 +1188,15 @@ __env_attach_regions(dbenv, flags, orig_flags, retry_ok)
goto err;
rep_check = IS_ENV_REPLICATED(env) ? 1 : 0;
- if (rep_check && (ret = __env_rep_enter(env, 0)) != 0)
+ if (rep_check && (ret = __env_rep_enter(env, 0)) != 0) {
+ /*
+ * If we get an error we didn't increment handle_cnt,
+ * so we don't want to decrement it later. Turn off
+ * rep_check here.
+ */
+ rep_check = 0;
goto err;
+ }
if (LF_ISSET(DB_INIT_MPOOL)) {
if ((ret = __memp_open(env, create_ok)) != 0)