📄 fop_util.c
字号:
ret = EEXIST; goto err; } goto done; } /* File does not exist. */ if (!LF_ISSET(DB_CREATE)) goto err; ret = 0; /* * We need to create file, which means that we need to set up the file, * the fileid and the locks. Then we need to call the appropriate * routines to create meta-data pages. */ if ((ret = __ENV_LPUT(dbenv, elock, 0)) != 0) goto err;create: if (txn != NULL && IS_REP_CLIENT(dbenv)) { __db_err(dbenv, "Transactional create on replication client disallowed"); ret = EINVAL; goto err; } if ((ret = __db_backup_name(dbenv, name, txn, &tmpname)) != 0) goto err; if (TXN_ON(dbenv) && txn != NULL && (ret = __txn_begin(dbenv, txn, &stxn, 0)) != 0) goto err; if ((ret = __fop_create(dbenv, stxn, &fhp, tmpname, DB_APP_DATA, mode, dflags)) != 0) { /* * If we don't have transactions there is a race on * creating the temp file. */ if (!TXN_ON(dbenv) && ret == EEXIST) { __os_free(dbenv, tmpname); tmpname = NULL; __os_yield(dbenv, 1); goto retry; } goto err; } tmp_created = 1;creat2: if ((ret = __db_appname(dbenv, DB_APP_DATA, tmpname, 0, NULL, &real_tmpname)) != 0) goto err; /* Set the pagesize if it isn't yet set. */ if (dbp->pgsize == 0 && (ret = __fop_set_pgsize(dbp, fhp, real_tmpname)) != 0) goto errmsg; /* Construct a file_id. */ if ((ret = __os_fileid(dbenv, real_tmpname, 1, dbp->fileid)) != 0) goto errmsg; if ((ret = __db_new_file(dbp, stxn, fhp, tmpname)) != 0) goto err; /* * We need to close the handle here on platforms where remove and * rename fail if a handle is open (including Windows). */ CLOSE_HANDLE(dbp, fhp); /* * Now move the file into place unless we are creating in place (because * we created a database in a file that started out 0-length). */ if (!F_ISSET(dbp, DB_AM_COMPENSATE) && !F_ISSET(dbp, DB_AM_RECOVER)) GET_ENVLOCK(dbenv, locker, &elock); if (F_ISSET(dbp, DB_AM_IN_RENAME)) { F_CLR(dbp, DB_AM_IN_RENAME); __txn_remrem(dbenv, txn, real_name); } else if (name == tmpname) { /* We created it in place. */ } else if (__os_exists(real_name, NULL) == 0) { /* * Someone managed to create the file; remove our temp * and try to open the file that now exists. */ (void)__fop_remove(dbenv, NULL, dbp->fileid, tmpname, DB_APP_DATA, dflags); (void)__ENV_LPUT(dbenv, dbp->handle_lock, 0); LOCK_INIT(dbp->handle_lock); if (stxn != NULL) { ret = __txn_abort(stxn); stxn = NULL; } if (ret != 0) goto err; goto reopen; } if ((ret = __fop_lock_handle(dbenv, dbp, locker, DB_LOCK_WRITE, &elock, NOWAIT_FLAG(txn))) != 0) goto err; if (tmpname != name && (ret = __fop_rename(dbenv, stxn, tmpname, name, dbp->fileid, DB_APP_DATA, dflags)) != 0) goto err; if (stxn != NULL) { *retidp = stxn->txnid; ret = __txn_commit(stxn, 0); stxn = NULL; } else *retidp = TXN_INVALID; if (ret != 0) goto err; F_SET(dbp, DB_AM_CREATED); if (0) {errmsg: __db_err(dbenv, "%s: %s", name, db_strerror(ret));err: CLOSE_HANDLE(dbp, fhp); if (stxn != NULL) (void)__txn_abort(stxn); if (tmp_created && txn == NULL) (void)__fop_remove(dbenv, NULL, NULL, tmpname, DB_APP_DATA, dflags); if (txn == NULL) (void)__ENV_LPUT(dbenv, dbp->handle_lock, 0); (void)__ENV_LPUT(dbenv, elock, 0); if (created_locker) { (void)__lock_id_free(dbenv, dbp->lid); dbp->lid = DB_LOCK_INVALIDID; } }done: /* * There are cases where real_name and tmpname take on the * exact same string, so we need to make sure that we do not * free twice. */ if (!truncating && tmpname != NULL && tmpname != name) __os_free(dbenv, tmpname); if (real_name != NULL) __os_free(dbenv, real_name); if (real_tmpname != NULL) __os_free(dbenv, real_tmpname); CLOSE_HANDLE(dbp, fhp); return (ret);}/* * __fop_set_pgsize -- * Set the page size based on file information. */static int__fop_set_pgsize(dbp, fhp, name) DB *dbp; DB_FH *fhp; const char *name;{ DB_ENV *dbenv; u_int32_t iopsize; int ret; dbenv = dbp->dbenv; /* * Use the filesystem's optimum I/O size as the pagesize if a pagesize * not specified. Some filesystems have 64K as their optimum I/O size, * but as that results in fairly large default caches, we limit the * default pagesize to 16K. */ if ((ret = __os_ioinfo(dbenv, name, fhp, NULL, NULL, &iopsize)) != 0) { __db_err(dbenv, "%s: %s", name, db_strerror(ret)); return (ret); } if (iopsize < 512) iopsize = 512; if (iopsize > 16 * 1024) iopsize = 16 * 1024; /* * Sheer paranoia, but we don't want anything that's not a power-of-2 * (we rely on that for alignment of various types on the pages), and * we want a multiple of the sector size as well. If the value * we got out of __os_ioinfo looks bad, use a default instead. */ if (!IS_VALID_PAGESIZE(iopsize)) iopsize = DB_DEF_IOSIZE; dbp->pgsize = iopsize; F_SET(dbp, DB_AM_PGDEF); return (0);}/* * __fop_subdb_setup -- * * Subdb setup is significantly simpler than file setup. In terms of * locking, for the duration of the operation/transaction, the locks on * the meta-data page will suffice to protect us from simultaneous operations * on the sub-database. Before we complete the operation though, we'll get a * handle lock on the subdatabase so that on one else can try to remove it * while we've got it open. We use an object that looks like the meta-data * page lock with a different type (DB_HANDLE_LOCK) for the long-term handle. * locks. * * PUBLIC: int __fop_subdb_setup __P((DB *, DB_TXN *, * PUBLIC: const char *, const char *, int, u_int32_t)); */int__fop_subdb_setup(dbp, txn, mname, name, mode, flags) DB *dbp; DB_TXN *txn; const char *mname, *name; int mode; u_int32_t flags;{ DB *mdbp; DB_ENV *dbenv; db_lockmode_t lkmode; int ret, t_ret; mdbp = NULL; dbenv = dbp->dbenv; if ((ret = __db_master_open(dbp, txn, mname, flags, mode, &mdbp)) != 0) return (ret); /* * If we created this file, then we need to set the DISCARD flag so * that if we fail in the middle of this routine, we discard from the * mpool any pages that we just created. */ if (F_ISSET(mdbp, DB_AM_CREATED)) F_SET(mdbp, DB_AM_DISCARD); /* * We are going to close this instance of the master, so we can * steal its handle instead of reopening a handle on the database. */ if (LF_ISSET(DB_FCNTL_LOCKING)) { dbp->saved_open_fhp = mdbp->saved_open_fhp; mdbp->saved_open_fhp = NULL; } /* Copy the pagesize and set the sub-database flag. */ dbp->pgsize = mdbp->pgsize; F_SET(dbp, DB_AM_SUBDB); if (name != NULL && (ret = __db_master_update(mdbp, dbp, txn, name, dbp->type, MU_OPEN, NULL, flags)) != 0) goto err; /* * Hijack the master's locker ID as well, so that our locks don't * conflict with the master's. Since we're closing the master, * that lid would just have been freed anyway. Once we've gotten * the locker id, we need to acquire the handle lock for this * subdatabase. */ dbp->lid = mdbp->lid; mdbp->lid = DB_LOCK_INVALIDID; DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, mname); /* * We copy our fileid from our master so that we all open * the same file in mpool. We'll use the meta-pgno to lock * so that we end up with different handle locks. */ memcpy(dbp->fileid, mdbp->fileid, DB_FILE_ID_LEN); lkmode = F_ISSET(dbp, DB_AM_CREATED) || LF_ISSET(DB_WRITEOPEN) ? DB_LOCK_WRITE : DB_LOCK_READ; if ((ret = __fop_lock_handle(dbenv, dbp, txn == NULL ? dbp->lid : txn->txnid, lkmode, NULL, NOWAIT_FLAG(txn))) != 0) goto err; if ((ret = __db_init_subdb(mdbp, dbp, name, txn)) != 0) { /* * If there was no transaction and we created this database, * then we need to undo the update of the master database. */ if (F_ISSET(dbp, DB_AM_CREATED) && txn != NULL) (void)__db_master_update(mdbp, dbp, txn, name, dbp->type, MU_REMOVE, NULL, 0); F_CLR(dbp, DB_AM_CREATED); goto err; } /* * XXX * This should have been done at the top of this routine. The problem * is that __db_init_subdb() uses "standard" routines to process the * meta-data page and set information in the DB handle based on it. * Those routines have to deal with swapped pages and will normally set * the DB_AM_SWAP flag. However, we use the master's metadata page and * that has already been swapped, so they get the is-swapped test wrong. */ F_CLR(dbp, DB_AM_SWAP); F_SET(dbp, F_ISSET(mdbp, DB_AM_SWAP)); /* * In the file create case, these happen in separate places so we have * two different tests. They end up in the same place for subdbs, but * for compatibility with file testing, we put them both here anyway. */ DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, mname); DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, mname); /* * File exists and we have the appropriate locks; we should now * process a normal open. */ if (F_ISSET(mdbp, DB_AM_CREATED)) { F_SET(dbp, DB_AM_CREATED_MSTR); F_CLR(mdbp, DB_AM_DISCARD); } if (0) {err:DB_TEST_RECOVERY_LABEL if (txn == NULL) (void)__ENV_LPUT(dbenv, dbp->handle_lock, 0); } /* * The master's handle lock is under the control of the * subdb (it acquired the master's locker). We want to * keep the master's handle lock so that no one can remove * the file while the subdb is open. If we register the * trade event and then invalidate the copy of the lock * in the master's handle, that will accomplish this. However, * before we register this event, we'd better remove any * events that we've already registered for the master. */ if (!F_ISSET(dbp, DB_AM_RECOVER) && txn != NULL) { /* Unregister old master events. */ __txn_remlock(dbenv, txn, &mdbp->handle_lock, DB_LOCK_INVALIDID); /* Now register the new event. */ if ((t_ret = __txn_lockevent(dbenv, txn, dbp, &mdbp->handle_lock, dbp->lid == DB_LOCK_INVALIDID ? mdbp->lid : dbp->lid)) != 0 && ret == 0) ret = t_ret; } LOCK_INIT(mdbp->handle_lock); /* * If the master was created, we need to sync so that the metadata * page is correct on disk for recovery, since it isn't read through * mpool. If we're opening a subdb in an existing file, we can skip * the sync. */ if ((t_ret =__db_close(mdbp, txn, F_ISSET(dbp, DB_AM_CREATED_MSTR) ? 0 : DB_NOSYNC)) != 0 && ret == 0) ret = t_ret; return (ret);}/* * __fop_remove_setup -- * Open handle appropriately and lock for removal of a database file. * * PUBLIC: int __fop_remove_setup __P((DB *, * PUBLIC: DB_TXN *, const char *, u_int32_t)); */int__fop_remove_setup(dbp, txn, name, flags) DB *dbp; DB_TXN *txn; const char *name; u_int32_t flags;{ DB_ENV *dbenv; DB_FH *fhp; DB_LOCK elock; u_int32_t refcnt; u_int8_t mbuf[DBMETASIZE]; int ret; COMPQUIET(flags, 0); dbenv = dbp->dbenv; PANIC_CHECK(dbenv); LOCK_INIT(elock); fhp = NULL; /* Create locker if necessary. */retry: if (LOCKING_ON(dbenv)) { if (txn != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -