diff options
Diffstat (limited to 'storage/bdb/dbreg/dbreg_rec.c')
-rw-r--r-- | storage/bdb/dbreg/dbreg_rec.c | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/storage/bdb/dbreg/dbreg_rec.c b/storage/bdb/dbreg/dbreg_rec.c new file mode 100644 index 00000000000..ba3ba0e06d9 --- /dev/null +++ b/storage/bdb/dbreg/dbreg_rec.c @@ -0,0 +1,362 @@ +/*- + * 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)); +} |