From 2cfd3012bfcb5c5c61bbaf662ef084e0ab789d79 Mon Sep 17 00:00:00 2001 From: Panu Matilainen Date: Mon, 16 Jul 2007 16:48:14 +0300 Subject: Update internal BDB to version 4.5.20 --- db/dbreg/dbreg.c | 296 ++++++++++++++++++++++++++++++++++--------------- db/dbreg/dbreg.src | 15 +-- db/dbreg/dbreg_auto.c | 53 +++++---- db/dbreg/dbreg_autop.c | 19 +--- db/dbreg/dbreg_rec.c | 87 ++++++++------- db/dbreg/dbreg_stat.c | 58 +++++++--- db/dbreg/dbreg_util.c | 212 ++++++++++++++++++++++++----------- 7 files changed, 477 insertions(+), 263 deletions(-) (limited to 'db/dbreg') diff --git a/db/dbreg/dbreg.c b/db/dbreg/dbreg.c index 930c8bb7a..edc4599be 100644 --- a/db/dbreg/dbreg.c +++ b/db/dbreg/dbreg.c @@ -1,27 +1,21 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1996-2006 + * Oracle Corporation. All rights reserved. * - * $Id: dbreg.c,v 11.90 2004/10/15 16:59:39 bostic Exp $ + * $Id: dbreg.c,v 12.20 2006/08/24 14:45:31 bostic Exp $ */ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include - -#include -#endif - #include "db_int.h" #include "dbinc/db_page.h" #include "dbinc/log.h" #include "dbinc/txn.h" #include "dbinc/db_am.h" -static int __dbreg_push_id __P((DB_ENV *, int32_t)); +static int __dbreg_push_id __P((DB_ENV *, DB *, int32_t)); static int __dbreg_pop_id __P((DB_ENV *, int32_t *)); static int __dbreg_pluck_id __P((DB_ENV *, int32_t)); @@ -60,9 +54,9 @@ static int __dbreg_pluck_id __P((DB_ENV *, int32_t)); * region list so they can get logged on checkpoints. * * An FNAME that may/does have a valid id must be accessed under - * protection of the fq_mutex, with the following exception: + * protection of the mtx_filelist, with the following exception: * - * We don't want to have to grab the fq_mutex on every log + * We don't want to have to grab the mtx_filelist on every log * record, and it should be safe not to do so when we're just * looking at the id, because once allocated, the id should * not change under a handle until the handle is closed. @@ -114,7 +108,7 @@ __dbreg_setup(dbp, name, create_txnid) namep = NULL; /* Allocate an FNAME and, if necessary, a buffer for the name itself. */ - R_LOCK(dbenv, infop); + LOG_SYSTEM_LOCK(dbenv); if ((ret = __db_shalloc(infop, sizeof(FNAME), 0, &fnp)) != 0) goto err; memset(fnp, 0, sizeof(FNAME)); @@ -127,13 +121,13 @@ __dbreg_setup(dbp, name, create_txnid) } else fnp->name_off = INVALID_ROFF; - R_UNLOCK(dbenv, infop); + LOG_SYSTEM_UNLOCK(dbenv); /* * Fill in all the remaining info that we'll need later to register * the file, if we use it for logging. */ - fnp->id = DB_LOGFILEID_INVALID; + fnp->id = fnp->old_id = DB_LOGFILEID_INVALID; fnp->s_type = dbp->type; memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN); fnp->meta_pgno = dbp->meta_pgno; @@ -143,9 +137,9 @@ __dbreg_setup(dbp, name, create_txnid) return (0); -err: R_UNLOCK(dbenv, infop); +err: LOG_SYSTEM_UNLOCK(dbenv); if (ret == ENOMEM) - __db_err(dbenv, + __db_errx(dbenv, "Logging region out of memory; you may need to increase its size"); return (ret); @@ -175,16 +169,16 @@ __dbreg_teardown(dbp) * We may not have an FNAME if we were never opened. This is not an * error. */ - if (fnp == NULL) + if (fnp == NULL || F_ISSET(fnp, DB_FNAME_NOTLOGGED)) return (0); - DB_ASSERT(fnp->id == DB_LOGFILEID_INVALID); + DB_ASSERT(dbenv, fnp->id == DB_LOGFILEID_INVALID); - R_LOCK(dbenv, infop); + LOG_SYSTEM_LOCK(dbenv); if (fnp->name_off != INVALID_ROFF) __db_shalloc_free(infop, R_ADDR(infop, fnp->name_off)); __db_shalloc_free(infop, fnp); - R_UNLOCK(dbenv, infop); + LOG_SYSTEM_UNLOCK(dbenv); dbp->log_filename = NULL; @@ -216,22 +210,22 @@ __dbreg_new_id(dbp, txn) lp = dblp->reginfo.primary; fnp = dbp->log_filename; - /* The fq_mutex protects the FNAME list and id management. */ - MUTEX_LOCK(dbenv, &lp->fq_mutex); + /* The mtx_filelist protects the FNAME list and id management. */ + MUTEX_LOCK(dbenv, lp->mtx_filelist); if (fnp->id != DB_LOGFILEID_INVALID) { - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (0); } if ((ret = __dbreg_get_id(dbp, txn, &id)) == 0) fnp->id = id; - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } /* * __dbreg_get_id -- * Assign an unused dbreg id to this database handle. - * Assume the caller holds the fq_mutex locked. Assume the + * Assume the caller holds the mtx_filelist locked. Assume the * caller will set the fnp->id field with the id we return. * * PUBLIC: int __dbreg_get_id __P((DB *, DB_TXN *, int32_t *)); @@ -242,10 +236,8 @@ __dbreg_get_id(dbp, txn, idp) DB_TXN *txn; int32_t *idp; { - DBT fid_dbt, r_name; DB_ENV *dbenv; DB_LOG *dblp; - DB_LSN unused; FNAME *fnp; LOG *lp; int32_t id; @@ -269,7 +261,9 @@ __dbreg_get_id(dbp, txn, idp) if (id == DB_LOGFILEID_INVALID) id = lp->fid_max++; - fnp->is_durable = !F_ISSET(dbp, DB_AM_NOT_DURABLE); + /* If the file is durable (i.e., not, not-durable), mark it as such. */ + if (!F_ISSET(dbp, DB_AM_NOT_DURABLE)) + F_SET(fnp, DB_FNAME_DURABLE); /* Hook the FNAME into the list of open files. */ SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname); @@ -278,21 +272,11 @@ __dbreg_get_id(dbp, txn, idp) * Log the registry. We should only request a new ID in situations * where logging is reasonable. */ - DB_ASSERT(!F_ISSET(dbp, DB_AM_RECOVER)); + DB_ASSERT(dbenv, !F_ISSET(dbp, DB_AM_RECOVER)); - memset(&fid_dbt, 0, sizeof(fid_dbt)); - memset(&r_name, 0, sizeof(r_name)); - if (fnp->name_off != INVALID_ROFF) { - r_name.data = R_ADDR(&dblp->reginfo, fnp->name_off); - r_name.size = (u_int32_t)strlen((char *)r_name.data) + 1; - } - fid_dbt.data = dbp->fileid; - fid_dbt.size = DB_FILE_ID_LEN; - if ((ret = __dbreg_register_log(dbenv, txn, &unused, - F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0, - DBREG_OPEN, r_name.size == 0 ? NULL : &r_name, &fid_dbt, id, - fnp->s_type, fnp->meta_pgno, fnp->create_txnid)) != 0) + if ((ret = __dbreg_log_id(dbp, txn, id, 0)) != 0) goto err; + /* * Once we log the create_txnid, we need to make sure we never * log it again (as might happen if this is a replication client @@ -300,8 +284,8 @@ __dbreg_get_id(dbp, txn, idp) */ fnp->create_txnid = TXN_INVALID; - DB_ASSERT(dbp->type == fnp->s_type); - DB_ASSERT(dbp->meta_pgno == fnp->meta_pgno); + DB_ASSERT(dbenv, dbp->type == fnp->s_type); + DB_ASSERT(dbenv, dbp->meta_pgno == fnp->meta_pgno); if ((ret = __dbreg_add_dbentry(dbenv, dblp, dbp, id)) != 0) goto err; @@ -345,11 +329,11 @@ __dbreg_assign_id(dbp, id) close_dbp = NULL; close_fnp = NULL; - /* The fq_mutex protects the FNAME list and id management. */ - MUTEX_LOCK(dbenv, &lp->fq_mutex); + /* The mtx_filelist protects the FNAME list and id management. */ + MUTEX_LOCK(dbenv, lp->mtx_filelist); /* We should only call this on DB handles that have no ID. */ - DB_ASSERT(fnp->id == DB_LOGFILEID_INVALID); + DB_ASSERT(dbenv, fnp->id == DB_LOGFILEID_INVALID); /* * Make sure there isn't already a file open with this ID. There can @@ -358,8 +342,8 @@ __dbreg_assign_id(dbp, id) */ if (__dbreg_id_to_fname(dblp, id, 1, &close_fnp) == 0) { /* - * We want to save off any dbp we have open with this id. - * We can't safely close it now, because we hold the fq_mutex, + * We want to save off any dbp we have open with this id. We + * can't safely close it now, because we hold the mtx_filelist, * but we should be able to rely on it being open in this * process, and we're running recovery, so no other thread * should muck with it if we just put off closing it until @@ -391,7 +375,9 @@ cont: if ((ret = __dbreg_pluck_id(dbenv, id)) != 0) /* Now go ahead and assign the id to our dbp. */ fnp->id = id; - fnp->is_durable = !F_ISSET(dbp, DB_AM_NOT_DURABLE); + /* If the file is durable (i.e., not, not-durable), mark it as such. */ + if (!F_ISSET(dbp, DB_AM_NOT_DURABLE)) + F_SET(fnp, DB_FNAME_DURABLE); SH_TAILQ_INSERT_HEAD(&lp->fq, fnp, q, __fname); /* @@ -402,7 +388,7 @@ cont: if ((ret = __dbreg_pluck_id(dbenv, id)) != 0) if ((ret = __dbreg_add_dbentry(dbenv, dblp, dbp, id)) != 0) (void)__dbreg_revoke_id(dbp, 1, id); -err: MUTEX_UNLOCK(dbenv, &lp->fq_mutex); +err: MUTEX_UNLOCK(dbenv, lp->mtx_filelist); /* There's nothing useful that our caller can do if this close fails. */ if (close_dbp != NULL) @@ -435,6 +421,7 @@ __dbreg_revoke_id(dbp, have_lock, force_id) dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; fnp = dbp->log_filename; + ret = 0; /* If we lack an ID, this is a null-op. */ if (fnp == NULL) @@ -447,26 +434,38 @@ __dbreg_revoke_id(dbp, have_lock, force_id) */ if (force_id != DB_LOGFILEID_INVALID) id = force_id; - else if (fnp->id == DB_LOGFILEID_INVALID) - return (0); - else + else if (fnp->id == DB_LOGFILEID_INVALID) { + if (fnp->old_id == DB_LOGFILEID_INVALID) + return (0); + id = fnp->old_id; + } else id = fnp->id; if (!have_lock) - MUTEX_LOCK(dbenv, &lp->fq_mutex); + MUTEX_LOCK(dbenv, lp->mtx_filelist); fnp->id = DB_LOGFILEID_INVALID; + fnp->old_id = DB_LOGFILEID_INVALID; /* Remove the FNAME from the list of open files. */ SH_TAILQ_REMOVE(&lp->fq, fnp, q, __fname); - /* Remove this id from the dbentry table. */ - __dbreg_rem_dbentry(dblp, id); - - /* Push this id onto the free list. */ - ret = __dbreg_push_id(dbenv, id); + /* + * Remove this id from the dbentry table and push it onto the + * free list. + */ + if ((ret = __dbreg_rem_dbentry(dblp, id)) == 0) { + /* + * If we are not in recovery but the file was opened + * for a recovery operation, then this process aborted + * a transaction for another process and the id may + * still be in use, so don't reuse this id. + */ + if (!F_ISSET(dbp, DB_AM_RECOVER) || IS_RECOVERING(dbenv)) + ret = __dbreg_push_id(dbenv, dbp, id); + } if (!have_lock) - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } @@ -483,10 +482,8 @@ __dbreg_close_id(dbp, txn, op) DB_TXN *txn; u_int32_t op; { - DBT fid_dbt, r_name, *dbtp; DB_ENV *dbenv; DB_LOG *dblp; - DB_LSN r_unused; FNAME *fnp; LOG *lp; int ret; @@ -497,10 +494,48 @@ __dbreg_close_id(dbp, txn, op) fnp = dbp->log_filename; /* If we lack an ID, this is a null-op. */ - if (fnp == NULL || fnp->id == DB_LOGFILEID_INVALID) + if (fnp == NULL) return (0); - MUTEX_LOCK(dbenv, &lp->fq_mutex); + if (fnp->id == DB_LOGFILEID_INVALID) + return (__dbreg_revoke_id(dbp, 0, DB_LOGFILEID_INVALID)); + + MUTEX_LOCK(dbenv, lp->mtx_filelist); + + if ((ret = __dbreg_log_close(dbenv, fnp, txn, op)) != 0) + goto err; + ret = __dbreg_revoke_id(dbp, 1, DB_LOGFILEID_INVALID); + +err: MUTEX_UNLOCK(dbenv, lp->mtx_filelist); + return (ret); +} + +/* + * __dbreg_log_close -- + * + * Log a close of a database. Called when closing a file or when a + * replication client is becoming a master. That closes all the + * files it previously had open. + * + * Assumes caller holds the lp->mutex_filelist lock already. + * + * PUBLIC: int __dbreg_log_close __P((DB_ENV *, FNAME *, + * PUBLIC: DB_TXN *, u_int32_t)); + */ +int +__dbreg_log_close(dbenv, fnp, txn, op) + DB_ENV *dbenv; + FNAME *fnp; + DB_TXN *txn; + u_int32_t op; +{ + DB_LOG *dblp; + DBT fid_dbt, r_name, *dbtp; + DB_LSN r_unused; + int ret; + + dblp = dbenv->lg_handle; + ret = 0; if (fnp->name_off == INVALID_ROFF) dbtp = NULL; @@ -515,14 +550,22 @@ __dbreg_close_id(dbp, txn, op) fid_dbt.data = fnp->ufid; fid_dbt.size = DB_FILE_ID_LEN; if ((ret = __dbreg_register_log(dbenv, txn, &r_unused, - F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0, + F_ISSET(fnp, DB_FNAME_DURABLE) ? 0 : DB_LOG_NOT_DURABLE, op, dbtp, &fid_dbt, fnp->id, - fnp->s_type, fnp->meta_pgno, TXN_INVALID)) != 0) - goto err; - - ret = __dbreg_revoke_id(dbp, 1, DB_LOGFILEID_INVALID); - -err: MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + fnp->s_type, fnp->meta_pgno, TXN_INVALID)) != 0) { + /* + * We are trying to close, but the log write failed. + * Unfortunately, close needs to plow forward, because + * the application can't do anything with the handle. + * Make the entry in the shared memory region so that + * when we close the environment, we know that this + * happened. Also, make sure we remove this from the + * per-process table, so that we don't try to close it + * later. + */ + F_SET(fnp, DB_FNAME_NOTLOGGED); + (void)__dbreg_rem_dbentry(dblp, fnp->id); + } return (ret); } @@ -533,15 +576,17 @@ err: MUTEX_UNLOCK(dbenv, &lp->fq_mutex); * process keeps open files in an array by ID.) Push them to the stack and * pop them from it, managing memory as appropriate. * - * The stack is protected by the fq_mutex, and in both functions we assume - * that this is already locked. + * The stack is protected by the mtx_filelist, and both functions assume it + * is already locked. */ static int -__dbreg_push_id(dbenv, id) +__dbreg_push_id(dbenv, dbp, id) DB_ENV *dbenv; + DB *dbp; int32_t id; { DB_LOG *dblp; + DB_REP *db_rep; LOG *lp; REGINFO *infop; int32_t *stack, *newstack; @@ -550,34 +595,37 @@ __dbreg_push_id(dbenv, id) dblp = dbenv->lg_handle; infop = &dblp->reginfo; lp = infop->primary; + db_rep = dbenv->rep_handle; - if (lp->free_fid_stack == INVALID_ROFF) { - stack = NULL; - DB_ASSERT(lp->free_fids_alloced == 0); - } else - stack = R_ADDR(infop, lp->free_fid_stack); - + /* + * If our fid generation in replication has changed, this fid should + * not be pushed back onto the stack. + */ + if (REP_ON(dbenv) && ((REP *)db_rep->region)->gen != dbp->fid_gen) + return (0); /* Check if we have room on the stack. */ - if (lp->free_fids_alloced <= lp->free_fids + 1) { - R_LOCK(dbenv, infop); + if (lp->free_fid_stack == INVALID_ROFF || + lp->free_fids_alloced <= lp->free_fids + 1) { + LOG_SYSTEM_LOCK(dbenv); if ((ret = __db_shalloc(infop, (lp->free_fids_alloced + 20) * sizeof(u_int32_t), 0, &newstack)) != 0) { - R_UNLOCK(dbenv, infop); + LOG_SYSTEM_UNLOCK(dbenv); return (ret); } - if (stack != NULL) { + if (lp->free_fid_stack != INVALID_ROFF) { + stack = R_ADDR(infop, lp->free_fid_stack); memcpy(newstack, stack, lp->free_fids_alloced * sizeof(u_int32_t)); __db_shalloc_free(infop, stack); } - stack = newstack; - lp->free_fid_stack = R_OFFSET(infop, stack); + lp->free_fid_stack = R_OFFSET(infop, newstack); lp->free_fids_alloced += 20; - R_UNLOCK(dbenv, infop); + LOG_SYSTEM_UNLOCK(dbenv); } + stack = R_ADDR(infop, lp->free_fid_stack); stack[lp->free_fids++] = id; return (0); } @@ -611,7 +659,7 @@ __dbreg_pop_id(dbenv, id) * be on the stack. * * Returns success whether or not the particular id was found, and like - * push and pop, assumes that the fq_mutex is locked. + * push and pop, assumes that the mtx_filelist is locked. */ static int __dbreg_pluck_id(dbenv, id) @@ -644,3 +692,73 @@ __dbreg_pluck_id(dbenv, id) return (0); } + +/* + * __dbreg_log_id -- + * Used for in-memory named files. They are created in mpool and + * are given id's early in the open process so that we can read and + * create pages in the mpool for the files. However, at the time that + * the mpf is created, the file may not be fully created and/or its + * meta-data may not be fully known, so we can't do a full dbregister. + * This is a routine exported that will log a complete dbregister + * record that will allow for both recovery and replication. + * + * PUBLIC: int __dbreg_log_id __P((DB *, DB_TXN *, int32_t, int)); + */ +int +__dbreg_log_id(dbp, txn, id, needlock) + DB *dbp; + DB_TXN *txn; + int32_t id; + int needlock; +{ + DBT fid_dbt, r_name; + DB_ENV *dbenv; + DB_LOG *dblp; + DB_LSN unused; + FNAME *fnp; + LOG *lp; + u_int32_t op; + int ret; + + dbenv = dbp->dbenv; + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + fnp = dbp->log_filename; + + /* Verify that the fnp has been initialized. */ + if (fnp->s_type == DB_UNKNOWN) { + memcpy(fnp->ufid, dbp->fileid, DB_FILE_ID_LEN); + fnp->s_type = dbp->type; + } + + /* + * Log the registry. We should only request a new ID in situations + * where logging is reasonable. + */ + memset(&fid_dbt, 0, sizeof(fid_dbt)); + memset(&r_name, 0, sizeof(r_name)); + + if (needlock) + MUTEX_LOCK(dbenv, lp->mtx_filelist); + + if (fnp->name_off != INVALID_ROFF) { + r_name.data = R_ADDR(&dblp->reginfo, fnp->name_off); + r_name.size = (u_int32_t)strlen((char *)r_name.data) + 1; + } + + fid_dbt.data = dbp->fileid; + fid_dbt.size = DB_FILE_ID_LEN; + + op = !F_ISSET(dbp, DB_AM_OPEN_CALLED) ? DBREG_PREOPEN : + (F_ISSET(dbp, DB_AM_INMEM) ? DBREG_REOPEN : DBREG_OPEN); + ret = __dbreg_register_log(dbenv, txn, &unused, + F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0, + op, r_name.size == 0 ? NULL : &r_name, &fid_dbt, id, + fnp->s_type, fnp->meta_pgno, fnp->create_txnid); + + if (needlock) + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); + + return (ret); +} diff --git a/db/dbreg/dbreg.src b/db/dbreg/dbreg.src index ff3fc2923..6f229e287 100644 --- a/db/dbreg/dbreg.src +++ b/db/dbreg/dbreg.src @@ -1,22 +1,15 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1996-2006 + * Oracle Corporation. All rights reserved. * - * $Id: dbreg.src,v 10.26 2004/06/17 17:35:17 bostic Exp $ + * $Id: dbreg.src,v 12.5 2006/08/24 14:45:31 bostic Exp $ */ PREFIX __dbreg DBPRIVATE -INCLUDE #ifndef NO_SYSTEM_INCLUDES -INCLUDE #include -INCLUDE -INCLUDE #include -INCLUDE #include -INCLUDE #endif -INCLUDE INCLUDE #include "db_int.h" INCLUDE #include "dbinc/crypto.h" INCLUDE #include "dbinc/db_page.h" @@ -35,7 +28,7 @@ INCLUDE * ftype: database type * id: transaction id of the subtransaction that created the fs object */ -BEGIN register 2 +BEGIN register 42 2 ARG opcode u_int32_t lu DBT name DBT s DBT uid DBT s diff --git a/db/dbreg/dbreg_auto.c b/db/dbreg/dbreg_auto.c index a9cc5f704..519786c14 100644 --- a/db/dbreg/dbreg_auto.c +++ b/db/dbreg/dbreg_auto.c @@ -2,13 +2,6 @@ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include - -#include -#include -#endif - #include "db_int.h" #include "dbinc/crypto.h" #include "dbinc/db_page.h" @@ -23,11 +16,11 @@ * PUBLIC: int32_t, DBTYPE, db_pgno_t, u_int32_t)); */ int -__dbreg_register_log(dbenv, txnid, ret_lsnp, flags, +__dbreg_register_log(dbenv, txnp, ret_lsnp, flags, opcode, name, uid, fileid, ftype, meta_pgno, id) DB_ENV *dbenv; - DB_TXN *txnid; + DB_TXN *txnp; DB_LSN *ret_lsnp; u_int32_t flags; u_int32_t opcode; @@ -55,29 +48,30 @@ __dbreg_register_log(dbenv, txnid, ret_lsnp, flags, ret = 0; if (LF_ISSET(DB_LOG_NOT_DURABLE)) { - if (txnid == NULL) + if (txnp == NULL) + return (0); + if (txnp == NULL) return (0); is_durable = 0; } else is_durable = 1; - if (txnid == NULL) { + if (txnp == NULL) { txn_num = 0; lsnp = &null_lsn; null_lsn.file = null_lsn.offset = 0; } else { - if (TAILQ_FIRST(&txnid->kids) != NULL && - (ret = __txn_activekids(dbenv, rectype, txnid)) != 0) + if (TAILQ_FIRST(&txnp->kids) != NULL && + (ret = __txn_activekids(dbenv, rectype, txnp)) != 0) return (ret); /* * We need to assign begin_lsn while holding region mutex. * That assignment is done inside the DbEnv->log_put call, * so pass in the appropriate memory location to be filled * in by the log_put code. - */ - DB_SET_BEGIN_LSNP(txnid, &rlsnp); - txn_num = txnid->txnid; - lsnp = &txnid->last_lsn; + */ + DB_SET_TXN_LSNP(txnp, &rlsnp, &lsnp); + txn_num = txnp->txnid; } logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN) @@ -94,7 +88,7 @@ __dbreg_register_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (is_durable || txnid == NULL) { + if (is_durable || txnp == NULL) { if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) return (ret); @@ -168,12 +162,13 @@ __dbreg_register_log(dbenv, txnid, ret_lsnp, flags, memcpy(bp, &uinttmp, sizeof(uinttmp)); bp += sizeof(uinttmp); - DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + DB_ASSERT(dbenv, + (u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); - if (is_durable || txnid == NULL) { + if (is_durable || txnp == NULL) { if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, - flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { - txnid->last_lsn = *rlsnp; + flags | DB_LOG_NOCOPY)) == 0 && txnp != NULL) { + *lsnp = *rlsnp; if (rlsnp != ret_lsnp) *ret_lsnp = *rlsnp; } @@ -192,20 +187,21 @@ __dbreg_register_log(dbenv, txnid, ret_lsnp, flags, #else ret = 0; #endif - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + STAILQ_INSERT_HEAD(&txnp->logs, lr, links); + F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); LSN_NOT_LOGGED(*ret_lsnp); } #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__dbreg_register_print(dbenv, - (DBT *)&logrec, ret_lsnp, NULL, NULL); + (DBT *)&logrec, ret_lsnp, DB_TXN_PRINT, NULL); #endif #ifdef DIAGNOSTIC __os_free(dbenv, logrec.data); #else - if (is_durable || txnid == NULL) + if (is_durable || txnp == NULL) __os_free(dbenv, logrec.data); #endif return (ret); @@ -230,13 +226,14 @@ __dbreg_register_read(dbenv, recbuf, argpp) sizeof(__dbreg_register_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); bp = recbuf; - argp->txnid = (DB_TXN *)&argp[1]; + argp->txnp = (DB_TXN *)&argp[1]; + memset(argp->txnp, 0, sizeof(DB_TXN)); memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); - memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid)); - bp += sizeof(argp->txnid->txnid); + memcpy(&argp->txnp->txnid, bp, sizeof(argp->txnp->txnid)); + bp += sizeof(argp->txnp->txnid); memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN)); bp += sizeof(DB_LSN); diff --git a/db/dbreg/dbreg_autop.c b/db/dbreg/dbreg_autop.c index 3889b357d..b2e12e2d4 100644 --- a/db/dbreg/dbreg_autop.c +++ b/db/dbreg/dbreg_autop.c @@ -2,13 +2,6 @@ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include - -#include -#include -#endif - #include "db_int.h" #include "dbinc/crypto.h" #include "dbinc/db_page.h" @@ -34,20 +27,18 @@ __dbreg_register_print(dbenv, dbtp, lsnp, notused2, notused3) int ch; int ret; - notused2 = DB_TXN_ABORT; + notused2 = DB_TXN_PRINT; notused3 = NULL; if ((ret = __dbreg_register_read(dbenv, dbtp->data, &argp)) != 0) return (ret); (void)printf( - "[%lu][%lu]__dbreg_register%s: rec: %lu txnid %lx prevlsn [%lu][%lu]\n", - (u_long)lsnp->file, - (u_long)lsnp->offset, + "[%lu][%lu]__dbreg_register%s: rec: %lu txnp %lx prevlsn [%lu][%lu]\n", + (u_long)lsnp->file, (u_long)lsnp->offset, (argp->type & DB_debug_FLAG) ? "_debug" : "", (u_long)argp->type, - (u_long)argp->txnid->txnid, - (u_long)argp->prev_lsn.file, - (u_long)argp->prev_lsn.offset); + (u_long)argp->txnp->txnid, + (u_long)argp->prev_lsn.file, (u_long)argp->prev_lsn.offset); (void)printf("\topcode: %lu\n", (u_long)argp->opcode); (void)printf("\tname: "); for (i = 0; i < argp->name.size; i++) { diff --git a/db/dbreg/dbreg_rec.c b/db/dbreg/dbreg_rec.c index 07b175a1f..180239842 100644 --- a/db/dbreg/dbreg_rec.c +++ b/db/dbreg/dbreg_rec.c @@ -1,8 +1,8 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1996-2006 + * Oracle Corporation. All rights reserved. */ /* * Copyright (c) 1995, 1996 @@ -32,23 +32,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: dbreg_rec.c,v 11.133 2004/09/24 00:43:18 bostic Exp $ + * $Id: dbreg_rec.c,v 12.17 2006/09/07 20:05:28 bostic Exp $ */ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include - -#include -#endif - #include "db_int.h" #include "dbinc/db_page.h" -#include "dbinc/db_shash.h" #include "dbinc/db_am.h" #include "dbinc/log.h" -#include "dbinc/mp.h" #include "dbinc/txn.h" static int __dbreg_open_file __P((DB_ENV *, @@ -84,11 +76,19 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) goto out; switch (argp->opcode) { + case DBREG_REOPEN: + case DBREG_PREOPEN: case DBREG_OPEN: + /* + * In general, we redo the open on REDO and abort on UNDO. + * However, a reopen is a second instance of an open of + * in-memory files and we don't want to close them yet + * on abort, so just skip that here. + */ if ((DB_REDO(op) || op == DB_TXN_OPENFILES || op == DB_TXN_POPENFILES)) do_open = 1; - else + else if (argp->opcode != DBREG_REOPEN) do_close = 1; break; case DBREG_CLOSE: @@ -117,9 +117,8 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) do_open = 1; break; default: - DB_ASSERT(0); - ret = EINVAL; - break; + ret = __db_unknown_path(dbenv, "__dbreg_register_recover"); + goto out; } if (do_open) { @@ -137,7 +136,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) */ ret = __dbreg_open_file(dbenv, op == DB_TXN_ABORT || op == DB_TXN_POPENFILES ? - argp->txnid : NULL, argp, info); + argp->txnp : NULL, argp, info); if (ret == DB_PAGE_NOTFOUND && argp->meta_pgno != PGNO_BASE_MD) ret = ENOENT; if (ret == ENOENT || ret == EINVAL) { @@ -149,7 +148,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) * for that case and possibly retry. */ if (op == DB_TXN_FORWARD_ROLL && - argp->txnid != 0 && + argp->txnp != 0 && dblp->dbentry[argp->fileid].deleted) { dblp->dbentry[argp->fileid].deleted = 0; ret = @@ -172,7 +171,9 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) if (do_close) { /* * If we are undoing an open, or redoing a close, - * then we need to close the file. + * then we need to close the file. If we are simply + * revoking then we just need to grab the DBP and revoke + * the log id. * * If the file is deleted, then we can just ignore this close. * Otherwise, we should usually have a valid dbp we should @@ -181,7 +182,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) * fact, not have the file open, and that's OK. */ do_rem = 0; - MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); if (argp->fileid < dblp->dbentry_cnt) { /* * Typically, closes should match an open which means @@ -205,13 +206,12 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) if ((DB_REDO(op) && argp->opcode != DBREG_RCLOSE) || argp->opcode == DBREG_CHKPNT) { - __db_err(dbenv, - "Improper file close at %lu/%lu", + __db_errx(dbenv, + "Warning: Improper file close at %lu/%lu", (u_long)lsnp->file, (u_long)lsnp->offset); - ret = EINVAL; } - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); goto done; } @@ -228,7 +228,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) */ do_rem = F_ISSET(dbp, DB_AM_RECOVER) || op == DB_TXN_ABORT; - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); if (op == DB_TXN_ABORT) (void)__dbreg_close_id(dbp, NULL, DBREG_RCLOSE); @@ -236,11 +236,13 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) (void)__dbreg_revoke_id(dbp, 0, DB_LOGFILEID_INVALID); } else if (dbe->deleted) { - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); - __dbreg_rem_dbentry(dblp, argp->fileid); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); + if ((ret = __dbreg_rem_dbentry( + dblp, argp->fileid)) != 0) + goto out; } } else - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); /* * During recovery, all files are closed. On an abort, we only @@ -262,7 +264,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) if (do_rem && dbp != NULL) { if (argp->id != TXN_INVALID) { if ((ret = __db_txnlist_find(dbenv, - info, argp->txnid->txnid, &status)) + info, argp->txnp->txnid, &status)) != DB_NOTFOUND && ret != 0) goto out; if (ret == DB_NOTFOUND || status != TXN_COMMIT) @@ -273,7 +275,7 @@ __dbreg_register_recover(dbenv, dbtp, lsnp, op, info) if (op == DB_TXN_ABORT && !F_ISSET(dbp, DB_AM_RECOVER)) { if ((t_ret = __db_refresh(dbp, - NULL, DB_NOSYNC, NULL)) != 0 && ret == 0) + NULL, DB_NOSYNC, NULL, 0)) != 0 && ret == 0) ret = t_ret; } else { if (op == DB_TXN_APPLY && @@ -311,27 +313,29 @@ __dbreg_open_file(dbenv, txn, argp, info) u_int32_t id, status; int ret; - dblp = (DB_LOG *)dbenv->lg_handle; + dblp = dbenv->lg_handle; /* * 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, dblp->mutexp); - if (argp->fileid < dblp->dbentry_cnt) + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); + if (argp->fileid != DB_LOGFILEID_INVALID && + argp->fileid < dblp->dbentry_cnt) dbe = &dblp->dbentry[argp->fileid]; else dbe = NULL; if (dbe != NULL) { if (dbe->deleted) { - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); return (ENOENT); } /* - * At the end of OPENFILES, we may have a file open. The + * At the end of OPENFILES, we may have a file open. If this + * is a reopen, then we will always close and reopen. If the * open was part of a committed transaction, so it doesn't * get undone. However, if the fileid was previously used, * we'll see a close that may need to get undone. There are @@ -342,11 +346,12 @@ __dbreg_open_file(dbenv, txn, argp, info) * which case it should never be opened during recovery. */ if ((dbp = dbe->dbp) != NULL) { - if (dbp->meta_pgno != argp->meta_pgno || + if (argp->opcode == DBREG_REOPEN || + dbp->meta_pgno != argp->meta_pgno || argp->name.size == 0 || memcmp(dbp->fileid, argp->uid.data, DB_FILE_ID_LEN) != 0) { - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); (void)__dbreg_revoke_id(dbp, 0, DB_LOGFILEID_INVALID); if (F_ISSET(dbp, DB_AM_RECOVER)) @@ -359,8 +364,8 @@ __dbreg_open_file(dbenv, txn, argp, info) * 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, dblp->mutexp); + DB_ASSERT(dbenv, dbe->dbp == dbp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); /* * This is a successful open. We need to record that @@ -375,7 +380,7 @@ __dbreg_open_file(dbenv, txn, argp, info) } } - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); reopen: /* @@ -402,6 +407,6 @@ reopen: } return (__dbreg_do_open(dbenv, - txn, dblp, argp->uid.data, argp->name.data, - argp->ftype, argp->fileid, argp->meta_pgno, info, argp->id)); + txn, dblp, argp->uid.data, argp->name.data, argp->ftype, + argp->fileid, argp->meta_pgno, info, argp->id, argp->opcode)); } diff --git a/db/dbreg/dbreg_stat.c b/db/dbreg/dbreg_stat.c index dd53b77c3..c19adc688 100644 --- a/db/dbreg/dbreg_stat.c +++ b/db/dbreg/dbreg_stat.c @@ -1,19 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1997-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1997-2006 + * Oracle Corporation. All rights reserved. * - * $Id: dbreg_stat.c,v 11.48 2004/10/15 16:59:41 bostic Exp $ + * $Id: dbreg_stat.c,v 12.9 2006/08/24 14:45:32 bostic Exp $ */ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include -#include -#endif - #include "db_int.h" #include "dbinc/db_page.h" #include "dbinc/db_am.h" @@ -21,6 +16,28 @@ #include "dbinc/txn.h" #ifdef HAVE_STATISTICS +static int __dbreg_print_dblist __P((DB_ENV *, u_int32_t)); + +/* + * __dbreg_stat_print -- + * Print the dbreg statistics. + * + * PUBLIC: int __dbreg_stat_print __P((DB_ENV *, u_int32_t)); + */ +int +__dbreg_stat_print(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + int ret; + + if (LF_ISSET(DB_STAT_ALL) && + (ret = __dbreg_print_dblist(dbenv, flags)) != 0) + return (ret); + + return (0); +} + /* * __dbreg_print_fname -- * Display the contents of an FNAME structure. @@ -32,22 +49,26 @@ __dbreg_print_fname(dbenv, fnp) DB_ENV *dbenv; FNAME *fnp; { + static const FN fn[] = { + { DB_FNAME_DURABLE, "DB_FNAME_DURABLE" }, + { DB_FNAME_NOTLOGGED, "DB_FNAME_NOTLOGGED" }, + { 0, NULL } + }; + __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); __db_msg(dbenv, "DB handle FNAME contents:"); STAT_LONG("log ID", fnp->id); STAT_ULONG("Meta pgno", fnp->meta_pgno); __db_print_fileid(dbenv, fnp->ufid, "\tFile ID"); STAT_ULONG("create txn", fnp->create_txnid); - STAT_LONG("durable", fnp->is_durable); + __db_prflags(dbenv, NULL, fnp->flags, fn, NULL, "\tFlags"); } /* * __dbreg_print_dblist -- * Display the DB_ENV's list of files. - * - * PUBLIC: void __dbreg_print_dblist __P((DB_ENV *, u_int32_t)); */ -void +static int __dbreg_print_dblist(dbenv, flags) DB_ENV *dbenv; u_int32_t flags; @@ -64,13 +85,14 @@ __dbreg_print_dblist(dbenv, flags) __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); __db_msg(dbenv, "LOG FNAME list:"); - __db_print_mutex(dbenv, NULL, &lp->fq_mutex, "File name mutex", flags); + __mutex_print_debug_single( + dbenv, "File name mutex", lp->mtx_filelist, flags); STAT_LONG("Fid max", lp->fid_max); - MUTEX_LOCK(dbenv, &lp->fq_mutex); - for (first = 1, fnp = SH_TAILQ_FIRST(&lp->fq, __fname); - fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + MUTEX_LOCK(dbenv, lp->mtx_filelist); + first = 1; + SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) { if (first) { first = 0; __db_msg(dbenv, @@ -92,6 +114,8 @@ __dbreg_print_dblist(dbenv, flags) dbp == NULL ? "No DBP" : "DBP", del, P_TO_ULONG(dbp), (u_long)(dbp == NULL ? 0 : dbp->flags)); } - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); + + return (0); } #endif diff --git a/db/dbreg/dbreg_util.c b/db/dbreg/dbreg_util.c index 6f1cc9297..5037810c1 100644 --- a/db/dbreg/dbreg_util.c +++ b/db/dbreg/dbreg_util.c @@ -1,23 +1,20 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1997-2004 - * Sleepycat Software. All rights reserved. + * Copyright (c) 1997-2006 + * Oracle Corporation. All rights reserved. * - * $Id: dbreg_util.c,v 11.50 2004/10/15 16:59:41 bostic Exp $ + * $Id: dbreg_util.c,v 12.20 2006/09/09 14:28:22 bostic Exp $ */ #include "db_config.h" -#ifndef NO_SYSTEM_INCLUDES -#include -#include -#endif - #include "db_int.h" #include "dbinc/db_page.h" #include "dbinc/db_am.h" +#include "dbinc/fop.h" #include "dbinc/log.h" +#include "dbinc/mp.h" #include "dbinc/txn.h" static int __dbreg_check_master __P((DB_ENV *, u_int8_t *, char *)); @@ -40,7 +37,7 @@ __dbreg_add_dbentry(dbenv, dblp, dbp, ndx) ret = 0; - MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); /* * Check if we need to grow the table. Note, ndx is 0-based (the @@ -61,11 +58,11 @@ __dbreg_add_dbentry(dbenv, dblp, dbp, ndx) dblp->dbentry_cnt = i; } - DB_ASSERT(dblp->dbentry[ndx].dbp == NULL); + DB_ASSERT(dbenv, dblp->dbentry[ndx].dbp == NULL); dblp->dbentry[ndx].deleted = dbp == NULL; dblp->dbentry[ndx].dbp = dbp; -err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); +err: MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); return (ret); } @@ -73,19 +70,21 @@ err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); * __dbreg_rem_dbentry * Remove an entry from the DB entry table. * - * PUBLIC: void __dbreg_rem_dbentry __P((DB_LOG *, int32_t)); + * PUBLIC: int __dbreg_rem_dbentry __P((DB_LOG *, int32_t)); */ -void +int __dbreg_rem_dbentry(dblp, ndx) DB_LOG *dblp; int32_t ndx; { - MUTEX_THREAD_LOCK(dblp->dbenv, dblp->mutexp); + MUTEX_LOCK(dblp->dbenv, dblp->mtx_dbreg); if (dblp->dbentry_cnt > ndx) { dblp->dbentry[ndx].dbp = NULL; dblp->dbentry[ndx].deleted = 0; } - MUTEX_THREAD_UNLOCK(dblp->dbenv, dblp->mutexp); + MUTEX_UNLOCK(dblp->dbenv, dblp->mtx_dbreg); + + return (0); } /* @@ -110,11 +109,12 @@ __dbreg_log_files(dbenv) ret = 0; - MUTEX_LOCK(dbenv, &lp->fq_mutex); - - for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); - fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + MUTEX_LOCK(dbenv, lp->mtx_filelist); + SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) { + /* This id was revoked by a switch in replication master. */ + if (fnp->id == DB_LOGFILEID_INVALID) + continue; if (fnp->name_off == INVALID_ROFF) dbtp = NULL; else { @@ -136,14 +136,14 @@ __dbreg_log_files(dbenv) */ if ((ret = __dbreg_register_log(dbenv, NULL, &r_unused, - fnp->is_durable ? 0 : DB_LOG_NOT_DURABLE, + F_ISSET(fnp, DB_FNAME_DURABLE) ? 0 : DB_LOG_NOT_DURABLE, F_ISSET(dblp, DBLOG_RECOVER) ? DBREG_RCLOSE : DBREG_CHKPNT, dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno, TXN_INVALID)) != 0) break; } - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } @@ -173,7 +173,8 @@ __dbreg_close_files(dbenv) dblp = dbenv->lg_handle; ret = 0; - MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); + + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); for (i = 0; i < dblp->dbentry_cnt; i++) { /* * We only want to close dbps that recovery opened. Any @@ -182,6 +183,12 @@ __dbreg_close_files(dbenv) * Before doing so, we need to revoke their log fileids * so that we don't end up leaving around FNAME entries * for dbps that shouldn't have them. + * + * Any FNAME entries that were marked NOTLOGGED had the + * log write fail while they were being closed. Since it's + * too late to be logging now we flag that as a failure + * so recovery will be run. This will get returned by + * __dbreg_revoke_id. */ if ((dbp = dblp->dbentry[i].dbp) != NULL) { /* @@ -195,7 +202,7 @@ __dbreg_close_files(dbenv) * we're in this loop anyway--we're in the process of * making all outstanding dbps invalid. */ - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); if (F_ISSET(dbp, DB_AM_RECOVER)) t_ret = __db_close(dbp, NULL, dbp->mpf == NULL ? DB_NOSYNC : 0); @@ -204,13 +211,52 @@ __dbreg_close_files(dbenv) dbp, 0, DB_LOGFILEID_INVALID); if (ret == 0) ret = t_ret; - MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); } dblp->dbentry[i].deleted = 0; dblp->dbentry[i].dbp = NULL; } - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); + return (ret); +} + +/* + * __dbreg_invalidate_files -- + * Invalidate files when we change replication roles. Save the + * id so that another process will be able to clean up the information + * when it notices. + * + * PUBLIC: int __dbreg_invalidate_files __P((DB_ENV *)); + */ +int +__dbreg_invalidate_files(dbenv) + DB_ENV *dbenv; +{ + DB_LOG *dblp; + FNAME *fnp; + LOG *lp; + int ret; + + /* If we haven't initialized logging, we have nothing to do. */ + if (!LOGGING_ON(dbenv)) + return (0); + + dblp = dbenv->lg_handle; + lp = dblp->reginfo.primary; + + ret = 0; + MUTEX_LOCK(dbenv, lp->mtx_filelist); + SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) { + if (fnp->id != DB_LOGFILEID_INVALID) { + if ((ret = __dbreg_log_close(dbenv, + fnp, NULL, DBREG_RCLOSE)) != 0) + goto err; + fnp->old_id = fnp->id; + fnp->id = DB_LOGFILEID_INVALID; + } + } +err: MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } @@ -261,7 +307,7 @@ __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) dblp = dbenv->lg_handle; COMPQUIET(inc, 0); - MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); + MUTEX_LOCK(dbenv, dblp->mtx_dbreg); /* * Under XA, a process different than the one issuing DB operations @@ -277,12 +323,12 @@ __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) } /* - * __dbreg_id_to_fname acquires the region's fq_mutex, - * which we can't safely acquire while we hold the thread lock. - * We no longer need it anyway--the dbentry table didn't - * have what we needed. + * __dbreg_id_to_fname acquires the mtx_filelist mutex, which + * we can't safely acquire while we hold the thread lock. We + * no longer need it anyway--the dbentry table didn't have what + * we needed. */ - MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); + MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0) /* @@ -294,11 +340,11 @@ __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) return (ENOENT); /* - * Note that we're relying on fname not to change, even - * though we released the mutex that protects it (fq_mutex) - * inside __dbreg_id_to_fname. This should be a safe - * assumption, because the other process that has the file - * open shouldn't be closing it while we're trying to abort. + * Note that we're relying on fname not to change, even though + * we released the mutex that protects it (mtx_filelist) inside + * __dbreg_id_to_fname. This should be a safe assumption, the + * other process that has the file open shouldn't be closing it + * while we're trying to abort. */ name = R_ADDR(&dblp->reginfo, fname->name_off); @@ -313,7 +359,7 @@ __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) */ if ((ret = __dbreg_do_open(dbenv, txn, dblp, fname->ufid, name, fname->s_type, - ndx, fname->meta_pgno, NULL, 0)) != 0) + ndx, fname->meta_pgno, NULL, 0, DBREG_OPEN)) != 0) return (ret); *dbpp = dblp->dbentry[ndx].dbp; @@ -331,8 +377,20 @@ __dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen) /* It's an error if we don't have a corresponding writeable DB. */ if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL) ret = ENOENT; + else + /* + * If we are in recovery, then set that the file has + * been written. It is possible to run recovery, + * find all the pages in their post update state + * in the OS buffer pool, put a checkpoint in the log + * and then crash the system without forcing the pages + * to disk. If this is an in-memory file, we may not have + * an mpf yet. + */ + if ((*dbpp)->mpf != NULL && (*dbpp)->mpf->mfp != NULL) + (*dbpp)->mpf->mfp->file_written = 1; -err: MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); +err: MUTEX_UNLOCK(dbenv, dblp->mtx_dbreg); return (ret); } @@ -361,17 +419,15 @@ __dbreg_id_to_fname(dblp, id, have_lock, fnamep) ret = -1; if (!have_lock) - MUTEX_LOCK(dbenv, &lp->fq_mutex); - for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); - fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + MUTEX_LOCK(dbenv, lp->mtx_filelist); + SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) if (fnp->id == id) { *fnamep = fnp; ret = 0; break; } - } if (!have_lock) - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } @@ -400,17 +456,15 @@ __dbreg_fid_to_fname(dblp, fid, have_lock, fnamep) ret = -1; if (!have_lock) - MUTEX_LOCK(dbenv, &lp->fq_mutex); - for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname); - fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) { + MUTEX_LOCK(dbenv, lp->mtx_filelist); + SH_TAILQ_FOREACH(fnp, &lp->fq, q, __fname) if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) { *fnamep = fnp; ret = 0; break; } - } if (!have_lock) - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } @@ -448,11 +502,12 @@ __dbreg_get_name(dbenv, fid, namep) * Open files referenced in the log. This is the part of the open that * is not protected by the thread mutex. * PUBLIC: int __dbreg_do_open __P((DB_ENV *, DB_TXN *, DB_LOG *, u_int8_t *, - * PUBLIC: char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t)); + * PUBLIC: char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t, + * PUBLIC: u_int32_t)); */ int __dbreg_do_open(dbenv, - txn, lp, uid, name, ftype, ndx, meta_pgno, info, id) + txn, lp, uid, name, ftype, ndx, meta_pgno, info, id, opcode) DB_ENV *dbenv; DB_TXN *txn; DB_LOG *lp; @@ -462,12 +517,16 @@ __dbreg_do_open(dbenv, int32_t ndx; db_pgno_t meta_pgno; void *info; - u_int32_t id; + u_int32_t id, opcode; { DB *dbp; u_int32_t cstat, ret_stat; int ret; + char *dname, *fname; + cstat = TXN_EXPECTED; + fname = name; + dname = NULL; if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0) return (ret); @@ -490,9 +549,24 @@ __dbreg_do_open(dbenv, memcpy(dbp->fileid, uid, DB_FILE_ID_LEN); dbp->meta_pgno = meta_pgno; } - if ((ret = __db_open(dbp, txn, name, NULL, - ftype, DB_ODDFILESIZE, __db_omode("rw----"), meta_pgno)) == 0) { + if (opcode == DBREG_PREOPEN) { + dbp->type = ftype; + if ((ret = __dbreg_setup(dbp, name, id)) != 0) + goto err; + MAKE_INMEM(dbp); + goto skip_open; + } + + if (opcode == DBREG_REOPEN) { + MAKE_INMEM(dbp); + fname = NULL; + dname = name; + } + if ((ret = __db_open(dbp, txn, fname, dname, ftype, + DB_DURABLE_UNKNOWN | DB_ODDFILESIZE, + __db_omode(OWNER_RW), meta_pgno)) == 0) { +skip_open: /* * Verify that we are opening the same file that we were * referring to when we wrote this log record. @@ -500,7 +574,7 @@ __dbreg_do_open(dbenv, if ((meta_pgno != PGNO_BASE_MD && __dbreg_check_master(dbenv, uid, name) != 0) || memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) - cstat = TXN_IGNORE; + cstat = TXN_UNEXPECTED; else cstat = TXN_EXPECTED; @@ -518,7 +592,7 @@ __dbreg_do_open(dbenv, ret = __db_txnlist_update(dbenv, info, id, cstat, NULL, &ret_stat, 1); -err: if (cstat == TXN_IGNORE) +err: if (cstat == TXN_UNEXPECTED) goto not_right; return (ret); } else if (ret == ENOENT) { @@ -547,8 +621,8 @@ __dbreg_check_master(dbenv, uid, name) if ((ret = db_create(&dbp, dbenv, 0)) != 0) return (ret); F_SET(dbp, DB_AM_RECOVER); - ret = __db_open(dbp, - NULL, name, NULL, DB_BTREE, 0, __db_omode("rw----"), PGNO_BASE_MD); + ret = __db_open(dbp, NULL, + name, NULL, DB_BTREE, 0, __db_omode(OWNER_RW), PGNO_BASE_MD); if (ret == 0 && memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0) ret = EINVAL; @@ -569,6 +643,10 @@ __dbreg_check_master(dbenv, uid, name) * at this point we have no way of knowing whether the log record that incited * us to call this will be part of a committed transaction. * + * We first revoke any old id this handle may have had. That can happen + * if a master becomes a client and then becomes a master again and + * there are other processes with valid open handles to this env. + * * PUBLIC: int __dbreg_lazy_id __P((DB *)); */ int @@ -585,20 +663,28 @@ __dbreg_lazy_id(dbp) dbenv = dbp->dbenv; - DB_ASSERT(IS_REP_MASTER(dbenv)); + DB_ASSERT(dbenv, IS_REP_MASTER(dbenv)); dbenv = dbp->dbenv; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; fnp = dbp->log_filename; - /* The fq_mutex protects the FNAME list and id management. */ - MUTEX_LOCK(dbenv, &lp->fq_mutex); + /* The mtx_filelist protects the FNAME list and id management. */ + MUTEX_LOCK(dbenv, lp->mtx_filelist); if (fnp->id != DB_LOGFILEID_INVALID) { - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (0); } id = DB_LOGFILEID_INVALID; + /* + * When we became master we moved the fnp->id to old_id in + * every FNAME structure that was open. If our id was changed, + * we need to revoke and give back that id. + */ + if (fnp->old_id != DB_LOGFILEID_INVALID && + (ret = __dbreg_revoke_id(dbp, 1, DB_LOGFILEID_INVALID)) != 0) + goto err; if ((ret = __txn_begin(dbenv, NULL, &txn, 0)) != 0) goto err; @@ -612,7 +698,7 @@ __dbreg_lazy_id(dbp) /* * All DB related logging routines check the id value *without* - * holding the fq_mutex to know whether we need to call + * holding the mtx_filelist to know whether we need to call * dbreg_lazy_id to begin with. We must set the ID after a * *successful* commit so that there is no possibility of a second * modification call finding a valid ID in the dbp before the @@ -624,6 +710,6 @@ __dbreg_lazy_id(dbp) err: if (ret != 0 && id != DB_LOGFILEID_INVALID) (void)__dbreg_revoke_id(dbp, 1, id); - MUTEX_UNLOCK(dbenv, &lp->fq_mutex); + MUTEX_UNLOCK(dbenv, lp->mtx_filelist); return (ret); } -- cgit v1.2.3