📄 fop_util.c
字号:
/* * 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; int do_remove, ret; mdbp = NULL; dbenv = dbp->dbenv; if ((ret = __db_master_open(dbp, txn, mname, flags, mode, &mdbp)) != 0) return (ret); /* * 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; } /* Now copy the pagesize. */ 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); if ((ret = __fop_lock_handle(dbenv, dbp, txn == NULL ? dbp->lid : txn->txnid, F_ISSET(dbp, DB_AM_CREATED) || LF_ISSET(DB_WRITEOPEN) ? DB_LOCK_WRITE : DB_LOCK_READ, NULL, 0)) != 0) goto err; if ((ret = __db_init_subdb(mdbp, dbp, name, txn)) != 0) goto err; /* * 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); } /* * 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 ((ret = __txn_lockevent(dbenv, txn, dbp, &mdbp->handle_lock, dbp->lid)) != 0) goto err; } LOCK_INIT(mdbp->handle_lock); return (__db_close_i(mdbp, txn, 0));err:DB_TEST_RECOVERY_LABEL if (LOCK_ISSET(dbp->handle_lock) && txn == NULL) __lock_put(dbenv, &dbp->handle_lock); /* If we created the master file then we need to remove it. */ if (mdbp != NULL) { do_remove = F_ISSET(mdbp, DB_AM_CREATED) ? 1 : 0; if (do_remove) F_SET(mdbp, DB_AM_DISCARD); (void)__db_close_i(mdbp, txn, 0); if (do_remove) { (void)db_create(&mdbp, dbp->dbenv, 0); (void)__db_remove_i(mdbp, txn, mname, NULL); } } 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_LOCK elock; u_int8_t mbuf[DBMETASIZE]; int ret; COMPQUIET(flags, 0); dbenv = dbp->dbenv; PANIC_CHECK(dbenv); LOCK_INIT(elock); /* Create locker if necessary. */ if (LOCKING_ON(dbenv)) { if (txn != NULL) dbp->lid = txn->txnid; else if (dbp->lid == DB_LOCK_INVALIDID) { if ((ret = __lock_id(dbenv, &dbp->lid)) != 0) goto err; } } /* * Lock environment to protect file open. That will enable us to * read the meta-data page and get the fileid so that we can lock * the handle. */ GET_ENVLOCK(dbenv, dbp->lid, &elock); if ((ret = __fop_read_meta(dbenv, name, mbuf, sizeof(mbuf), NULL, 0, 0)) != 0) goto err; if ((ret = __db_meta_setup(dbenv, dbp, name, (DBMETA *)mbuf, flags, 1)) != 0) goto err; /* Now, release the environment and get the handle lock. */ if ((ret = __fop_lock_handle(dbenv, dbp, dbp->lid, DB_LOCK_WRITE, &elock, 0)) != 0) goto err; return (0);err: (void)REL_ENVLOCK(dbenv, &elock); return (ret);}/* * __fop_read_meta -- * Read the meta-data page from a file and return it in buf. The * open file handle is returned in fhp. * * PUBLIC: int __fop_read_meta __P((DB_ENV *, * PUBLIC: const char *, u_int8_t *, size_t, DB_FH *, int, u_int32_t)); */int__fop_read_meta(dbenv, name, buf, size, fhp, errok, flags) DB_ENV *dbenv; const char *name; u_int8_t *buf; size_t size; DB_FH *fhp; int errok; u_int32_t flags;{ DB_FH fh, *lfhp; size_t nr; int ret; lfhp = fhp == NULL ? &fh : fhp; memset(lfhp, 0, sizeof(*fhp)); if ((ret = __os_open(dbenv, name, flags, 0, lfhp)) != 0) goto err; if ((ret = __os_read(dbenv, lfhp, buf, size, &nr)) != 0) { if (!errok) __db_err(dbenv, "%s: %s", name, db_strerror(ret)); goto err; } if (nr != size) { if (!errok) __db_err(dbenv, "%s: unexpected file type or format", name); ret = EINVAL; goto err; }err: /* * On error, we always close the handle. If there is no error, * then we only return the handle if the user didn't pass us * a handle into which to return it. If fhp is valid, then * lfhp is the same as fhp. */ if (F_ISSET(lfhp, DB_FH_VALID) && (ret != 0 || fhp == NULL)) __os_closehandle(dbenv, lfhp); return (ret);}/* * __fop_dummy -- * This implements the creation and name swapping of dummy files that * we use for remove and rename (remove is simply a rename with a delayed * remove). * * PUBLIC: int __fop_dummy __P((DB *, * PUBLIC: DB_TXN *, const char *, const char *, u_int32_t)); */int__fop_dummy(dbp, txn, old, new, flags) DB *dbp; DB_TXN *txn; const char *old, *new; u_int32_t flags;{ DB *tmpdbp; DB_ENV *dbenv; DB_LOCK elock; DB_LSN lsn; DBT fiddbt, namedbt, tmpdbt; DB_TXN *stxn; char *back; char *realback, *realnew, *realold; int ret, t_ret; u_int8_t mbuf[DBMETASIZE]; u_int32_t locker, stxnid; dbenv = dbp->dbenv; LOCK_INIT(elock); realback = NULL; realnew = NULL; realold = NULL; back = NULL; stxn = NULL; tmpdbp = NULL; DB_ASSERT(txn != NULL); locker = txn->txnid; /* Begin sub transaction to encapsulate the rename. */ if (TXN_ON(dbenv) && (ret = dbenv->txn_begin(dbenv, txn, &stxn, 0)) != 0) goto err; /* We need to create a dummy file as a place holder. */ if ((ret = __db_backup_name(dbenv, new, stxn, &back)) != 0) goto err; if ((ret = __db_appname(dbenv, DB_APP_DATA, back, flags, NULL, &realback)) != 0) goto err; if ((ret = __fop_create(dbenv, stxn, NULL, back, DB_APP_DATA, 0)) != 0) goto err; memset(mbuf, 0, sizeof(mbuf)); if ((ret = __os_fileid(dbenv, realback, 1, ((DBMETA *)mbuf)->uid)) != 0) goto err; ((DBMETA *)mbuf)->magic = DB_RENAMEMAGIC; if ((ret = __fop_write(dbenv, stxn, back, DB_APP_DATA, NULL, 0, mbuf, DBMETASIZE, 1)) != 0) goto err; /* Create a dummy dbp handle. */ if ((ret = db_create(&tmpdbp, dbenv, 0)) != 0) goto err; memcpy(&tmpdbp->fileid, ((DBMETA *)mbuf)->uid, DB_FILE_ID_LEN); /* Now, lock the name space while we initialize this file. */ if ((ret = __db_appname(dbenv, DB_APP_DATA, new, 0, NULL, &realnew)) != 0) goto err; GET_ENVLOCK(dbenv, locker, &elock); if (__os_exists(realnew, NULL) == 0) { ret = EEXIST; goto err; } /* * While we have the namespace locked, do the renames and then * swap for the handle lock. */ if ((ret = __fop_rename(dbenv, stxn, old, new, dbp->fileid, DB_APP_DATA)) != 0) goto err; if ((ret = __fop_rename(dbenv, stxn, back, old, tmpdbp->fileid, DB_APP_DATA)) != 0) goto err; if ((ret = __fop_lock_handle(dbenv, tmpdbp, locker, DB_LOCK_WRITE, &elock, 0)) != 0) goto err; /* * We just acquired a transactional lock on the tmp handle. * We need to null out the tmp handle's lock so that it * doesn't create problems for us in the close path. */ LOCK_INIT(tmpdbp->handle_lock); if (stxn != NULL) { /* Commit the child. */ stxnid = stxn->txnid; ret = stxn->commit(stxn, 0); stxn = NULL; /* Now log the child information in the parent. */ memset(&fiddbt, 0, sizeof(fiddbt)); memset(&tmpdbt, 0, sizeof(fiddbt)); memset(&namedbt, 0, sizeof(namedbt)); fiddbt.data = dbp->fileid; fiddbt.size = DB_FILE_ID_LEN; tmpdbt.data = tmpdbp->fileid; tmpdbt.size = DB_FILE_ID_LEN; namedbt.data = (void *)old; namedbt.size = (u_int32_t)strlen(old) + 1; if ((t_ret = __fop_file_remove_log(dbenv, txn, &lsn, 0, &fiddbt, &tmpdbt, &namedbt, DB_APP_DATA, stxnid)) != 0 && ret == 0) ret = t_ret; } /* This is a delayed delete of the dummy file. */ if ((ret = __db_appname(dbenv, DB_APP_DATA, old, flags, NULL, &realold)) != 0) goto err; if ((ret = __txn_remevent(dbenv, txn, realold, NULL)) != 0) goto err;err: (void)REL_ENVLOCK(dbenv, &elock); if (stxn != NULL) (void)stxn->abort(stxn); if (tmpdbp != NULL && (t_ret = __db_close_i(tmpdbp, NULL, 0)) != 0 && ret == 0) ret = t_ret; if (realold != NULL) __os_free(dbenv, realold); if (realnew != NULL) __os_free(dbenv, realnew); if (realback != NULL) __os_free(dbenv, realback); if (back != NULL) __os_free(dbenv, back); return (ret);}/* * __fop_dbrename -- * Do the appropriate file locking and file system operations * to effect a dbrename in the absence of transactions (__fop_dummy * and the subsequent calls in __db_rename do the work for the * transactional case). * * PUBLIC: int __fop_dbrename __P((DB *, const char *, const char *)); */int__fop_dbrename(dbp, old, new) DB *dbp; const char *old, *new;{ DB_ENV *dbenv; DB_LOCK elock; char *real_new, *real_old; int ret, tret; dbenv = dbp->dbenv; real_new = NULL; real_old = NULL; LOCK_INIT(elock); /* Find the real newname of the file. */ if ((ret = __db_appname(dbenv, DB_APP_DATA, new, 0, NULL, &real_new)) != 0) goto err; /* * It is an error to rename a file over one that already exists, * as that wouldn't be transaction-safe. */ GET_ENVLOCK(dbenv, dbp->lid, &elock); if (__os_exists(real_new, NULL) == 0) { ret = EEXIST; __db_err(dbenv, "rename: file %s exists", real_new); goto err; } if ((ret = __db_appname(dbenv, DB_APP_DATA, old, 0, NULL, &real_old)) != 0) goto err; ret = dbenv->memp_nameop(dbenv, dbp->fileid, new, real_old, real_new);err: if ((tret = REL_ENVLOCK(dbenv, &elock)) != 0 && ret == 0) ret = tret; if (real_old != NULL) __os_free(dbenv, real_old); if (real_new != NULL) __os_free(dbenv, real_new); return (ret);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -