📄 env_open.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996-2002 * Sleepycat Software. All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: env_open.c,v 11.111 2002/09/03 01:20:51 mjc Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <ctype.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#endif#include "db_int.h"#include "dbinc/crypto.h"#include "dbinc/db_page.h"#include "dbinc/db_shash.h"#include "dbinc/btree.h"#include "dbinc/hash.h"#include "dbinc/lock.h"#include "dbinc/log.h"#include "dbinc/mp.h"#include "dbinc/qam.h"#include "dbinc/rep.h"#include "dbinc/txn.h"#include "dbinc/fop.h"static int __db_parse __P((DB_ENV *, char *));static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, DB_FH *));static int __dbenv_config __P((DB_ENV *, const char *, u_int32_t));static int __dbenv_iremove __P((DB_ENV *, const char *, u_int32_t));static int __dbenv_refresh __P((DB_ENV *, u_int32_t));/* * db_version -- * Return version information. * * EXTERN: char *db_version __P((int *, int *, int *)); */char *db_version(majverp, minverp, patchp) int *majverp, *minverp, *patchp;{ if (majverp != NULL) *majverp = DB_VERSION_MAJOR; if (minverp != NULL) *minverp = DB_VERSION_MINOR; if (patchp != NULL) *patchp = DB_VERSION_PATCH; return ((char *)DB_VERSION_STRING);}/* * __dbenv_open -- * Initialize an environment. * * PUBLIC: int __dbenv_open __P((DB_ENV *, const char *, u_int32_t, int)); */int__dbenv_open(dbenv, db_home, flags, mode) DB_ENV *dbenv; const char *db_home; u_int32_t flags; int mode;{ DB_MPOOL *dbmp; int ret; u_int32_t init_flags, orig_flags; orig_flags = dbenv->flags;#undef OKFLAGS#define OKFLAGS \ DB_CREATE | DB_INIT_CDB | DB_INIT_LOCK | DB_INIT_LOG | \ DB_INIT_MPOOL | DB_INIT_TXN | DB_JOINENV | DB_LOCKDOWN | \ DB_PRIVATE | DB_RECOVER | DB_RECOVER_FATAL | DB_SYSTEM_MEM | \ DB_THREAD | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT#undef OKFLAGS_CDB#define OKFLAGS_CDB \ DB_CREATE | DB_INIT_CDB | DB_INIT_MPOOL | DB_LOCKDOWN | \ DB_PRIVATE | DB_SYSTEM_MEM | DB_THREAD | \ DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT /* * Flags saved in the init_flags field of the environment, representing * flags to DB_ENV->set_flags and DB_ENV->open that need to be set. */#define DB_INITENV_CDB 0x0001 /* DB_INIT_CDB */#define DB_INITENV_CDB_ALLDB 0x0002 /* DB_INIT_CDB_ALLDB */#define DB_INITENV_LOCK 0x0004 /* DB_INIT_LOCK */#define DB_INITENV_LOG 0x0008 /* DB_INIT_LOG */#define DB_INITENV_MPOOL 0x0010 /* DB_INIT_MPOOL */#define DB_INITENV_TXN 0x0020 /* DB_INIT_TXN */ if ((ret = __db_fchk(dbenv, "DB_ENV->open", flags, OKFLAGS)) != 0) return (ret); if (LF_ISSET(DB_INIT_CDB) && (ret = __db_fchk(dbenv, "DB_ENV->open", flags, OKFLAGS_CDB)) != 0) return (ret); if ((ret = __db_fcchk(dbenv, "DB_ENV->open", flags, DB_PRIVATE, DB_SYSTEM_MEM)) != 0) return (ret); if ((ret = __db_fcchk(dbenv, "DB_ENV->open", flags, DB_RECOVER, DB_RECOVER_FATAL)) != 0) return (ret); if ((ret = __db_fcchk(dbenv, "DB_ENV->open", flags, DB_JOINENV, DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN | DB_PRIVATE)) != 0) return (ret); /* * Currently we support one kind of mutex that is intra-process only, * POSIX 1003.1 pthreads, because a variety of systems don't support * the full pthreads API, and our only alternative is test-and-set. */#ifdef HAVE_MUTEX_THREAD_ONLY if (!LF_ISSET(DB_PRIVATE)) { __db_err(dbenv, "Berkeley DB library configured to support only DB_PRIVATE environments"); return (EINVAL); }#endif /* * If we're doing recovery, destroy the environment so that we create * all the regions from scratch. I'd like to reuse already created * regions, but that's hard. We would have to create the environment * region from scratch, at least, as we have no way of knowing if its * linked lists are corrupted. * * I suppose we could set flags while modifying those links, but that * is going to be difficult to get right. The major concern I have * is if the application stomps the environment with a rogue pointer. * We have no way of detecting that, and we could be forced into a * situation where we start up and then crash, repeatedly. * * Note that we do not check any flags like DB_PRIVATE before calling * remove. We don't care if the current environment was private or * not, we just want to nail any files that are left-over for whatever * reason, from whatever session. */ if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) if ((ret = __dbenv_iremove(dbenv, db_home, DB_FORCE)) != 0 || (ret = __dbenv_refresh(dbenv, orig_flags)) != 0) return (ret); /* Initialize the DB_ENV structure. */ if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0) goto err; /* Convert the DB_ENV->open flags to internal flags. */ if (LF_ISSET(DB_CREATE)) F_SET(dbenv, DB_ENV_CREATE); if (LF_ISSET(DB_LOCKDOWN)) F_SET(dbenv, DB_ENV_LOCKDOWN); if (LF_ISSET(DB_PRIVATE)) F_SET(dbenv, DB_ENV_PRIVATE); if (LF_ISSET(DB_RECOVER_FATAL)) F_SET(dbenv, DB_ENV_FATAL); if (LF_ISSET(DB_SYSTEM_MEM)) F_SET(dbenv, DB_ENV_SYSTEM_MEM); if (LF_ISSET(DB_THREAD)) F_SET(dbenv, DB_ENV_THREAD); /* Default permissions are read-write for both owner and group. */ dbenv->db_mode = mode == 0 ? __db_omode("rwrw--") : mode; /* * Create/join the environment. We pass in the flags that * will be of interest to an environment joining later; if * we're not the ones to do the create, we * pull out whatever has been stored, if we don't do a create. */ init_flags = 0; init_flags |= (LF_ISSET(DB_INIT_CDB) ? DB_INITENV_CDB : 0); init_flags |= (LF_ISSET(DB_INIT_LOCK) ? DB_INITENV_LOCK : 0); init_flags |= (LF_ISSET(DB_INIT_LOG) ? DB_INITENV_LOG : 0); init_flags |= (LF_ISSET(DB_INIT_MPOOL) ? DB_INITENV_MPOOL : 0); init_flags |= (LF_ISSET(DB_INIT_TXN) ? DB_INITENV_TXN : 0); init_flags |= (F_ISSET(dbenv, DB_ENV_CDB_ALLDB) ? DB_INITENV_CDB_ALLDB : 0); if ((ret = __db_e_attach(dbenv, &init_flags)) != 0) goto err; /* * __db_e_attach will return the saved init_flags field, which * contains the DB_INIT_* flags used when we were created. */ if (LF_ISSET(DB_JOINENV)) { LF_CLR(DB_JOINENV); LF_SET((init_flags & DB_INITENV_CDB) ? DB_INIT_CDB : 0); LF_SET((init_flags & DB_INITENV_LOCK) ? DB_INIT_LOCK : 0); LF_SET((init_flags & DB_INITENV_LOG) ? DB_INIT_LOG : 0); LF_SET((init_flags & DB_INITENV_MPOOL) ? DB_INIT_MPOOL : 0); LF_SET((init_flags & DB_INITENV_TXN) ? DB_INIT_TXN : 0); if (LF_ISSET(DB_INITENV_CDB_ALLDB) && (ret = dbenv->set_flags(dbenv, DB_CDB_ALLDB, 1)) != 0) goto err; } /* Initialize for CDB product. */ if (LF_ISSET(DB_INIT_CDB)) { LF_SET(DB_INIT_LOCK); F_SET(dbenv, DB_ENV_CDB); } /* * Initialize the subsystems. Transactions imply logging but do not * imply locking. While almost all applications want both locking * and logging, it would not be unreasonable for a single threaded * process to want transactions for atomicity guarantees, but not * necessarily need concurrency. */ if (LF_ISSET(DB_INIT_MPOOL)) if ((ret = __memp_open(dbenv)) != 0) goto err;#ifdef HAVE_CRYPTO /* * Initialize the ciphering area prior to any running of recovery so * that we can initialize the keys, etc. before recovery. * * !!! * This must be after the mpool init, but before the log initialization * because log_open may attempt to run log_recover during its open. */ if ((ret = __crypto_region_init(dbenv)) != 0) goto err;#endif if (LF_ISSET(DB_INIT_LOG | DB_INIT_TXN)) if ((ret = __log_open(dbenv)) != 0) goto err; if (LF_ISSET(DB_INIT_LOCK)) if ((ret = __lock_open(dbenv)) != 0) goto err; if (LF_ISSET(DB_INIT_TXN)) { if ((ret = __txn_open(dbenv)) != 0) goto err; /* * If the application is running with transactions, initialize * the function tables. */ if ((ret = __bam_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __crdel_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __db_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __dbreg_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __fop_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __ham_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __qam_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; if ((ret = __txn_init_recover(dbenv, &dbenv->recover_dtab, &dbenv->recover_dtab_size)) != 0) goto err; /* Perform recovery for any previous run. */ if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) && (ret = __db_apprec(dbenv, NULL, LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0) goto err; } /* Initialize the replication area just in case. */ if ((ret = __rep_region_init(dbenv)) != 0) goto err; /* * Initialize the DB list, and its mutex as necessary. If the env * handle isn't free-threaded we don't need a mutex because there * will never be more than a single DB handle on the list. If the * mpool wasn't initialized, then we can't ever open a DB handle. * * We also need to initialize the MT mutex as necessary, so do them * both. If we error, __dbenv_refresh() will clean up. * * !!! * This must come after the __memp_open call above because if we are * recording mutexes for system resources, we will do it in the mpool * region for environments and db handles. So, the mpool region must * already be initialized. */ LIST_INIT(&dbenv->dblist); if (F_ISSET(dbenv, DB_ENV_THREAD) && LF_ISSET(DB_INIT_MPOOL)) { dbmp = dbenv->mp_handle; if ((ret = __db_mutex_setup( dbenv, dbmp->reginfo, &dbenv->dblist_mutexp, MUTEX_ALLOC | MUTEX_THREAD)) != 0) goto err; if ((ret = __db_mutex_setup( dbenv, dbmp->reginfo, &dbenv->mt_mutexp, MUTEX_ALLOC | MUTEX_THREAD)) != 0) goto err; } /* * If we've created the regions, are running with transactions, and did * not just run recovery, we need to log the fact that the transaction * IDs got reset. * * If we ran recovery, there may be prepared-but-not-yet-committed * transactions that need to be resolved. Recovery resets the minimum * transaction ID and logs the reset if that's appropriate, so we * don't need to do anything here in the recover case. */ if (TXN_ON(dbenv) && F_ISSET((REGINFO *)dbenv->reginfo, REGION_CREATE) && !LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) && (ret = __txn_reset(dbenv)) != 0) goto err; return (0);err: /* If we fail after creating the regions, remove them. */ if (dbenv->reginfo != NULL && F_ISSET((REGINFO *)dbenv->reginfo, REGION_CREATE)) { ret = __db_panic(dbenv, ret); (void)__dbenv_refresh(dbenv, orig_flags); (void)__dbenv_iremove(dbenv, db_home, DB_FORCE); } (void)__dbenv_refresh(dbenv, orig_flags); return (ret);}/* * __dbenv_remove -- * Discard an environment. * * PUBLIC: int __dbenv_remove __P((DB_ENV *, const char *, u_int32_t)); */int__dbenv_remove(dbenv, db_home, flags) DB_ENV *dbenv; const char *db_home; u_int32_t flags;{ int ret, t_ret; ret = __dbenv_iremove(dbenv, db_home, flags); if ((t_ret = dbenv->close(dbenv, 0)) != 0 && ret == 0) ret = t_ret; return (ret);}/* * __dbenv_iremove -- * Discard an environment, internal version. */static int__dbenv_iremove(dbenv, db_home, flags) DB_ENV *dbenv; const char *db_home; u_int32_t flags;{ int ret;#undef OKFLAGS#define OKFLAGS \ DB_FORCE | DB_USE_ENVIRON | DB_USE_ENVIRON_ROOT /* Validate arguments. */ if ((ret = __db_fchk(dbenv, "DB_ENV->remove", flags, OKFLAGS)) != 0) return (ret); ENV_ILLEGAL_AFTER_OPEN(dbenv, "DB_ENV->remove"); /* Initialize the DB_ENV structure. */ if ((ret = __dbenv_config(dbenv, db_home, flags)) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -