dbreg_rec.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:11k
- /*-
- * See the file LICENSE for redistribution information.
- *
- * Copyright (c) 1996-2002
- * Sleepycat Software. All rights reserved.
- */
- /*
- * Copyright (c) 1995, 1996
- * The President and Fellows of Harvard University. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- #include "db_config.h"
- #ifndef lint
- static const char revid[] = "$Id: dbreg_rec.c,v 11.108 2002/08/14 20:04:25 bostic Exp $";
- #endif /* not lint */
- #ifndef NO_SYSTEM_INCLUDES
- #include <sys/types.h>
- #include <string.h>
- #endif
- #include "db_int.h"
- #include "dbinc/db_page.h"
- #include "dbinc/db_am.h"
- #include "dbinc/log.h"
- #include "dbinc/txn.h"
- static int __dbreg_open_file __P((DB_ENV *,
- DB_TXN *, __dbreg_register_args *, void *));
- /*
- * PUBLIC: int __dbreg_register_recover
- * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
- */
- int
- __dbreg_register_recover(dbenv, dbtp, lsnp, op, info)
- DB_ENV *dbenv;
- DBT *dbtp;
- DB_LSN *lsnp;
- db_recops op;
- void *info;
- {
- DB_ENTRY *dbe;
- DB_LOG *dblp;
- DB *dbp;
- __dbreg_register_args *argp;
- int do_close, do_open, do_rem, ret, t_ret;
- dblp = dbenv->lg_handle;
- dbp = NULL;
- #ifdef DEBUG_RECOVER
- REC_PRINT(__dbreg_register_print);
- #endif
- do_open = do_close = 0;
- if ((ret = __dbreg_register_read(dbenv, dbtp->data, &argp)) != 0)
- goto out;
- switch (argp->opcode) {
- case LOG_OPEN:
- if ((DB_REDO(op) ||
- op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES))
- do_open = 1;
- else
- do_close = 1;
- break;
- case LOG_CLOSE:
- if (DB_UNDO(op))
- do_open = 1;
- else
- do_close = 1;
- break;
- case LOG_RCLOSE:
- /*
- * LOG_RCLOSE was generated by recover because a file
- * was left open. The POPENFILES pass, which is run
- * to open files to abort prepared transactions,
- * may not include the open for this file so we
- * open it here. Note that a normal CLOSE is
- * not legal before the prepared transaction is
- * committed or aborted.
- */
- if (DB_UNDO(op) || op == DB_TXN_POPENFILES)
- do_open = 1;
- else
- do_close = 1;
- break;
- case LOG_CHECKPOINT:
- if (DB_UNDO(op) ||
- op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES)
- do_open = 1;
- break;
- }
- if (do_open) {
- /*
- * We must open the db even if the meta page is not
- * yet written as we may be creating subdatabase.
- */
- if (op == DB_TXN_OPENFILES && argp->opcode != LOG_CHECKPOINT)
- F_SET(dblp, DBLOG_FORCE_OPEN);
- /*
- * During an abort or an open pass to recover prepared txns,
- * we need to make sure that we use the same locker id on the
- * open. We pass the txnid along to ensure this.
- */
- ret = __dbreg_open_file(dbenv,
- op == DB_TXN_ABORT || op == DB_TXN_POPENFILES ?
- argp->txnid : NULL, argp, info);
- if (ret == ENOENT || ret == EINVAL) {
- /*
- * If this is an OPEN while rolling forward, it's
- * possible that the file was recreated since last
- * time we got here. In that case, we've got deleted
- * set and probably shouldn't, so we need to check
- * for that case and possibly retry.
- */
- if (op == DB_TXN_FORWARD_ROLL &&
- argp->txnid != 0 &&
- dblp->dbentry[argp->fileid].deleted) {
- dblp->dbentry[argp->fileid].deleted = 0;
- ret =
- __dbreg_open_file(dbenv, NULL, argp, info);
- }
- ret = 0;
- }
- F_CLR(dblp, DBLOG_FORCE_OPEN);
- }
- if (do_close) {
- /*
- * If we are undoing an open, or redoing a close,
- * then we need to close the file.
- *
- * If the file is deleted, then we can just ignore this close.
- * Otherwise, we should usually have a valid dbp we should
- * close or whose reference count should be decremented.
- * However, if we shut down without closing a file, we may, in
- * fact, not have the file open, and that's OK.
- */
- do_rem = 0;
- MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
- if (argp->fileid < dblp->dbentry_cnt) {
- /*
- * Typically, closes should match an open which means
- * that if this is a close, there should be a valid
- * entry in the dbentry table when we get here,
- * however there is an exception. If this is an
- * OPENFILES pass, then we may have started from
- * a log file other than the first, and the
- * corresponding open appears in an earlier file.
- * We can ignore that case, but all others are errors.
- */
- dbe = &dblp->dbentry[argp->fileid];
- if (dbe->dbp == NULL && !dbe->deleted) {
- /* No valid entry here. */
- if ((argp->opcode != LOG_CLOSE &&
- argp->opcode != LOG_RCLOSE) ||
- (op != DB_TXN_OPENFILES &&
- op !=DB_TXN_POPENFILES)) {
- __db_err(dbenv,
- "Improper file close at %lu/%lu",
- (u_long)lsnp->file,
- (u_long)lsnp->offset);
- ret = EINVAL;
- }
- MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
- goto done;
- }
- /* We have either an open entry or a deleted entry. */
- if ((dbp = dbe->dbp) != NULL) {
- MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
- (void)__dbreg_revoke_id(dbp, 0);
- /*
- * If we're a replication client, it's
- * possible to get here with a dbp that
- * the user opened, but which we later
- * assigned a fileid to. Be sure that
- * we only close dbps that we opened in
- * the recovery code; they should have
- * DB_AM_RECOVER set.
- *
- * The only exception is if we're aborting
- * in a normal environment; then we might
- * get here with a non-AM_RECOVER database.
- */
- if (F_ISSET(dbp, DB_AM_RECOVER) ||
- op == DB_TXN_ABORT)
- do_rem = 1;
- } else if (dbe->deleted) {
- MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
- __dbreg_rem_dbentry(dblp, argp->fileid);
- }
- } else
- MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
- if (do_rem) {
- /*
- * If we are undoing a create we'd better discard
- * any buffers from the memory pool.
- */
- if (dbp != NULL && dbp->mpf != NULL && argp->id != 0) {
- if ((ret = dbp->mpf->close(dbp->mpf,
- DB_MPOOL_DISCARD)) != 0)
- goto out;
- dbp->mpf = NULL;
- }
- /*
- * During recovery, all files are closed. On an abort,
- * we only close the file if we opened it during the
- * abort (DB_AM_RECOVER set), otherwise we simply do
- * a __db_refresh. For the close case, if remove or
- * rename has closed the file, don't request a sync,
- * because the NULL mpf would be a problem.
- */
- if (dbp != NULL) {
- if (op == DB_TXN_ABORT &&
- !F_ISSET(dbp, DB_AM_RECOVER))
- t_ret =
- __db_refresh(dbp, NULL, DB_NOSYNC);
- else
- t_ret = dbp->close(dbp, DB_NOSYNC);
- if (t_ret != 0 && ret == 0)
- ret = t_ret;
- }
- }
- }
- done: if (ret == 0)
- *lsnp = argp->prev_lsn;
- out: if (argp != NULL)
- __os_free(dbenv, argp);
- return (ret);
- }
- /*
- * __dbreg_open_file --
- * Called during log_register recovery. Make sure that we have an
- * entry in the dbentry table for this ndx. Returns 0 on success,
- * non-zero on error.
- */
- static int
- __dbreg_open_file(dbenv, txn, argp, info)
- DB_ENV *dbenv;
- DB_TXN *txn;
- __dbreg_register_args *argp;
- void *info;
- {
- DB_ENTRY *dbe;
- DB_LOG *lp;
- DB *dbp;
- u_int32_t id;
- lp = (DB_LOG *)dbenv->lg_handle;
- /*
- * We never re-open temporary files. Temp files are only
- * useful during aborts in which case the dbp was entered
- * when the file was registered. During recovery, we treat
- * temp files as properly deleted files, allowing the open to
- * fail and not reporting any errors when recovery fails to
- * get a valid dbp from __dbreg_id_to_db.
- */
- if (argp->name.size == 0) {
- (void)__dbreg_add_dbentry(dbenv, lp, NULL, argp->fileid);
- return (ENOENT);
- }
- /*
- * When we're opening, we have to check that the name we are opening
- * is what we expect. If it's not, then we close the old file and
- * open the new one.
- */
- MUTEX_THREAD_LOCK(dbenv, lp->mutexp);
- if (argp->fileid < lp->dbentry_cnt)
- dbe = &lp->dbentry[argp->fileid];
- else
- dbe = NULL;
- if (dbe != NULL) {
- if (dbe->deleted) {
- MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
- return (ENOENT);
- }
- if ((dbp = dbe->dbp) != NULL) {
- if (dbp->meta_pgno != argp->meta_pgno ||
- memcmp(dbp->fileid,
- argp->uid.data, DB_FILE_ID_LEN) != 0) {
- MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
- (void)__dbreg_revoke_id(dbp, 0);
- if (F_ISSET(dbp, DB_AM_RECOVER))
- dbp->close(dbp, DB_NOSYNC);
- goto reopen;
- }
- /*
- * We should only get here if we already have the
- * dbp from an openfiles pass, in which case, what's
- * here had better be the same dbp.
- */
- DB_ASSERT(dbe->dbp == dbp);
- MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
- /*
- * This is a successful open. We need to record that
- * in the txnlist so that we know how to handle the
- * subtransaction that created the file system object.
- */
- if (argp->id != TXN_INVALID &&
- __db_txnlist_update(dbenv, info,
- argp->id, TXN_EXPECTED, NULL) == TXN_NOTFOUND)
- (void)__db_txnlist_add(dbenv,
- info, argp->id, TXN_EXPECTED, NULL);
- return (0);
- }
- }
- MUTEX_THREAD_UNLOCK(dbenv, lp->mutexp);
- /*
- * We are about to pass a recovery txn pointer into the main library.
- * We need to make sure that any accessed fields are set appropriately.
- */
- reopen: if (txn != NULL) {
- id = txn->txnid;
- memset(txn, 0, sizeof(DB_TXN));
- txn->txnid = id;
- txn->mgrp = dbenv->tx_handle;
- }
- return (__dbreg_do_open(dbenv, txn, lp, argp->uid.data, argp->name.data,
- argp->ftype, argp->fileid, argp->meta_pgno, info, argp->id));
- }