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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. /*
  8.  * Copyright (c) 1995, 1996
  9.  * The President and Fellows of Harvard University.  All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms, with or without
  12.  * modification, are permitted provided that the following conditions
  13.  * are met:
  14.  * 1. Redistributions of source code must retain the above copyright
  15.  *    notice, this list of conditions and the following disclaimer.
  16.  * 2. Redistributions in binary form must reproduce the above copyright
  17.  *    notice, this list of conditions and the following disclaimer in the
  18.  *    documentation and/or other materials provided with the distribution.
  19.  * 3. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35. #include "db_config.h"
  36. #ifndef lint
  37. static const char revid[] = "$Id: dbreg_rec.c,v 11.108 2002/08/14 20:04:25 bostic Exp $";
  38. #endif /* not lint */
  39. #ifndef NO_SYSTEM_INCLUDES
  40. #include <sys/types.h>
  41. #include <string.h>
  42. #endif
  43. #include "db_int.h"
  44. #include "dbinc/db_page.h"
  45. #include "dbinc/db_am.h"
  46. #include "dbinc/log.h"
  47. #include "dbinc/txn.h"
  48. static int __dbreg_open_file __P((DB_ENV *,
  49.     DB_TXN *, __dbreg_register_args *, void *));
  50. /*
  51.  * PUBLIC: int __dbreg_register_recover
  52.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  53.  */
  54. int
  55. __dbreg_register_recover(dbenv, dbtp, lsnp, op, info)
  56. DB_ENV *dbenv;
  57. DBT *dbtp;
  58. DB_LSN *lsnp;
  59. db_recops op;
  60. void *info;
  61. {
  62. DB_ENTRY *dbe;
  63. DB_LOG *dblp;
  64. DB *dbp;
  65. __dbreg_register_args *argp;
  66. int do_close, do_open, do_rem, ret, t_ret;
  67. dblp = dbenv->lg_handle;
  68. dbp = NULL;
  69. #ifdef DEBUG_RECOVER
  70. REC_PRINT(__dbreg_register_print);
  71. #endif
  72. do_open = do_close = 0;
  73. if ((ret = __dbreg_register_read(dbenv, dbtp->data, &argp)) != 0)
  74. goto out;
  75. switch (argp->opcode) {
  76. case LOG_OPEN:
  77. if ((DB_REDO(op) ||
  78.     op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES))
  79. do_open = 1;
  80. else
  81. do_close = 1;
  82. break;
  83. case LOG_CLOSE:
  84. if (DB_UNDO(op))
  85. do_open = 1;
  86. else
  87. do_close = 1;
  88. break;
  89. case LOG_RCLOSE:
  90. /*
  91.  * LOG_RCLOSE was generated by recover because a file
  92.  * was left open.  The POPENFILES pass, which is run
  93.  * to open files to abort prepared transactions,
  94.  * may not include the open for this file so we
  95.  * open it here.  Note that a normal CLOSE is
  96.  * not legal before the prepared transaction is
  97.  * committed or aborted.
  98.  */
  99. if (DB_UNDO(op) || op == DB_TXN_POPENFILES)
  100. do_open = 1;
  101. else
  102. do_close = 1;
  103. break;
  104. case LOG_CHECKPOINT:
  105. if (DB_UNDO(op) ||
  106.     op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES)
  107. do_open = 1;
  108. break;
  109. }
  110. if (do_open) {
  111. /*
  112.  * We must open the db even if the meta page is not
  113.  * yet written as we may be creating subdatabase.
  114.  */
  115. if (op == DB_TXN_OPENFILES && argp->opcode != LOG_CHECKPOINT)
  116. F_SET(dblp, DBLOG_FORCE_OPEN);
  117. /*
  118.  * During an abort or an open pass to recover prepared txns,
  119.  * we need to make sure that we use the same locker id on the
  120.  * open.  We pass the txnid along to ensure this.
  121.  */
  122. ret = __dbreg_open_file(dbenv,
  123.     op == DB_TXN_ABORT || op == DB_TXN_POPENFILES ?
  124.     argp->txnid : NULL, argp, info);
  125. if (ret == ENOENT || ret == EINVAL) {
  126. /*
  127.  * If this is an OPEN while rolling forward, it's
  128.  * possible that the file was recreated since last
  129.  * time we got here.  In that case, we've got deleted
  130.  * set and probably shouldn't, so we need to check
  131.  * for that case and possibly retry.
  132.  */
  133. if (op == DB_TXN_FORWARD_ROLL &&
  134.     argp->txnid != 0 &&
  135.     dblp->dbentry[argp->fileid].deleted) {
  136. dblp->dbentry[argp->fileid].deleted = 0;
  137. ret =
  138.     __dbreg_open_file(dbenv, NULL, argp, info);
  139. }
  140. ret = 0;
  141. }
  142. F_CLR(dblp, DBLOG_FORCE_OPEN);
  143. }
  144. if (do_close) {
  145. /*
  146.  * If we are undoing an open, or redoing a close,
  147.  * then we need to close the file.
  148.  *
  149.  * If the file is deleted, then we can just ignore this close.
  150.  * Otherwise, we should usually have a valid dbp we should
  151.  * close or whose reference count should be decremented.
  152.  * However, if we shut down without closing a file, we may, in
  153.  * fact, not have the file open, and that's OK.
  154.  */
  155. do_rem = 0;
  156. MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
  157. if (argp->fileid < dblp->dbentry_cnt) {
  158. /*
  159.  * Typically, closes should match an open which means
  160.  * that if this is a close, there should be a valid
  161.  * entry in the dbentry table when we get here,
  162.  * however there is an exception.  If this is an
  163.  * OPENFILES pass, then we may have started from
  164.  * a log file other than the first, and the
  165.  * corresponding open appears in an earlier file.
  166.  * We can ignore that case, but all others are errors.
  167.  */
  168. dbe = &dblp->dbentry[argp->fileid];
  169. if (dbe->dbp == NULL && !dbe->deleted) {
  170. /* No valid entry here. */
  171. if ((argp->opcode != LOG_CLOSE &&
  172.     argp->opcode != LOG_RCLOSE) ||
  173.     (op != DB_TXN_OPENFILES &&
  174.     op !=DB_TXN_POPENFILES)) {
  175. __db_err(dbenv,
  176.     "Improper file close at %lu/%lu",
  177.     (u_long)lsnp->file,
  178.     (u_long)lsnp->offset);
  179. ret = EINVAL;
  180. }
  181. MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
  182. goto done;
  183. }
  184. /* We have either an open entry or a deleted entry. */
  185. if ((dbp = dbe->dbp) != NULL) {
  186. MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
  187. (void)__dbreg_revoke_id(dbp, 0);
  188. /*
  189.  * If we're a replication client, it's
  190.  * possible to get here with a dbp that
  191.  * the user opened, but which we later
  192.  * assigned a fileid to.  Be sure that
  193.  * we only close dbps that we opened in
  194.  * the recovery code;  they should have
  195.  * DB_AM_RECOVER set.
  196.  *
  197.  * The only exception is if we're aborting
  198.  * in a normal environment;  then we might
  199.  * get here with a non-AM_RECOVER database.
  200.  */
  201. if (F_ISSET(dbp, DB_AM_RECOVER) ||
  202.     op == DB_TXN_ABORT)
  203. do_rem = 1;
  204. } else if (dbe->deleted) {
  205. MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
  206. __dbreg_rem_dbentry(dblp, argp->fileid);
  207. }
  208. } else
  209. MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
  210. if (do_rem) {
  211. /*
  212.  * If we are undoing a create we'd better discard
  213.  * any buffers from the memory pool.
  214.  */
  215. if (dbp != NULL && dbp->mpf != NULL && argp->id != 0) {
  216. if ((ret = dbp->mpf->close(dbp->mpf,
  217.     DB_MPOOL_DISCARD)) != 0)
  218. goto out;
  219. dbp->mpf = NULL;
  220. }
  221. /*
  222.  * During recovery, all files are closed.  On an abort,
  223.  * we only close the file if we opened it during the
  224.  * abort (DB_AM_RECOVER set), otherwise we simply do
  225.  * a __db_refresh.  For the close case, if remove or
  226.  * rename has closed the file, don't request a sync,
  227.  * because the NULL mpf would be a problem.
  228.  */
  229. if (dbp != NULL) {
  230. if (op == DB_TXN_ABORT &&
  231.     !F_ISSET(dbp, DB_AM_RECOVER))
  232. t_ret =
  233.     __db_refresh(dbp, NULL, DB_NOSYNC);
  234. else
  235. t_ret = dbp->close(dbp, DB_NOSYNC);
  236. if (t_ret != 0 && ret == 0)
  237. ret = t_ret;
  238. }
  239. }
  240. }
  241. done: if (ret == 0)
  242. *lsnp = argp->prev_lsn;
  243. out: if (argp != NULL)
  244. __os_free(dbenv, argp);
  245. return (ret);
  246. }
  247. /*
  248.  * __dbreg_open_file --
  249.  * Called during log_register recovery.  Make sure that we have an
  250.  * entry in the dbentry table for this ndx.  Returns 0 on success,
  251.  * non-zero on error.
  252.  */
  253. static int
  254. __dbreg_open_file(dbenv, txn, argp, info)
  255. DB_ENV *dbenv;
  256. DB_TXN *txn;
  257. __dbreg_register_args *argp;
  258. void *info;
  259. {
  260. DB_ENTRY *dbe;
  261. DB_LOG *lp;
  262. DB *dbp;
  263. u_int32_t id;
  264. lp = (DB_LOG *)dbenv->lg_handle;
  265. /*
  266.  * We never re-open temporary files.  Temp files are only
  267.  * useful during aborts in which case the dbp was entered
  268.  * when the file was registered.  During recovery, we treat
  269.  * temp files as properly deleted files, allowing the open to
  270.  * fail and not reporting any errors when recovery fails to
  271.  * get a valid dbp from __dbreg_id_to_db.
  272.  */
  273. if (argp->name.size == 0) {
  274. (void)__dbreg_add_dbentry(dbenv, lp, NULL, argp->fileid);
  275. return (ENOENT);
  276. }
  277. /*
  278.  * When we're opening, we have to check that the name we are opening
  279.  * is what we expect.  If it's not, then we close the old file and
  280.  * open the new one.
  281.  */
  282. MUTEX_THREAD_LOCK(dbenv, lp->mutexp);
  283. if (argp->fileid < lp->dbentry_cnt)
  284. dbe = &lp->dbentry[argp->fileid];
  285. else
  286. dbe = NULL;
  287. if (dbe != NULL) {
  288. if (dbe->deleted) {
  289. MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
  290. return (ENOENT);
  291. }
  292. if ((dbp = dbe->dbp) != NULL) {
  293. if (dbp->meta_pgno != argp->meta_pgno ||
  294.     memcmp(dbp->fileid,
  295.     argp->uid.data, DB_FILE_ID_LEN) != 0) {
  296. MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
  297. (void)__dbreg_revoke_id(dbp, 0);
  298. if (F_ISSET(dbp, DB_AM_RECOVER))
  299. dbp->close(dbp, DB_NOSYNC);
  300. goto reopen;
  301. }
  302. /*
  303.  * We should only get here if we already have the
  304.  * dbp from an openfiles pass, in which case, what's
  305.  * here had better be the same dbp.
  306.  */
  307. DB_ASSERT(dbe->dbp == dbp);
  308. MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
  309. /*
  310.  * This is a successful open.  We need to record that
  311.  * in the txnlist so that we know how to handle the
  312.  * subtransaction that created the file system object.
  313.  */
  314. if (argp->id != TXN_INVALID &&
  315.     __db_txnlist_update(dbenv, info,
  316.     argp->id, TXN_EXPECTED, NULL) == TXN_NOTFOUND)
  317. (void)__db_txnlist_add(dbenv,
  318.     info, argp->id, TXN_EXPECTED, NULL);
  319. return (0);
  320. }
  321. }
  322. MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
  323. /*
  324.  * We are about to pass a recovery txn pointer into the main library.
  325.  * We need to make sure that any accessed fields are set appropriately.
  326.  */
  327. reopen: if (txn != NULL) {
  328. id = txn->txnid;
  329. memset(txn, 0, sizeof(DB_TXN));
  330. txn->txnid = id;
  331. txn->mgrp = dbenv->tx_handle;
  332. }
  333. return (__dbreg_do_open(dbenv, txn, lp, argp->uid.data, argp->name.data,
  334.     argp->ftype, argp->fileid, argp->meta_pgno, info, argp->id));
  335. }