📄 fop_util.c
字号:
dbp->lid = txn->txnid; else if (dbp->lid == DB_LOCK_INVALIDID) { if ((ret = __lock_id(dbenv, &dbp->lid)) != 0) goto err; } } /* * We are about to open a file handle and then possibly close it. * We cannot close handles if we are doing FCNTL locking. However, * there is no way to pass the FCNTL flag into this routine via the * user API. The only way we can get in here and be doing FCNTL * locking is if we are trying to clean up an open that was called * with FCNTL locking. In that case, the save_fhp should already be * set. So, we use that field to tell us if we need to make sure * that we shouldn't close the handle. */ fhp = dbp->saved_open_fhp; DB_ASSERT(LF_ISSET(DB_FCNTL_LOCKING) || fhp == NULL); /* * 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 (fhp == NULL && (ret = __os_open(dbenv, name, DB_OSO_RDONLY, 0, &fhp)) != 0) goto err; if ((ret = __fop_read_meta(dbenv, name, mbuf, sizeof(mbuf), fhp, 0, NULL)) != 0) goto err; if ((ret = __db_meta_setup(dbenv, dbp, name, (DBMETA *)mbuf, flags, 1)) != 0) goto err; /* * Now, get the handle lock. We first try with NOWAIT, because if * we have to wait, we're going to have to close the file and reopen * it, so that if there is someone else removing it, our open doesn't * prevent that. */ if ((ret = __fop_lock_handle(dbenv, dbp, dbp->lid, DB_LOCK_WRITE, NULL, DB_LOCK_NOWAIT)) != 0) { /* * Close the file, block on the lock, clean up the dbp, and * then start all over again. */ if (!LF_ISSET(DB_FCNTL_LOCKING)) { (void)__os_closehandle(dbenv, fhp); fhp = NULL; } if (ret == DB_LOCK_NOTEXIST) { if ((ret = __ENV_LPUT(dbenv, elock, 0)) != 0) goto err; } else if (ret != DB_LOCK_NOTGRANTED || (txn != NULL && F_ISSET(txn, TXN_NOWAIT))) goto err; else if ((ret = __fop_lock_handle(dbenv, dbp, dbp->lid, DB_LOCK_WRITE, &elock, 0)) != 0 && ret != DB_LOCK_NOTEXIST) goto err; if (txn != NULL) dbp->lid = DB_LOCK_INVALIDID; (void)__db_refresh(dbp, txn, DB_NOSYNC, NULL); goto retry; } else if ((ret = __ENV_LPUT(dbenv, elock, 0)) != 0) goto err; /* Check if the file is already open. */ if ((ret = __memp_get_refcnt(dbenv, dbp->fileid, &refcnt)) != 0) goto err; /* * Now, error check. If the file is already open (refcnt != 0), then * we must have it open (since we got the lock) and we need to panic, * because this is a self deadlock and the application has a bug. * If the file isn't open, but it's in the midst of a rename then * this file doesn't really exist. */ if (refcnt != 0) { __db_err(dbenv,"Attempting to remove file open in current transaction causing self-deadlock"); ret = __db_panic(dbenv, DB_LOCK_DEADLOCK); } else if (F_ISSET(dbp, DB_AM_IN_RENAME)) ret = ENOENT; if (0) {err: (void)__ENV_LPUT(dbenv, elock, 0); } if (fhp != NULL && !LF_ISSET(DB_FCNTL_LOCKING)) (void)__os_closehandle(dbenv, fhp); /* * If we are going to proceed with the removal, then we need to make * sure that we don't leave any pages around in the mpool. */ if (ret == 0) F_SET(dbp, DB_AM_DISCARD); return (ret);}/* * __fop_read_meta -- * Read the meta-data page from a file and return it in buf. * * PUBLIC: int __fop_read_meta __P((DB_ENV *, const char *, * PUBLIC: u_int8_t *, size_t, DB_FH *, int, size_t *)); */int__fop_read_meta(dbenv, name, buf, size, fhp, errok, nbytesp) DB_ENV *dbenv; const char *name; u_int8_t *buf; size_t size; DB_FH *fhp; int errok; size_t *nbytesp;{ size_t nr; int ret; /* * Our caller wants to know the number of bytes read, even if we * return an error. */ if (nbytesp != NULL) *nbytesp = 0; nr = 0; ret = __os_read(dbenv, fhp, buf, size, &nr); if (nbytesp != NULL) *nbytesp = nr; if (ret != 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; }err: 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, *t2dbp; DB_ENV *dbenv; DB_FH *fhp; DB_LOCK elock; DB_LSN lsn; DBT fiddbt, namedbt, tmpdbt; DB_TXN *stxn; char *back; char *realback, *realnew, *realold; int ret, t_ret; size_t len; u_int8_t mbuf[DBMETASIZE]; u_int32_t dflags, locker, stxnid; dbenv = dbp->dbenv; LOCK_INIT(elock); realback = NULL; realnew = NULL; realold = NULL; back = NULL; stxn = NULL; tmpdbp = t2dbp = NULL; fhp = NULL; dflags = F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0; DB_ASSERT(txn != NULL); locker = txn->txnid; /* Begin sub transaction to encapsulate the rename. */ if (TXN_ON(dbenv) && (ret = __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, dflags)) != 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, 0, 0, mbuf, DBMETASIZE, 1, dflags)) != 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) { /* * It is possible that the only reason this file exists is * because we've done a previous rename of it and we have * left a placeholder here. We need to check for that case * and allow this rename to succeed if that's the case. */ if ((ret = db_create(&t2dbp, dbenv, 0)) != 0) goto err; if ((ret = __os_open(dbenv, realnew, 0, 0, &fhp)) != 0) goto err; if ((ret = __fop_read_meta(dbenv, realnew, mbuf, sizeof(mbuf), fhp, 0, &len)) != 0 || (ret = __db_meta_setup(dbenv, t2dbp, realnew, (DBMETA *)mbuf, 0, 1)) != 0) { ret = EEXIST; goto err; } /* * Now, try to acquire the handle lock. If it's from our txn, * then we'll get the lock. If it's not, then someone else has * it locked, and we need to report this as an error. If we * know we can get the lock, we can immediately release it, * which we need to do since this is a temporary handle. */ if ((ret = __fop_lock_handle(dbenv, t2dbp, locker, DB_LOCK_WRITE, NULL, DB_LOCK_NOWAIT)) != 0) ret = EEXIST; else { (void)__lock_put(dbenv, &t2dbp->handle_lock, 0); if (!F_ISSET(t2dbp, DB_AM_IN_RENAME)) ret = EEXIST; } if ((t_ret = __os_closehandle(dbenv, fhp)) != 0 && ret == 0) ret = t_ret; fhp = NULL; if (ret != 0) 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, dflags)) != 0) goto err; if ((ret = __fop_rename(dbenv, stxn, back, old, tmpdbp->fileid, DB_APP_DATA, dflags)) != 0) goto err; if ((ret = __fop_lock_handle(dbenv, tmpdbp, locker, DB_LOCK_WRITE, &elock, NOWAIT_FLAG(txn))) != 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 = __txn_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)__ENV_LPUT(dbenv, elock, 0); if (stxn != NULL) (void)__txn_abort(stxn); if (tmpdbp != NULL && (t_ret = __db_close(tmpdbp, NULL, 0)) != 0 && ret == 0) ret = t_ret; if (t2dbp != NULL && (t_ret = __db_close(t2dbp, NULL, 0)) != 0 && ret == 0) ret = t_ret; if (fhp != NULL) (void)__os_closehandle(dbenv, fhp); 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, t_ret; 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 = __memp_nameop(dbenv, dbp->fileid, new, real_old, real_new);err: if ((t_ret = __ENV_LPUT(dbenv, elock, 0)) != 0 && ret == 0) ret = t_ret; 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 + -