fop_util.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 2001-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: fop_util.c,v 1.52 2002/09/10 02:41:42 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stddef.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "dbinc/db_page.h"
  19. #include "dbinc/db_shash.h"
  20. #include "dbinc/db_am.h"
  21. #include "dbinc/fop.h"
  22. #include "dbinc/lock.h"
  23. #include "dbinc/log.h"
  24. #include "dbinc/txn.h"
  25. static int __fop_set_pgsize __P((DB *, DB_FH *, const char *));
  26. /*
  27.  * Acquire the environment meta-data lock.  The parameters are the
  28.  * environment (ENV), the locker id to use in acquiring the lock (ID)
  29.  * and a pointer to a DB_LOCK.
  30.  */
  31. #define GET_ENVLOCK(ENV, ID, L) do {
  32. DBT __dbt;
  33. u_int32_t __lockval;
  34. if (LOCKING_ON((ENV))) {
  35. __lockval = 0;
  36. __dbt.data = &__lockval;
  37. __dbt.size = sizeof(__lockval);
  38. if ((ret = (ENV)->lock_get((ENV), (ID),
  39.     0, &__dbt, DB_LOCK_WRITE, (L))) != 0)
  40. goto err;
  41. }
  42. } while (0)
  43. #define REL_ENVLOCK(ENV, L)
  44. (!LOCK_ISSET(*(L)) ? 0 : (ENV)->lock_put((ENV), (L)))
  45. /*
  46.  * If our caller is doing fcntl(2) locking, then we can't close it
  47.  * because that would discard the caller's lock.  Otherwise, close
  48.  * the handle.
  49.  */
  50. #define CLOSE_HANDLE(D, F) {
  51. if (F_ISSET((F), DB_FH_VALID)) {
  52. if (LF_ISSET(DB_FCNTL_LOCKING))
  53. (D)->saved_open_fhp = (F);
  54. else if ((ret = __os_closehandle((D)->dbenv,(F))) != 0)
  55. goto err;
  56. }
  57. }
  58. /*
  59.  * __fop_lock_handle --
  60.  *
  61.  * Get the handle lock for a database.  If the envlock is specified,
  62.  * do this as a lock_vec call that releases the enviroment lock before
  63.  * acquiring the handle lock.
  64.  *
  65.  * PUBLIC: int __fop_lock_handle __P((DB_ENV *,
  66.  * PUBLIC:     DB *, u_int32_t, db_lockmode_t, DB_LOCK *, u_int32_t));
  67.  *
  68.  */
  69. int
  70. __fop_lock_handle(dbenv, dbp, locker, mode, elock, flags)
  71. DB_ENV *dbenv;
  72. DB *dbp;
  73. u_int32_t locker;
  74. db_lockmode_t mode;
  75. DB_LOCK *elock;
  76. u_int32_t flags;
  77. {
  78. DBT fileobj;
  79. DB_LOCKREQ reqs[2], *ereq;
  80. DB_LOCK_ILOCK lock_desc;
  81. int ret;
  82. if (!LOCKING_ON(dbenv) || F_ISSET(dbp, DB_AM_COMPENSATE))
  83. return (0);
  84. /*
  85.  * If we are in recovery, the only locking we should be
  86.  * doing is on the global environment.
  87.  */
  88. if (IS_RECOVERING(dbenv)) {
  89. if (elock != NULL)
  90. REL_ENVLOCK(dbenv, elock);
  91. return (0);
  92. }
  93. memcpy(&lock_desc.fileid, &dbp->fileid, DB_FILE_ID_LEN);
  94. lock_desc.pgno = dbp->meta_pgno;
  95. lock_desc.type = DB_HANDLE_LOCK;
  96. memset(&fileobj, 0, sizeof(fileobj));
  97. fileobj.data = &lock_desc;
  98. fileobj.size = sizeof(lock_desc);
  99. DB_TEST_SUBLOCKS(dbenv, flags);
  100. if (elock == NULL)
  101. ret = dbenv->lock_get(dbenv, locker,
  102.     flags, &fileobj, mode, &dbp->handle_lock);
  103. else {
  104. reqs[0].op = DB_LOCK_PUT;
  105. reqs[0].lock = *elock;
  106. reqs[1].op = DB_LOCK_GET;
  107. reqs[1].mode = mode;
  108. reqs[1].obj = &fileobj;
  109. reqs[1].timeout = 0;
  110. if ((ret = __lock_vec(dbenv,
  111.     locker, flags, reqs, 2, &ereq)) == 0) {
  112. dbp->handle_lock = reqs[1].lock;
  113. LOCK_INIT(*elock);
  114. } else if (ereq != reqs)
  115. LOCK_INIT(*elock);
  116. }
  117. dbp->cur_lid = locker;
  118. return (ret);
  119. }
  120. /*
  121.  * __fop_file_setup --
  122.  *
  123.  * Perform all the needed checking and locking to open up or create a
  124.  * file.
  125.  *
  126.  * There's a reason we don't push this code down into the buffer cache.
  127.  * The problem is that there's no information external to the file that
  128.  * we can use as a unique ID.  UNIX has dev/inode pairs, but they are
  129.  * not necessarily unique after reboot, if the file was mounted via NFS.
  130.  * Windows has similar problems, as the FAT filesystem doesn't maintain
  131.  * dev/inode numbers across reboot.  So, we must get something from the
  132.  * file we can use to ensure that, even after a reboot, the file we're
  133.  * joining in the cache is the right file for us to join.  The solution
  134.  * we use is to maintain a file ID that's stored in the database, and
  135.  * that's why we have to open and read the file before calling into the
  136.  * buffer cache or obtaining a lock (we use this unique fileid to lock
  137.  * as well as to identify like files in the cache).
  138.  *
  139.  * PUBLIC: int __fop_file_setup __P((DB *,
  140.  * PUBLIC:     DB_TXN *, const char *, int, u_int32_t, u_int32_t *));
  141.  */
  142. int
  143. __fop_file_setup(dbp, txn, name, mode, flags, retidp)
  144. DB *dbp;
  145. DB_TXN *txn;
  146. const char *name;
  147. int mode;
  148. u_int32_t flags, *retidp;
  149. {
  150. DB_ENV *dbenv;
  151. DB_FH fh, *fhp;
  152. DB_LOCK elock, tmp_lock;
  153. DB_TXN *stxn;
  154. db_lockmode_t lmode;
  155. u_int32_t locker, oflags;
  156. u_int8_t mbuf[DBMETASIZE];
  157. int created_fhp, created_locker, ret, tmp_created, truncating;
  158. char *real_name, *real_tmpname, *tmpname;
  159. DB_ASSERT(name != NULL);
  160. *retidp = TXN_INVALID;
  161. dbenv = dbp->dbenv;
  162. LOCK_INIT(elock);
  163. LOCK_INIT(tmp_lock);
  164. stxn = NULL;
  165. created_fhp = created_locker = 0;
  166. real_name = real_tmpname = tmpname = NULL;
  167. tmp_created = truncating = 0;
  168. /*
  169.  * If we open a file handle and our caller is doing fcntl(2) locking,
  170.  * we can't close it because that would discard the caller's lock.
  171.  * Save it until we close the DB handle.
  172.  */
  173. if (LF_ISSET(DB_FCNTL_LOCKING)) {
  174. if ((ret = __os_malloc(dbenv, sizeof(*fhp), &fhp)) != 0)
  175. return (ret);
  176. created_fhp = 1;
  177. } else
  178. fhp = &fh;
  179. memset(fhp, 0, sizeof(*fhp));
  180. /*
  181.  * Get a lockerid for this handle.  There are paths through queue
  182.  * rename and remove where this dbp already has a locker, so make
  183.  * sure we don't clobber it and conflict.
  184.  */
  185. if (LOCKING_ON(dbenv) &&
  186.     !F_ISSET(dbp, DB_AM_COMPENSATE) && dbp->lid == DB_LOCK_INVALIDID) {
  187. if ((ret = __lock_id(dbenv, &dbp->lid)) != 0)
  188. goto err;
  189. created_locker = 1;
  190. }
  191. locker = txn == NULL ? dbp->lid : txn->txnid;
  192. /* Get the real backing file name. */
  193. if ((ret = __db_appname(dbenv,
  194.     DB_APP_DATA, name, 0, NULL, &real_name)) != 0)
  195. goto err;
  196. /* Fill in the default file mode. */
  197. if (mode == 0)
  198. mode = __db_omode("rwrw--");
  199. oflags = 0;
  200. if (LF_ISSET(DB_RDONLY))
  201. oflags |= DB_OSO_RDONLY;
  202. retry: if (!F_ISSET(dbp, DB_AM_COMPENSATE))
  203. GET_ENVLOCK(dbenv, locker, &elock);
  204. if ((ret = __os_exists(real_name, NULL)) == 0) {
  205. if (LF_ISSET(DB_EXCL)) {
  206. ret = EEXIST;
  207. goto err;
  208. }
  209. reopen: if ((ret = __fop_read_meta(dbenv, real_name,
  210.     mbuf, sizeof(mbuf), fhp, 0, oflags)) != 0)
  211. goto err;
  212. if ((ret = __db_meta_setup(dbenv,
  213.     dbp, real_name, (DBMETA *)mbuf, flags, 1)) != 0)
  214. goto err;
  215. /* Now, get our handle lock. */
  216. lmode = LF_ISSET(DB_TRUNCATE) ? DB_LOCK_WRITE : DB_LOCK_READ;
  217. if ((ret = __fop_lock_handle(dbenv,
  218.     dbp, locker, lmode, NULL, DB_LOCK_NOWAIT)) == 0) {
  219. if ((ret = REL_ENVLOCK(dbenv, &elock)) != 0)
  220. goto err;
  221. } else {
  222. /* Someone else has file locked; need to wait. */
  223. if ((ret = __os_closehandle(dbenv, fhp)) != 0)
  224. goto err;
  225. ret = __fop_lock_handle(dbenv,
  226.     dbp, locker, lmode, &elock, 0);
  227. if (ret == DB_LOCK_NOTEXIST)
  228. goto retry;
  229. if (ret != 0)
  230. goto err;
  231. /*
  232.  * XXX I need to convince myself that I don't need
  233.  * to re-read the metadata page here.
  234.  * XXX If you do need to re-read it you'd better
  235.  * decrypt it too...
  236.  */
  237. if ((ret = __os_open(dbenv, real_name, 0, 0, fhp)) != 0)
  238. goto err;
  239. }
  240. /*
  241.  * Check for a truncate which needs to leap over to the
  242.  * create case.
  243.  */
  244. if (LF_ISSET(DB_TRUNCATE)) {
  245. /*
  246.  * Sadly, we need to close and reopen the handle
  247.  * in order to do the actual truncate.  We couldn't
  248.  * do the truncate on the initial open because we
  249.  * needed to read the old file-id in order to lock.
  250.  */
  251. if ((ret = __os_closehandle(dbenv, fhp)) != 0)
  252. goto err;
  253. if ((ret = __os_open(dbenv,
  254.     real_name, DB_OSO_TRUNC, 0, fhp)) != 0)
  255. goto err;
  256. /*
  257.  * This is not-transactional, so we'll do the
  258.  * open/create in-place.
  259.  */
  260. tmp_lock = dbp->handle_lock;
  261. truncating = 1;
  262. tmpname = (char *)name;
  263. goto creat2;
  264. }
  265. /*
  266.  * Check for a file in the midst of a rename
  267.  */
  268. if (F_ISSET(dbp, DB_AM_IN_RENAME)) {
  269. if (LF_ISSET(DB_CREATE)) {
  270. F_CLR(dbp, DB_AM_IN_RENAME);
  271. goto create;
  272. } else {
  273. ret = ENOENT;
  274. goto err;
  275. }
  276. }
  277. CLOSE_HANDLE(dbp, fhp);
  278. goto done;
  279. }
  280. /* File does not exist. */
  281. if (!LF_ISSET(DB_CREATE))
  282. goto err;
  283. ret = 0;
  284. /*
  285.  * Need to create file; we need to set up the file,
  286.  * the fileid and the locks.  Then we need to call
  287.  * the appropriate routines to create meta-data pages.
  288.  */
  289. if ((ret = REL_ENVLOCK(dbenv, &elock)) != 0)
  290. goto err;
  291. create: if ((ret = __db_backup_name(dbenv, name, txn, &tmpname)) != 0)
  292. goto err;
  293. if (TXN_ON(dbenv) && txn != NULL &&
  294.     (ret = dbenv->txn_begin(dbenv, txn, &stxn, 0)) != 0)
  295. goto err;
  296. if ((ret = __fop_create(dbenv,
  297.     stxn, fhp, tmpname, DB_APP_DATA, mode)) != 0)
  298. goto err;
  299. tmp_created = 1;
  300. creat2: if ((ret = __db_appname(dbenv,
  301.     DB_APP_DATA, tmpname, 0, NULL, &real_tmpname)) != 0)
  302. goto err;
  303. /* Set the pagesize if it isn't yet set. */
  304. if (dbp->pgsize == 0 &&
  305.     (ret = __fop_set_pgsize(dbp, fhp, real_tmpname)) != 0)
  306. goto errmsg;
  307. /* Construct a file_id. */
  308. if ((ret = __os_fileid(dbenv, real_tmpname, 1, dbp->fileid)) != 0)
  309. goto errmsg;
  310. if ((ret = __db_new_file(dbp, stxn, fhp, tmpname)) != 0)
  311. goto err;
  312. CLOSE_HANDLE(dbp, fhp);
  313. /* Now move the file into place. */
  314. if (!F_ISSET(dbp, DB_AM_COMPENSATE))
  315. GET_ENVLOCK(dbenv, locker, &elock);
  316. if (!truncating && __os_exists(real_name, NULL) == 0) {
  317. /*
  318.  * Someone managed to create the file; remove our temp
  319.  * and try to open the file that now exists.
  320.  */
  321. (void)__fop_remove(dbenv,
  322.     NULL, dbp->fileid, tmpname, DB_APP_DATA);
  323. if (LOCKING_ON(dbenv))
  324. dbenv->lock_put(dbenv, &dbp->handle_lock);
  325. LOCK_INIT(dbp->handle_lock);
  326. /* If we have a saved handle; close it. */
  327. if (LF_ISSET(DB_FCNTL_LOCKING))
  328. (void)__os_closehandle(dbenv, fhp);
  329. if (stxn != NULL) {
  330. ret = stxn->abort(stxn);
  331. stxn = NULL;
  332. }
  333. if (ret != 0)
  334. goto err;
  335. goto reopen;
  336. }
  337. /* We've successfully created, move the file into place. */
  338. if ((ret = __fop_lock_handle(dbenv,
  339.     dbp, locker, DB_LOCK_WRITE, &elock, 0)) != 0)
  340. goto err;
  341. if (!truncating && (ret = __fop_rename(dbenv,
  342.     stxn, tmpname, name, dbp->fileid, DB_APP_DATA)) != 0)
  343. goto err;
  344. /* If this was a truncate; release lock on the old file. */
  345. if (LOCK_ISSET(tmp_lock) && (ret = __lock_put(dbenv, &tmp_lock)) != 0)
  346. goto err;
  347. if (stxn != NULL) {
  348. *retidp = stxn->txnid;
  349. ret = stxn->commit(stxn, 0);
  350. stxn = NULL;
  351. } else
  352. *retidp = TXN_INVALID;
  353. if (ret != 0)
  354. goto err;
  355. F_SET(dbp, DB_AM_CREATED);
  356. if (0) {
  357. errmsg: __db_err(dbenv, "%s: %s", name, db_strerror(ret));
  358. err: if (stxn != NULL)
  359. (void)stxn->abort(stxn);
  360. if (tmp_created && txn == NULL)
  361. (void)__fop_remove(dbenv,
  362.     NULL, NULL, tmpname, DB_APP_DATA);
  363. if (F_ISSET(fhp, DB_FH_VALID))
  364. (void)__os_closehandle(dbenv, fhp);
  365. if (LOCK_ISSET(tmp_lock))
  366. __lock_put(dbenv, &tmp_lock);
  367. if (LOCK_ISSET(dbp->handle_lock) && txn == NULL)
  368. __lock_put(dbenv, &dbp->handle_lock);
  369. if (LOCK_ISSET(elock))
  370. (void)REL_ENVLOCK(dbenv, &elock);
  371. if (created_locker) {
  372. (void)__lock_id_free(dbenv, dbp->lid);
  373. dbp->lid = DB_LOCK_INVALIDID;
  374. }
  375. if (created_fhp)
  376. __os_free(dbenv, fhp);
  377. }
  378. done: if (!truncating && tmpname != NULL)
  379. __os_free(dbenv, tmpname);
  380. if (real_name != NULL)
  381. __os_free(dbenv, real_name);
  382. if (real_tmpname != NULL)
  383. __os_free(dbenv, real_tmpname);
  384. return (ret);
  385. }
  386. /*
  387.  * __fop_set_pgsize --
  388.  * Set the page size based on file information.
  389.  */
  390. static int
  391. __fop_set_pgsize(dbp, fhp, name)
  392. DB *dbp;
  393. DB_FH *fhp;
  394. const char *name;
  395. {
  396. DB_ENV *dbenv;
  397. u_int32_t iopsize;
  398. int ret;
  399. dbenv = dbp->dbenv;
  400. /*
  401.  * Use the filesystem's optimum I/O size as the pagesize if a pagesize
  402.  * not specified.  Some filesystems have 64K as their optimum I/O size,
  403.  * but as that results in fairly large default caches, we limit the
  404.  * default pagesize to 16K.
  405.  */
  406. if ((ret = __os_ioinfo(dbenv, name, fhp, NULL, NULL, &iopsize)) != 0) {
  407. __db_err(dbenv, "%s: %s", name, db_strerror(ret));
  408. return (ret);
  409. }
  410. if (iopsize < 512)
  411. iopsize = 512;
  412. if (iopsize > 16 * 1024)
  413. iopsize = 16 * 1024;
  414. /*
  415.  * Sheer paranoia, but we don't want anything that's not a power-of-2
  416.  * (we rely on that for alignment of various types on the pages), and
  417.  * we want a multiple of the sector size as well.  If the value
  418.  * we got out of __os_ioinfo looks bad, use a default instead.
  419.  */
  420. if (!IS_VALID_PAGESIZE(iopsize))
  421. iopsize = DB_DEF_IOSIZE;
  422. dbp->pgsize = iopsize;
  423. F_SET(dbp, DB_AM_PGDEF);
  424. return (0);
  425. }
  426. /*
  427.  * __fop_subdb_setup --
  428.  *
  429.  * Subdb setup is significantly simpler than file setup.  In terms of
  430.  * locking, for the duration of the operation/transaction, the locks on
  431.  * the meta-data page will suffice to protect us from simultaneous operations
  432.  * on the sub-database.  Before we complete the operation though, we'll get a
  433.  * handle lock on the subdatabase so that on one else can try to remove it
  434.  * while we've got it open.  We use an object that looks like the meta-data
  435.  * page lock with a different type (DB_HANDLE_LOCK) for the long-term handle.
  436.  * locks.
  437.  *
  438.  * PUBLIC: int __fop_subdb_setup __P((DB *, DB_TXN *,
  439.  * PUBLIC:     const char *, const char *, int, u_int32_t));
  440.  */
  441. int
  442. __fop_subdb_setup(dbp, txn, mname, name, mode, flags)
  443. DB *dbp;
  444. DB_TXN *txn;
  445. const char *mname, *name;
  446. int mode;
  447. u_int32_t flags;
  448. {
  449. DB *mdbp;
  450. DB_ENV *dbenv;
  451. int do_remove, ret;
  452. mdbp = NULL;
  453. dbenv = dbp->dbenv;
  454. if ((ret = __db_master_open(dbp, txn, mname, flags, mode, &mdbp)) != 0)
  455. return (ret);
  456. /*
  457.  * We are going to close this instance of the master, so we can
  458.  * steal its handle instead of reopening a handle on the database.
  459.  */
  460. if (LF_ISSET(DB_FCNTL_LOCKING)) {
  461. dbp->saved_open_fhp = mdbp->saved_open_fhp;
  462. mdbp->saved_open_fhp = NULL;
  463. }
  464. /* Now copy the pagesize. */
  465. dbp->pgsize = mdbp->pgsize;
  466. F_SET(dbp, DB_AM_SUBDB);
  467. if (name != NULL && (ret = __db_master_update(mdbp, dbp, txn,
  468.     name, dbp->type, MU_OPEN, NULL, flags)) != 0)
  469. goto err;
  470. /*
  471.  * Hijack the master's locker ID as well, so that our locks don't
  472.  * conflict with the master's.  Since we're closing the master,
  473.  * that lid would just have been freed anyway.  Once we've gotten
  474.  * the locker id, we need to acquire the handle lock for this
  475.  * subdatabase.
  476.  */
  477. dbp->lid = mdbp->lid;
  478. mdbp->lid = DB_LOCK_INVALIDID;
  479. DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOG, ret, mname);
  480. /*
  481.  * We copy our fileid from our master so that we all open
  482.  * the same file in mpool.  We'll use the meta-pgno to lock
  483.  * so that we end up with different handle locks.
  484.  */
  485. memcpy(dbp->fileid, mdbp->fileid, DB_FILE_ID_LEN);
  486. if ((ret = __fop_lock_handle(dbenv, dbp,
  487.     txn == NULL ? dbp->lid : txn->txnid,
  488.     F_ISSET(dbp, DB_AM_CREATED) || LF_ISSET(DB_WRITEOPEN) ?
  489.     DB_LOCK_WRITE : DB_LOCK_READ, NULL, 0)) != 0)
  490. goto err;
  491. if ((ret = __db_init_subdb(mdbp, dbp, name, txn)) != 0)
  492. goto err;
  493. /*
  494.  * In the file create case, these happen in separate places so we have
  495.  * two different tests.  They end up in the same place for subdbs, but
  496.  * for compatibility with file testing, we put them both here anyway.
  497.  */
  498. DB_TEST_RECOVERY(dbp, DB_TEST_POSTLOGMETA, ret, mname);
  499. DB_TEST_RECOVERY(dbp, DB_TEST_POSTSYNC, ret, mname);
  500. /*
  501.  * File exists and we have the appropriate locks; we should now
  502.  * process a normal open.
  503.  */
  504. if (F_ISSET(mdbp, DB_AM_CREATED)) {
  505. F_SET(dbp, DB_AM_CREATED_MSTR);
  506. F_CLR(mdbp, DB_AM_DISCARD);
  507. }
  508. /*
  509.  * The master's handle lock is under the control of the
  510.  * subdb (it acquired the master's locker.  We want to
  511.  * keep the master's handle lock so that no one can remove
  512.  * the file while the subdb is open.  If we register the
  513.  * trade event and then invalidate the copy of the lock
  514.  * in the master's handle, that will accomplish this.  However,
  515.  * before we register this event, we'd better remove any
  516.  * events that we've already registered for the master.
  517.  */
  518. if (!F_ISSET(dbp, DB_AM_RECOVER) && txn != NULL) {
  519. /* Unregister old master events. */
  520.  __txn_remlock(dbenv,
  521.     txn, &mdbp->handle_lock, DB_LOCK_INVALIDID);
  522. /* Now register the new event. */
  523. if ((ret = __txn_lockevent(dbenv,
  524.     txn, dbp, &mdbp->handle_lock, dbp->lid)) != 0)
  525. goto err;
  526. }
  527. LOCK_INIT(mdbp->handle_lock);
  528. return (__db_close_i(mdbp, txn, 0));
  529. err:
  530. DB_TEST_RECOVERY_LABEL
  531. if (LOCK_ISSET(dbp->handle_lock) && txn == NULL)
  532. __lock_put(dbenv, &dbp->handle_lock);
  533. /* If we created the master file then we need to remove it.  */
  534. if (mdbp != NULL) {
  535. do_remove = F_ISSET(mdbp, DB_AM_CREATED) ? 1 : 0;
  536. if (do_remove)
  537. F_SET(mdbp, DB_AM_DISCARD);
  538. (void)__db_close_i(mdbp, txn, 0);
  539. if (do_remove) {
  540. (void)db_create(&mdbp, dbp->dbenv, 0);
  541. (void)__db_remove_i(mdbp, txn, mname, NULL);
  542. }
  543. }
  544. return (ret);
  545. }
  546. /*
  547.  * __fop_remove_setup --
  548.  * Open handle appropriately and lock for removal of a database file.
  549.  *
  550.  * PUBLIC: int __fop_remove_setup __P((DB *,
  551.  * PUBLIC:      DB_TXN *, const char *, u_int32_t));
  552.  */
  553. int
  554. __fop_remove_setup(dbp, txn, name, flags)
  555. DB *dbp;
  556. DB_TXN *txn;
  557. const char *name;
  558. u_int32_t flags;
  559. {
  560. DB_ENV *dbenv;
  561. DB_LOCK elock;
  562. u_int8_t mbuf[DBMETASIZE];
  563. int ret;
  564. COMPQUIET(flags, 0);
  565. dbenv = dbp->dbenv;
  566. PANIC_CHECK(dbenv);
  567. LOCK_INIT(elock);
  568. /* Create locker if necessary. */
  569. if (LOCKING_ON(dbenv)) {
  570. if (txn != NULL)
  571. dbp->lid = txn->txnid;
  572. else if (dbp->lid == DB_LOCK_INVALIDID) {
  573. if ((ret = __lock_id(dbenv, &dbp->lid)) != 0)
  574. goto err;
  575. }
  576. }
  577. /*
  578.  * Lock environment to protect file open.  That will enable us to
  579.  * read the meta-data page and get the fileid so that we can lock
  580.  * the handle.
  581.  */
  582. GET_ENVLOCK(dbenv, dbp->lid, &elock);
  583. if ((ret = __fop_read_meta(dbenv,
  584.     name, mbuf, sizeof(mbuf), NULL, 0, 0)) != 0)
  585. goto err;
  586. if ((ret =
  587.     __db_meta_setup(dbenv, dbp, name, (DBMETA *)mbuf, flags, 1)) != 0)
  588. goto err;
  589. /* Now, release the environment and get the handle lock. */
  590. if ((ret = __fop_lock_handle(dbenv,
  591.     dbp, dbp->lid, DB_LOCK_WRITE, &elock, 0)) != 0)
  592. goto err;
  593. return (0);
  594. err: (void)REL_ENVLOCK(dbenv, &elock);
  595. return (ret);
  596. }
  597. /*
  598.  * __fop_read_meta --
  599.  * Read the meta-data page from a file and return it in buf.  The
  600.  * open file handle is returned in fhp.
  601.  *
  602.  * PUBLIC: int __fop_read_meta __P((DB_ENV *,
  603.  * PUBLIC:     const char *, u_int8_t *, size_t, DB_FH *, int, u_int32_t));
  604.  */
  605. int
  606. __fop_read_meta(dbenv, name, buf, size, fhp, errok, flags)
  607. DB_ENV *dbenv;
  608. const char *name;
  609. u_int8_t *buf;
  610. size_t size;
  611. DB_FH *fhp;
  612. int errok;
  613. u_int32_t flags;
  614. {
  615. DB_FH fh, *lfhp;
  616. size_t nr;
  617. int ret;
  618. lfhp = fhp == NULL ? &fh : fhp;
  619. memset(lfhp, 0, sizeof(*fhp));
  620. if ((ret = __os_open(dbenv, name, flags, 0, lfhp)) != 0)
  621. goto err;
  622. if ((ret = __os_read(dbenv, lfhp, buf, size, &nr)) != 0) {
  623. if (!errok)
  624. __db_err(dbenv, "%s: %s", name, db_strerror(ret));
  625. goto err;
  626. }
  627. if (nr != size) {
  628. if (!errok)
  629. __db_err(dbenv,
  630.     "%s: unexpected file type or format", name);
  631. ret = EINVAL;
  632. goto err;
  633. }
  634. err: /*
  635.  * On error, we always close the handle.  If there is no error,
  636.  * then we only return the handle if the user didn't pass us
  637.  * a handle into which to return it.  If fhp is valid, then
  638.  * lfhp is the same as fhp.
  639.  */
  640. if (F_ISSET(lfhp, DB_FH_VALID) && (ret != 0 || fhp == NULL))
  641. __os_closehandle(dbenv, lfhp);
  642. return (ret);
  643. }
  644. /*
  645.  * __fop_dummy --
  646.  * This implements the creation and name swapping of dummy files that
  647.  * we use for remove and rename (remove is simply a rename with a delayed
  648.  * remove).
  649.  *
  650.  * PUBLIC: int __fop_dummy __P((DB *,
  651.  * PUBLIC:     DB_TXN *, const char *, const char *, u_int32_t));
  652.  */
  653. int
  654. __fop_dummy(dbp, txn, old, new, flags)
  655. DB *dbp;
  656. DB_TXN *txn;
  657. const char *old, *new;
  658. u_int32_t flags;
  659. {
  660. DB *tmpdbp;
  661. DB_ENV *dbenv;
  662. DB_LOCK elock;
  663. DB_LSN lsn;
  664. DBT fiddbt, namedbt, tmpdbt;
  665. DB_TXN *stxn;
  666. char *back;
  667. char *realback, *realnew, *realold;
  668. int ret, t_ret;
  669. u_int8_t mbuf[DBMETASIZE];
  670. u_int32_t locker, stxnid;
  671. dbenv = dbp->dbenv;
  672. LOCK_INIT(elock);
  673. realback = NULL;
  674. realnew = NULL;
  675. realold = NULL;
  676. back = NULL;
  677. stxn = NULL;
  678. tmpdbp = NULL;
  679. DB_ASSERT(txn != NULL);
  680. locker = txn->txnid;
  681. /* Begin sub transaction to encapsulate the rename. */
  682. if (TXN_ON(dbenv) &&
  683.     (ret = dbenv->txn_begin(dbenv, txn, &stxn, 0)) != 0)
  684. goto err;
  685. /* We need to create a dummy file as a place holder. */
  686. if ((ret = __db_backup_name(dbenv, new, stxn, &back)) != 0)
  687. goto err;
  688. if ((ret = __db_appname(dbenv,
  689.     DB_APP_DATA, back, flags, NULL, &realback)) != 0)
  690. goto err;
  691. if ((ret = __fop_create(dbenv, stxn, NULL, back, DB_APP_DATA, 0)) != 0)
  692. goto err;
  693. memset(mbuf, 0, sizeof(mbuf));
  694. if ((ret =
  695.     __os_fileid(dbenv, realback, 1, ((DBMETA *)mbuf)->uid)) != 0)
  696. goto err;
  697. ((DBMETA *)mbuf)->magic = DB_RENAMEMAGIC;
  698. if ((ret = __fop_write(dbenv,
  699.     stxn, back, DB_APP_DATA, NULL, 0, mbuf, DBMETASIZE, 1)) != 0)
  700. goto err;
  701. /* Create a dummy dbp handle. */
  702. if ((ret = db_create(&tmpdbp, dbenv, 0)) != 0)
  703. goto err;
  704. memcpy(&tmpdbp->fileid, ((DBMETA *)mbuf)->uid, DB_FILE_ID_LEN);
  705. /* Now, lock the name space while we initialize this file. */
  706. if ((ret = __db_appname(dbenv,
  707.     DB_APP_DATA, new, 0, NULL, &realnew)) != 0)
  708. goto err;
  709. GET_ENVLOCK(dbenv, locker, &elock);
  710. if (__os_exists(realnew, NULL) == 0) {
  711. ret = EEXIST;
  712. goto err;
  713. }
  714. /*
  715.  * While we have the namespace locked, do the renames and then
  716.  * swap for the handle lock.
  717.  */
  718. if ((ret = __fop_rename(dbenv,
  719.     stxn, old, new, dbp->fileid, DB_APP_DATA)) != 0)
  720. goto err;
  721. if ((ret = __fop_rename(dbenv,
  722.     stxn, back, old, tmpdbp->fileid, DB_APP_DATA)) != 0)
  723. goto err;
  724. if ((ret = __fop_lock_handle(dbenv,
  725.     tmpdbp, locker, DB_LOCK_WRITE, &elock, 0)) != 0)
  726. goto err;
  727. /*
  728.  * We just acquired a transactional lock on the tmp handle.
  729.  * We need to null out the tmp handle's lock so that it
  730.  * doesn't create problems for us in the close path.
  731.  */
  732. LOCK_INIT(tmpdbp->handle_lock);
  733. if (stxn != NULL) {
  734. /* Commit the child. */
  735. stxnid = stxn->txnid;
  736. ret = stxn->commit(stxn, 0);
  737. stxn = NULL;
  738. /* Now log the child information in the parent. */
  739. memset(&fiddbt, 0, sizeof(fiddbt));
  740. memset(&tmpdbt, 0, sizeof(fiddbt));
  741. memset(&namedbt, 0, sizeof(namedbt));
  742. fiddbt.data = dbp->fileid;
  743. fiddbt.size = DB_FILE_ID_LEN;
  744. tmpdbt.data = tmpdbp->fileid;
  745. tmpdbt.size = DB_FILE_ID_LEN;
  746. namedbt.data = (void *)old;
  747. namedbt.size = (u_int32_t)strlen(old) + 1;
  748. if ((t_ret =
  749.     __fop_file_remove_log(dbenv, txn, &lsn, 0, &fiddbt,
  750.     &tmpdbt, &namedbt, DB_APP_DATA, stxnid)) != 0 && ret == 0)
  751. ret = t_ret;
  752. }
  753. /* This is a delayed delete of the dummy file. */
  754. if ((ret = __db_appname(dbenv,
  755.     DB_APP_DATA, old, flags, NULL, &realold)) != 0)
  756. goto err;
  757. if ((ret = __txn_remevent(dbenv, txn, realold, NULL)) != 0)
  758. goto err;
  759. err: (void)REL_ENVLOCK(dbenv, &elock);
  760. if (stxn != NULL)
  761. (void)stxn->abort(stxn);
  762. if (tmpdbp != NULL &&
  763.     (t_ret = __db_close_i(tmpdbp, NULL, 0)) != 0 && ret == 0)
  764. ret = t_ret;
  765. if (realold != NULL)
  766. __os_free(dbenv, realold);
  767. if (realnew != NULL)
  768. __os_free(dbenv, realnew);
  769. if (realback != NULL)
  770. __os_free(dbenv, realback);
  771. if (back != NULL)
  772. __os_free(dbenv, back);
  773. return (ret);
  774. }
  775. /*
  776.  * __fop_dbrename --
  777.  * Do the appropriate file locking and file system operations
  778.  * to effect a dbrename in the absence of transactions (__fop_dummy
  779.  * and the subsequent calls in __db_rename do the work for the
  780.  * transactional case).
  781.  *
  782.  * PUBLIC: int __fop_dbrename __P((DB *, const char *, const char *));
  783.  */
  784. int
  785. __fop_dbrename(dbp, old, new)
  786. DB *dbp;
  787. const char *old, *new;
  788. {
  789. DB_ENV *dbenv;
  790. DB_LOCK elock;
  791. char *real_new, *real_old;
  792. int ret, tret;
  793. dbenv = dbp->dbenv;
  794. real_new = NULL;
  795. real_old = NULL;
  796. LOCK_INIT(elock);
  797. /* Find the real newname of the file. */
  798. if ((ret = __db_appname(dbenv,
  799.     DB_APP_DATA, new, 0, NULL, &real_new)) != 0)
  800. goto err;
  801. /*
  802.  * It is an error to rename a file over one that already exists,
  803.  * as that wouldn't be transaction-safe.
  804.  */
  805. GET_ENVLOCK(dbenv, dbp->lid, &elock);
  806. if (__os_exists(real_new, NULL) == 0) {
  807. ret = EEXIST;
  808. __db_err(dbenv, "rename: file %s exists", real_new);
  809. goto err;
  810. }
  811. if ((ret = __db_appname(dbenv,
  812.     DB_APP_DATA, old, 0, NULL, &real_old)) != 0)
  813. goto err;
  814. ret = dbenv->memp_nameop(dbenv, dbp->fileid, new, real_old, real_new);
  815. err: if ((tret = REL_ENVLOCK(dbenv, &elock)) != 0 && ret == 0)
  816. ret = tret;
  817. if (real_old != NULL)
  818. __os_free(dbenv, real_old);
  819. if (real_new != NULL)
  820. __os_free(dbenv, real_new);
  821. return (ret);
  822. }