diff options
author | jbj <devnull@localhost> | 2004-10-16 01:31:54 +0000 |
---|---|---|
committer | jbj <devnull@localhost> | 2004-10-16 01:31:54 +0000 |
commit | d03f220fde879509cab2ac1c73b71b7efb52b737 (patch) | |
tree | 1e34bfadac0a6618d0e9a7933bad90063a785acf /db/txn | |
parent | 2dc699bfe049b9319ea3719f604d25940ff52004 (diff) | |
download | librpm-tizen-d03f220fde879509cab2ac1c73b71b7efb52b737.tar.gz librpm-tizen-d03f220fde879509cab2ac1c73b71b7efb52b737.tar.bz2 librpm-tizen-d03f220fde879509cab2ac1c73b71b7efb52b737.zip |
... and in with the New ...
CVS patchset: 7471
CVS date: 2004/10/16 01:31:54
Diffstat (limited to 'db/txn')
-rw-r--r-- | db/txn/txn.c | 230 | ||||
-rw-r--r-- | db/txn/txn.src | 19 | ||||
-rw-r--r-- | db/txn/txn_auto.c | 954 | ||||
-rw-r--r-- | db/txn/txn_autop.c | 281 | ||||
-rw-r--r-- | db/txn/txn_method.c | 25 | ||||
-rw-r--r-- | db/txn/txn_rec.c | 158 | ||||
-rw-r--r-- | db/txn/txn_recover.c | 162 | ||||
-rw-r--r-- | db/txn/txn_region.c | 91 | ||||
-rw-r--r-- | db/txn/txn_stat.c | 315 | ||||
-rw-r--r-- | db/txn/txn_util.c | 16 |
10 files changed, 1259 insertions, 992 deletions
diff --git a/db/txn/txn.c b/db/txn/txn.c index 937046fa8..94755318b 100644 --- a/db/txn/txn.c +++ b/db/txn/txn.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. */ /* @@ -34,14 +34,12 @@ * 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. + * + * $Id: txn.c,v 11.248 2004/09/23 15:02:32 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn.c,v 11.219 2003/12/03 14:33:06 bostic Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> #include <stdlib.h> @@ -106,6 +104,7 @@ static int __txn_isvalid __P((const DB_TXN *, TXN_DETAIL **, txnop_t)); static int __txn_undo __P((DB_TXN *)); static int __txn_dispatch_undo __P((DB_ENV *, DB_TXN *, DBT *, DB_LSN *, void *)); +static void __txn_set_begin_lsnp __P((DB_TXN *txn, DB_LSN **)); /* * __txn_begin_pp -- @@ -126,7 +125,7 @@ __txn_begin_pp(dbenv, parent, txnpp, flags) if ((ret = __db_fchk(dbenv, "txn_begin", flags, - DB_DIRTY_READ | DB_TXN_NOWAIT | + DB_DEGREE_2 | DB_DIRTY_READ | DB_TXN_NOWAIT | DB_TXN_NOSYNC | DB_TXN_SYNC)) != 0) return (ret); if ((ret = __db_fcchk(dbenv, @@ -185,6 +184,8 @@ __txn_begin(dbenv, parent, txnpp, flags) TAILQ_INIT(&txn->events); STAILQ_INIT(&txn->logs); txn->flags = TXN_MALLOC; + if (LF_ISSET(DB_DEGREE_2)) + F_SET(txn, TXN_DEGREE_2); if (LF_ISSET(DB_DIRTY_READ)) F_SET(txn, TXN_DIRTY_READ); if (LF_ISSET(DB_TXN_NOSYNC)) @@ -246,9 +247,8 @@ __txn_xa_begin(dbenv, txn) PANIC_CHECK(dbenv); /* - * We need to initialize the transaction structure, but we must - * be careful not to smash the links. We manually intialize the - * structure. + * We need to initialize the transaction structure, but must be careful + * not to smash the links. We manually initialize the structure. */ txn->mgrp = dbenv->tx_handle; TAILQ_INIT(&txn->kids); @@ -306,7 +306,7 @@ __txn_begin_int(txn, internal) int internal; { DB_ENV *dbenv; - DB_LSN begin_lsn, null_lsn; + DB_LSN null_lsn; DB_TXNMGR *mgr; DB_TXNREGION *region; TXN_DETAIL *td; @@ -318,21 +318,6 @@ __txn_begin_int(txn, internal) dbenv = mgr->dbenv; region = mgr->reginfo.primary; - /* - * We do not have to write begin records (and if we do not, then we - * need never write records for read-only transactions). However, - * we do need to find the current LSN so that we can store it in the - * transaction structure, so we can know where to take checkpoints. - * - * XXX - * We should set this value when we write the first log record, not - * here. - */ - if (DBENV_LOGGING(dbenv)) - __log_txn_lsn(dbenv, &begin_lsn, NULL, NULL); - else - ZERO_LSN(begin_lsn); - R_LOCK(dbenv, &mgr->reginfo); if (!F_ISSET(txn, TXN_COMPENSATE) && F_ISSET(region, TXN_IN_RECOVERY)) { __db_err(dbenv, "operation not permitted during recovery"); @@ -372,14 +357,14 @@ __txn_begin_int(txn, internal) ®ion->last_txnid, ®ion->cur_maxid); __os_free(dbenv, ids); if (DBENV_LOGGING(dbenv) && - (ret = __txn_recycle_log(dbenv, NULL, - &null_lsn, 0, region->last_txnid, region->cur_maxid)) != 0) + (ret = __txn_recycle_log(dbenv, NULL, &null_lsn, + 0, region->last_txnid + 1, region->cur_maxid)) != 0) goto err; } /* Allocate a new transaction detail structure. */ if ((ret = - __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) { + __db_shalloc(&mgr->reginfo, sizeof(TXN_DETAIL), 0, &td)) != 0) { __db_err(dbenv, "Unable to allocate memory for transaction detail"); goto err; @@ -395,7 +380,7 @@ __txn_begin_int(txn, internal) td->txnid = id; ZERO_LSN(td->last_lsn); - td->begin_lsn = begin_lsn; + ZERO_LSN(td->begin_lsn); if (txn->parent != NULL) td->parent = txn->parent->off; else @@ -404,7 +389,7 @@ __txn_begin_int(txn, internal) td->flags = 0; td->xa_status = 0; - off = R_OFFSET(&mgr->reginfo, td); + off = R_OFFSET(dbenv, &mgr->reginfo, td); R_UNLOCK(dbenv, &mgr->reginfo); ZERO_LSN(txn->last_lsn); @@ -417,6 +402,7 @@ __txn_begin_int(txn, internal) txn->id = __txn_id; txn->prepare = __txn_prepare; txn->set_timeout = __txn_set_timeout; + txn->set_begin_lsnp = __txn_set_begin_lsnp; /* * If this is a transaction family, we must link the child to the @@ -586,19 +572,20 @@ __txn_commit(txnp, flags) } /* - * Process any aborted pages from our children. - * We delay putting pages on the free list that are newly - * allocated and then aborted so that we can undo other - * allocations, if necessary, without worrying about - * these pages which were not on the free list before. + * Process any aborted pages from our children. We delay putting pages + * on the free list that are newly allocated and then aborted so we can + * undo other allocations, if necessary, without worrying about these + * pages which were not on the free list before. */ if (txnp->txn_list != NULL) { +#ifndef HAVE_FTRUNCATE t_ret = __db_do_the_limbo(dbenv, NULL, txnp, txnp->txn_list, LIMBO_NORMAL); - __db_txnlist_end(dbenv, txnp->txn_list); - txnp->txn_list = NULL; if (t_ret != 0 && ret == 0) ret = t_ret; +#endif + __db_txnlist_end(dbenv, txnp->txn_list); + txnp->txn_list = NULL; } if (ret != 0) @@ -608,13 +595,12 @@ __txn_commit(txnp, flags) return (__txn_end(txnp, 1)); err: /* - * If we are prepared, then we "must" be able to commit. We - * panic here because even though the coordinator might be - * able to retry it is not clear it would know to do that. - * Otherwise we'll try to abort. If that is successful, - * then we return whatever was in ret (i.e., the reason we failed). - * If the abort was unsuccessful, then abort probably returned - * DB_RUNRECOVERY and we need to propagate that up. + * If we are prepared, then we "must" be able to commit. We panic here + * because even though the coordinator might be able to retry it is not + * clear it would know to do that. Otherwise we'll try to abort. If + * that is successful, then we return whatever was in ret (that is, the + * reason we failed). If the abort was unsuccessful, abort probably + * returned DB_RUNRECOVERY and we need to propagate that up. */ if (td->status == TXN_PREPARED) return (__db_panic(dbenv, ret)); @@ -702,7 +688,7 @@ __txn_abort(txnp) request.op = DB_LOCK_UPGRADE_WRITE; request.obj = NULL; if ((ret = __lock_vec( - dbenv, txnp->txnid, 0, &request, 1, NULL)) != 0) + dbenv, txnp->txnid, DB_LOCK_ABORT, &request, 1, NULL)) != 0) return (__db_panic(dbenv, ret)); } if ((ret = __txn_undo(txnp)) != 0) @@ -818,10 +804,12 @@ __txn_prepare(txnp, gid) if ((ret = __txn_commit(kid, DB_TXN_NOSYNC)) != 0) return (ret); +#ifndef HAVE_FTRUNCATE if (txnp->txn_list != NULL && (ret = __db_do_the_limbo(dbenv, NULL, txnp, txnp->txn_list, LIMBO_PREPARE)) != 0) return (ret); +#endif /* * In XA, the global transaction ID in the txn_detail structure is * already set; in a non-XA environment, we must set it here. XA @@ -866,7 +854,7 @@ __txn_prepare(txnp, gid) __os_free(dbenv, request.obj->data); if (ret != 0) return (ret); - + } MUTEX_THREAD_LOCK(dbenv, txnp->mgrp->mutexp); @@ -917,29 +905,30 @@ __txn_isvalid(txnp, tdp, op) TXN_DETAIL **tdp; txnop_t op; { + DB_ENV *dbenv; DB_TXNMGR *mgrp; DB_TXNREGION *region; TXN_DETAIL *tp; mgrp = txnp->mgrp; + dbenv = mgrp->dbenv; region = mgrp->reginfo.primary; /* Check for recovery. */ if (!F_ISSET(txnp, TXN_COMPENSATE) && F_ISSET(region, TXN_IN_RECOVERY)) { - __db_err(mgrp->dbenv, - "operation not permitted during recovery"); + __db_err(dbenv, "operation not permitted during recovery"); goto err; } /* Check for live cursors. */ if (txnp->cursors != 0) { - __db_err(mgrp->dbenv, "transaction has active cursors"); + __db_err(dbenv, "transaction has active cursors"); goto err; } /* Check transaction's state. */ - tp = (TXN_DETAIL *)R_ADDR(&mgrp->reginfo, txnp->off); + tp = (TXN_DETAIL *)R_ADDR(dbenv, &mgrp->reginfo, txnp->off); if (tdp != NULL) *tdp = tp; @@ -961,8 +950,8 @@ __txn_isvalid(txnp, tdp, op) */ if (tp->status != TXN_PREPARED && !F_ISSET(tp, TXN_DTL_RESTORED)) { - __db_err(mgrp->dbenv, "not a restored transaction"); - return (__db_panic(mgrp->dbenv, EINVAL)); + __db_err(dbenv, "not a restored transaction"); + return (__db_panic(dbenv, EINVAL)); } return (0); @@ -975,7 +964,7 @@ __txn_isvalid(txnp, tdp, op) * I'm not arguing this is good, but I could imagine * someone doing it. */ - __db_err(mgrp->dbenv, + __db_err(dbenv, "Prepare disallowed on child transactions"); return (EINVAL); } @@ -989,7 +978,7 @@ __txn_isvalid(txnp, tdp, op) switch (tp->status) { case TXN_PREPARED: if (op == TXN_OP_PREPARE) { - __db_err(mgrp->dbenv, "transaction already prepared"); + __db_err(dbenv, "transaction already prepared"); /* * Txn_prepare doesn't blow away the user handle, so * in this case, give the user the opportunity to @@ -1003,7 +992,7 @@ __txn_isvalid(txnp, tdp, op) case TXN_ABORTED: case TXN_COMMITTED: default: - __db_err(mgrp->dbenv, "transaction already %s", + __db_err(dbenv, "transaction already %s", tp->status == TXN_COMMITTED ? "committed" : "aborted"); goto err; } @@ -1015,7 +1004,7 @@ err: /* * handles are dead by definition when we return, and if you use * a cursor you forgot to close, we have no idea what will happen. */ - return (__db_panic(mgrp->dbenv, EINVAL)); + return (__db_panic(dbenv, EINVAL)); } /* @@ -1066,14 +1055,14 @@ __txn_end(txnp, is_commit) /* End the transaction. */ R_LOCK(dbenv, &mgr->reginfo); - tp = (TXN_DETAIL *)R_ADDR(&mgr->reginfo, txnp->off); + tp = (TXN_DETAIL *)R_ADDR(dbenv, &mgr->reginfo, txnp->off); SH_TAILQ_REMOVE(®ion->active_txn, tp, links, __txn_detail); if (F_ISSET(tp, TXN_DTL_RESTORED)) { region->stat.st_nrestores--; do_closefiles = region->stat.st_nrestores == 0; } - __db_shalloc_free(mgr->reginfo.addr, tp); + __db_shalloc_free(&mgr->reginfo, tp); if (is_commit) region->stat.st_ncommits++; @@ -1163,6 +1152,7 @@ __txn_undo(txnp) dbenv = mgr->dbenv; logc = NULL; txnlist = NULL; + ret = 0; if (!DBENV_LOGGING(dbenv)) return (0); @@ -1178,7 +1168,7 @@ __txn_undo(txnp) * Allocate a txnlist for children and aborted page allocs. * We need to associate the list with the maximal parent * so that aborted pages are recovered when that transaction - * is commited or aborted. + * is committed or aborted. */ for (ptxn = txnp->parent; ptxn != NULL && ptxn->parent != NULL;) ptxn = ptxn->parent; @@ -1240,7 +1230,9 @@ __txn_undo(txnp) } } +#ifndef HAVE_FTRUNCATE ret = __db_do_the_limbo(dbenv, ptxn, txnp, txnlist, LIMBO_NORMAL); +#endif err: if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0) ret = t_ret; @@ -1285,7 +1277,7 @@ __txn_checkpoint_pp(dbenv, kbytes, minutes, flags) __env_rep_enter(dbenv); ret = __txn_checkpoint(dbenv, kbytes, minutes, flags); if (rep_check) - __env_rep_exit(dbenv); + __env_db_rep_exit(dbenv); return (ret); } @@ -1304,13 +1296,13 @@ __txn_checkpoint(dbenv, kbytes, minutes, flags) DB_LSN ckp_lsn, last_ckp; DB_TXNMGR *mgr; DB_TXNREGION *region; - TXN_DETAIL *txnp; + REGENV *renv; + REGINFO *infop; time_t last_ckp_time, now; - u_int32_t bytes, gen, mbytes; + u_int32_t bytes, gen, id, logflags, mbytes; int ret; ret = gen = 0; - /* * A client will only call through here during recovery, * so just sync the Mpool and go home. @@ -1327,6 +1319,12 @@ __txn_checkpoint(dbenv, kbytes, minutes, flags) mgr = dbenv->tx_handle; region = mgr->reginfo.primary; + infop = dbenv->reginfo; + renv = infop->primary; + /* + * No mutex is needed as envid is read-only once it is set. + */ + id = renv->envid; /* * The checkpoint LSN is an LSN such that all transactions begun before @@ -1369,20 +1367,8 @@ __txn_checkpoint(dbenv, kbytes, minutes, flags) return (0); } -do_ckp: /* - * Find the oldest active transaction and figure out its "begin" LSN. - * This is the lowest LSN we can checkpoint, since any record written - * after it may be involved in a transaction and may therefore need - * to be undone in the case of an abort. - */ - R_LOCK(dbenv, &mgr->reginfo); - for (txnp = SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); - txnp != NULL; - txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) - if (!IS_ZERO_LSN(txnp->begin_lsn) && - log_compare(&txnp->begin_lsn, &ckp_lsn) < 0) - ckp_lsn = txnp->begin_lsn; - R_UNLOCK(dbenv, &mgr->reginfo); +do_ckp: + __txn_getactive(dbenv, &ckp_lsn); if (MPOOL_ON(dbenv) && (ret = __memp_sync(dbenv, NULL)) != 0) { __db_err(dbenv, @@ -1411,10 +1397,12 @@ do_ckp: /* * recovery from the ckp_lsn contained in this * checkpoint. */ - if ((ret = __dbreg_open_files(dbenv)) != 0 || - (ret = __txn_ckp_log(dbenv, NULL, - &ckp_lsn, DB_FLUSH | DB_LOG_PERM | DB_LOG_CHKPNT, &ckp_lsn, - &last_ckp, (int32_t)time(NULL), gen)) != 0) { + logflags = DB_LOG_PERM | DB_LOG_CHKPNT; + if (!IS_RECOVERING(dbenv)) + logflags |= DB_FLUSH; + if ((ret = __dbreg_log_files(dbenv)) != 0 || + (ret = __txn_ckp_log(dbenv, NULL, &ckp_lsn, logflags, + &ckp_lsn, &last_ckp, (int32_t)time(NULL), id, gen)) != 0) { __db_err(dbenv, "txn_checkpoint: log failed at LSN [%ld %ld] %s", (long)ckp_lsn.file, (long)ckp_lsn.offset, @@ -1428,6 +1416,43 @@ do_ckp: /* } /* + * __txn_getactive -- + * Find the oldest active transaction and figure out its "begin" LSN. + * This is the lowest LSN we can checkpoint, since any record written + * after it may be involved in a transaction and may therefore need + * to be undone in the case of an abort. + * + * We check both the file and offset for 0 since the lsn may be in + * transition. If it is then we don't care about this txn becuase it + * must be starting after we set the initial value of lsnp in the caller. + * All txns must initalize their begin_lsn before writing to the log. + * + * PUBLIC: void __txn_getactive __P((DB_ENV *, DB_LSN *)); + */ +void +__txn_getactive(dbenv, lsnp) + DB_ENV *dbenv; + DB_LSN *lsnp; +{ + DB_TXNMGR *mgr; + DB_TXNREGION *region; + TXN_DETAIL *txnp; + + mgr = dbenv->tx_handle; + region = mgr->reginfo.primary; + + R_LOCK(dbenv, &mgr->reginfo); + for (txnp = SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); + txnp != NULL; + txnp = SH_TAILQ_NEXT(txnp, links, __txn_detail)) + if (txnp->begin_lsn.file != 0 && + txnp->begin_lsn.offset != 0 && + log_compare(&txnp->begin_lsn, lsnp) < 0) + *lsnp = txnp->begin_lsn; + R_UNLOCK(dbenv, &mgr->reginfo); +} + +/* * __txn_getckp -- * Get the LSN of the last transaction checkpoint. * @@ -1470,7 +1495,7 @@ __txn_activekids(dbenv, rectype, txnp) { /* * On a child commit, we know that there are children (i.e., the - * commiting child at the least. In that case, skip this check. + * committing child at the least. In that case, skip this check. */ if (F_ISSET(txnp, TXN_COMPENSATE) || rectype == DB___txn_child) return (0); @@ -1496,9 +1521,9 @@ __txn_force_abort(dbenv, buffer) { DB_CIPHER *db_cipher; HDR *hdr; - u_int32_t hdrlen, offset, opcode, rec_len, sum_len; + u_int32_t hdrlen, offset, opcode, sum_len; u_int8_t *bp, *key, chksum[DB_MAC_KEY]; - size_t hdrsize; + size_t hdrsize, rec_len; int ret; db_cipher = dbenv->crypto_handle; @@ -1536,7 +1561,7 @@ __txn_force_abort(dbenv, buffer) return (__db_panic(dbenv, ret)); __db_chksum(buffer + hdrsize, rec_len, key, chksum); - memcpy(buffer + SSZ(HDR, chksum), &chksum, sum_len); + memcpy(buffer + SSZA(HDR, chksum), chksum, sum_len); return (0); } @@ -1563,8 +1588,8 @@ __txn_preclose(dbenv) R_LOCK(dbenv, &mgr->reginfo); if (region != NULL && - region->stat.st_nrestores - <= mgr->n_discards && mgr->n_discards != 0) + region->stat.st_nrestores <= mgr->n_discards && + mgr->n_discards != 0) do_closefiles = 1; R_UNLOCK(dbenv, &mgr->reginfo); @@ -1624,10 +1649,10 @@ __txn_updateckp(dbenv, lsnp) region = mgr->reginfo.primary; /* - * We want to make sure last_ckp only moves forward; since - * we drop locks above and in log_put, it's possible - * for two calls to __txn_ckp_log to finish in a different - * order from how they were called. + * We want to make sure last_ckp only moves forward; since we drop + * locks above and in log_put, it's possible for two calls to + * __txn_ckp_log to finish in a different order from how they were + * called. */ R_LOCK(dbenv, &mgr->reginfo); if (log_compare(®ion->last_ckp, lsnp) < 0) { @@ -1636,3 +1661,26 @@ __txn_updateckp(dbenv, lsnp) } R_UNLOCK(dbenv, &mgr->reginfo); } + +/* + * txn_set_begin_lsnp -- + * Set the pointer to the begin_lsn field if that field is zero. + */ +static void +__txn_set_begin_lsnp(txn, rlsnp) + DB_TXN *txn; + DB_LSN **rlsnp; +{ + DB_LSN *lsnp; + TXN_DETAIL *td; + + td = (TXN_DETAIL *)R_ADDR(txn->mgrp->dbenv, + &txn->mgrp->reginfo, txn->off); + while (td->parent != INVALID_ROFF) + td = (TXN_DETAIL *)R_ADDR(txn->mgrp->dbenv, + &txn->mgrp->reginfo, td->parent); + + lsnp = &td->begin_lsn; + if (IS_ZERO_LSN(*lsnp)) + *rlsnp = lsnp; +} diff --git a/db/txn/txn.src b/db/txn/txn.src index 11afb4004..34bd8bd0b 100644 --- a/db/txn/txn.src +++ b/db/txn/txn.src @@ -1,17 +1,15 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. * - * $Id: txn.src,v 11.24 2003/11/14 05:32:33 ubell Exp $ + * $Id: txn.src,v 11.33 2004/07/27 12:35:19 bostic Exp $ */ PREFIX __txn DBPRIVATE -INCLUDE #include "db_config.h" -INCLUDE INCLUDE #ifndef NO_SYSTEM_INCLUDES INCLUDE #include <sys/types.h> INCLUDE @@ -35,6 +33,8 @@ INCLUDE #include "dbinc/crypto.h" INCLUDE #include "dbinc/db_page.h" INCLUDE #include "dbinc/db_dispatch.h" INCLUDE #include "dbinc/db_am.h" +INCLUDE #include "dbinc/db_shash.h" +INCLUDE #include "dbinc/lock.h" INCLUDE #include "dbinc/log.h" INCLUDE #include "dbinc/txn.h" INCLUDE @@ -46,9 +46,9 @@ INCLUDE * either changes the Epoch or has a 64-bit offset. */ BEGIN regop 10 -ARG opcode u_int32_t lu +ARG opcode u_int32_t ld TIME timestamp int32_t ld -DBT locks DBT s +LOCKS locks DBT s END /* @@ -64,11 +64,16 @@ END * The previous checkpoint. * timestamp: * See comment in commit about timestamps. + * envid: + * Environment ID of this checkpoint. + * rep_gen: + * Persistent replication generation number. */ BEGIN ckp 11 POINTER ckp_lsn DB_LSN * lu POINTER last_ckp DB_LSN * lu TIME timestamp int32_t ld +ARG envid u_int32_t ld ARG rep_gen u_int32_t ld END @@ -94,7 +99,7 @@ ARG formatID int32_t ld ARG gtrid u_int32_t u ARG bqual u_int32_t u POINTER begin_lsn DB_LSN * lu -DBT locks DBT s +LOCKS locks DBT s END /* diff --git a/db/txn/txn_auto.c b/db/txn/txn_auto.c index a8bd386b4..c5afa0cdb 100644 --- a/db/txn/txn_auto.c +++ b/db/txn/txn_auto.c @@ -1,4 +1,5 @@ /* Do not edit: automatically built by gen_rec.awk. */ + #include "db_config.h" #ifndef NO_SYSTEM_INCLUDES @@ -24,6 +25,8 @@ #include "dbinc/db_page.h" #include "dbinc/db_dispatch.h" #include "dbinc/db_am.h" +#include "dbinc/db_shash.h" +#include "dbinc/lock.h" #include "dbinc/log.h" #include "dbinc/txn.h" @@ -44,31 +47,42 @@ __txn_regop_log(dbenv, txnid, ret_lsnp, flags, { DBT logrec; DB_TXNLOGREC *lr; - DB_LSN *lsnp, null_lsn; + DB_LSN *lsnp, null_lsn, *rlsnp; u_int32_t zero, uinttmp, rectype, txn_num; u_int npad; u_int8_t *bp; int is_durable, ret; + COMPQUIET(lr, NULL); + rectype = DB___txn_regop; npad = 0; + rlsnp = ret_lsnp; - is_durable = 1; - if (LF_ISSET(DB_LOG_NOT_DURABLE) || - F_ISSET(dbenv, DB_ENV_TXN_NOT_DURABLE)) { + ret = 0; + + if (LF_ISSET(DB_LOG_NOT_DURABLE)) { if (txnid == NULL) return (0); is_durable = 0; - } + } else + is_durable = 1; + if (txnid == NULL) { txn_num = 0; - null_lsn.file = 0; - null_lsn.offset = 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) 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; } @@ -83,27 +97,23 @@ __txn_regop_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (!is_durable && txnid != NULL) { + if (is_durable || txnid == NULL) { + if ((ret = + __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) + return (ret); + } else { if ((ret = __os_malloc(dbenv, logrec.size + sizeof(DB_TXNLOGREC), &lr)) != 0) return (ret); #ifdef DIAGNOSTIC - goto do_malloc; -#else - logrec.data = &lr->data; -#endif - } else { -#ifdef DIAGNOSTIC -do_malloc: -#endif if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) { -#ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) - (void)__os_free(dbenv, lr); -#endif + __os_free(dbenv, lr); return (ret); } +#else + logrec.data = lr->data; +#endif } if (npad > 0) memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); @@ -140,137 +150,47 @@ do_malloc: DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + if (is_durable || txnid == NULL) { + if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { + txnid->last_lsn = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } + } else { #ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) { - /* - * We set the debug bit if we are going - * to log non-durable transactions so - * they will be ignored by recovery. + /* + * Set the debug bit if we are going to log non-durable + * transactions so they will be ignored by recovery. */ memcpy(lr->data, logrec.data, logrec.size); rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - } -#endif - if (!is_durable && txnid != NULL) { + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); +#else ret = 0; - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); -#ifdef DIAGNOSTIC - goto do_put; #endif - } else{ -#ifdef DIAGNOSTIC -do_put: -#endif - ret = __log_put(dbenv, - ret_lsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); - if (ret == 0 && txnid != NULL) - txnid->last_lsn = *ret_lsnp; + STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + LSN_NOT_LOGGED(*ret_lsnp); } - if (!is_durable) - LSN_NOT_LOGGED(*ret_lsnp); #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__txn_regop_print(dbenv, (DBT *)&logrec, ret_lsnp, NULL, NULL); #endif -#ifndef DIAGNOSTIC + +#ifdef DIAGNOSTIC + __os_free(dbenv, logrec.data); +#else if (is_durable || txnid == NULL) -#endif __os_free(dbenv, logrec.data); - +#endif return (ret); } -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_regop_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_regop_getpgnos(dbenv, rec, lsnp, notused1, summary) - DB_ENV *dbenv; - DBT *rec; - DB_LSN *lsnp; - db_recops notused1; - void *summary; -{ - TXN_RECS *t; - int ret; - COMPQUIET(rec, NULL); - COMPQUIET(notused1, DB_TXN_ABORT); - - t = (TXN_RECS *)summary; - - if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) - return (ret); - - t->array[t->npages].flags = LSN_PAGE_NOLOCK; - t->array[t->npages].lsn = *lsnp; - t->array[t->npages].fid = DB_LOGFILEID_INVALID; - memset(&t->array[t->npages].pgdesc, 0, - sizeof(t->array[t->npages].pgdesc)); - - t->npages++; - - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* - * PUBLIC: int __txn_regop_print __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_regop_print(dbenv, dbtp, lsnp, notused2, notused3) - DB_ENV *dbenv; - DBT *dbtp; - DB_LSN *lsnp; - db_recops notused2; - void *notused3; -{ - __txn_regop_args *argp; - struct tm *lt; - u_int32_t i; - int ch; - int ret; - - notused2 = DB_TXN_ABORT; - notused3 = NULL; - - if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0) - return (ret); - (void)printf( - "[%lu][%lu]__txn_regop%s: rec: %lu txnid %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); - (void)printf("\topcode: %lu\n", (u_long)argp->opcode); - lt = localtime((time_t *)&argp->timestamp); - (void)printf( - "\ttimestamp: %ld (%.24s, 20%02lu%02lu%02lu%02lu%02lu.%02lu)\n", - (long)argp->timestamp, ctime((time_t *)&argp->timestamp), - (u_long)lt->tm_year - 100, (u_long)lt->tm_mon+1, - (u_long)lt->tm_mday, (u_long)lt->tm_hour, - (u_long)lt->tm_min, (u_long)lt->tm_sec); - (void)printf("\tlocks: "); - for (i = 0; i < argp->locks.size; i++) { - ch = ((u_int8_t *)argp->locks.data)[i]; - printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch); - } - (void)printf("\n"); - (void)printf("\n"); - __os_free(dbenv, argp); - - return (0); -} - /* * PUBLIC: int __txn_regop_read __P((DB_ENV *, void *, __txn_regop_args **)); */ @@ -288,9 +208,9 @@ __txn_regop_read(dbenv, recbuf, argpp) if ((ret = __os_malloc(dbenv, sizeof(__txn_regop_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); + bp = recbuf; argp->txnid = (DB_TXN *)&argp[1]; - bp = recbuf; memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); @@ -320,11 +240,11 @@ __txn_regop_read(dbenv, recbuf, argpp) /* * PUBLIC: int __txn_ckp_log __P((DB_ENV *, DB_TXN *, DB_LSN *, - * PUBLIC: u_int32_t, DB_LSN *, DB_LSN *, int32_t, u_int32_t)); + * PUBLIC: u_int32_t, DB_LSN *, DB_LSN *, int32_t, u_int32_t, u_int32_t)); */ int __txn_ckp_log(dbenv, txnid, ret_lsnp, flags, - ckp_lsn, last_ckp, timestamp, rep_gen) + ckp_lsn, last_ckp, timestamp, envid, rep_gen) DB_ENV *dbenv; DB_TXN *txnid; DB_LSN *ret_lsnp; @@ -332,35 +252,47 @@ __txn_ckp_log(dbenv, txnid, ret_lsnp, flags, DB_LSN * ckp_lsn; DB_LSN * last_ckp; int32_t timestamp; + u_int32_t envid; u_int32_t rep_gen; { DBT logrec; DB_TXNLOGREC *lr; - DB_LSN *lsnp, null_lsn; + DB_LSN *lsnp, null_lsn, *rlsnp; u_int32_t uinttmp, rectype, txn_num; u_int npad; u_int8_t *bp; int is_durable, ret; + COMPQUIET(lr, NULL); + rectype = DB___txn_ckp; npad = 0; + rlsnp = ret_lsnp; + + ret = 0; - is_durable = 1; - if (LF_ISSET(DB_LOG_NOT_DURABLE) || - F_ISSET(dbenv, DB_ENV_TXN_NOT_DURABLE)) { + if (LF_ISSET(DB_LOG_NOT_DURABLE)) { if (txnid == NULL) return (0); is_durable = 0; - } + } else + is_durable = 1; + if (txnid == NULL) { txn_num = 0; - null_lsn.file = 0; - null_lsn.offset = 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) 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; } @@ -369,6 +301,7 @@ __txn_ckp_log(dbenv, txnid, ret_lsnp, flags, + sizeof(*ckp_lsn) + sizeof(*last_ckp) + sizeof(u_int32_t) + + sizeof(u_int32_t) + sizeof(u_int32_t); if (CRYPTO_ON(dbenv)) { npad = @@ -376,27 +309,23 @@ __txn_ckp_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (!is_durable && txnid != NULL) { + if (is_durable || txnid == NULL) { + if ((ret = + __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) + return (ret); + } else { if ((ret = __os_malloc(dbenv, logrec.size + sizeof(DB_TXNLOGREC), &lr)) != 0) return (ret); #ifdef DIAGNOSTIC - goto do_malloc; -#else - logrec.data = &lr->data; -#endif - } else { -#ifdef DIAGNOSTIC -do_malloc: -#endif if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) { -#ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) - (void)__os_free(dbenv, lr); -#endif + __os_free(dbenv, lr); return (ret); } +#else + logrec.data = lr->data; +#endif } if (npad > 0) memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); @@ -428,139 +357,57 @@ do_malloc: memcpy(bp, &uinttmp, sizeof(uinttmp)); bp += sizeof(uinttmp); + uinttmp = (u_int32_t)envid; + memcpy(bp, &uinttmp, sizeof(uinttmp)); + bp += sizeof(uinttmp); + uinttmp = (u_int32_t)rep_gen; memcpy(bp, &uinttmp, sizeof(uinttmp)); bp += sizeof(uinttmp); DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + if (is_durable || txnid == NULL) { + if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { + txnid->last_lsn = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } + } else { #ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) { - /* - * We set the debug bit if we are going - * to log non-durable transactions so - * they will be ignored by recovery. + /* + * Set the debug bit if we are going to log non-durable + * transactions so they will be ignored by recovery. */ memcpy(lr->data, logrec.data, logrec.size); rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - } -#endif - if (!is_durable && txnid != NULL) { + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); +#else ret = 0; - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); -#ifdef DIAGNOSTIC - goto do_put; -#endif - } else{ -#ifdef DIAGNOSTIC -do_put: #endif - ret = __log_put(dbenv, - ret_lsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); - if (ret == 0 && txnid != NULL) - txnid->last_lsn = *ret_lsnp; + STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + LSN_NOT_LOGGED(*ret_lsnp); } - if (!is_durable) - LSN_NOT_LOGGED(*ret_lsnp); #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__txn_ckp_print(dbenv, (DBT *)&logrec, ret_lsnp, NULL, NULL); #endif -#ifndef DIAGNOSTIC + +#ifdef DIAGNOSTIC + __os_free(dbenv, logrec.data); +#else if (is_durable || txnid == NULL) -#endif __os_free(dbenv, logrec.data); - +#endif return (ret); } -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_ckp_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_ckp_getpgnos(dbenv, rec, lsnp, notused1, summary) - DB_ENV *dbenv; - DBT *rec; - DB_LSN *lsnp; - db_recops notused1; - void *summary; -{ - TXN_RECS *t; - int ret; - COMPQUIET(rec, NULL); - COMPQUIET(notused1, DB_TXN_ABORT); - - t = (TXN_RECS *)summary; - - if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) - return (ret); - - t->array[t->npages].flags = LSN_PAGE_NOLOCK; - t->array[t->npages].lsn = *lsnp; - t->array[t->npages].fid = DB_LOGFILEID_INVALID; - memset(&t->array[t->npages].pgdesc, 0, - sizeof(t->array[t->npages].pgdesc)); - - t->npages++; - - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* - * PUBLIC: int __txn_ckp_print __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_ckp_print(dbenv, dbtp, lsnp, notused2, notused3) - DB_ENV *dbenv; - DBT *dbtp; - DB_LSN *lsnp; - db_recops notused2; - void *notused3; -{ - __txn_ckp_args *argp; - struct tm *lt; - int ret; - - notused2 = DB_TXN_ABORT; - notused3 = NULL; - - if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0) - return (ret); - (void)printf( - "[%lu][%lu]__txn_ckp%s: rec: %lu txnid %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); - (void)printf("\tckp_lsn: [%lu][%lu]\n", - (u_long)argp->ckp_lsn.file, (u_long)argp->ckp_lsn.offset); - (void)printf("\tlast_ckp: [%lu][%lu]\n", - (u_long)argp->last_ckp.file, (u_long)argp->last_ckp.offset); - lt = localtime((time_t *)&argp->timestamp); - (void)printf( - "\ttimestamp: %ld (%.24s, 20%02lu%02lu%02lu%02lu%02lu.%02lu)\n", - (long)argp->timestamp, ctime((time_t *)&argp->timestamp), - (u_long)lt->tm_year - 100, (u_long)lt->tm_mon+1, - (u_long)lt->tm_mday, (u_long)lt->tm_hour, - (u_long)lt->tm_min, (u_long)lt->tm_sec); - (void)printf("\trep_gen: %ld\n", (long)argp->rep_gen); - (void)printf("\n"); - __os_free(dbenv, argp); - - return (0); -} - /* * PUBLIC: int __txn_ckp_read __P((DB_ENV *, void *, __txn_ckp_args **)); */ @@ -578,9 +425,9 @@ __txn_ckp_read(dbenv, recbuf, argpp) if ((ret = __os_malloc(dbenv, sizeof(__txn_ckp_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); + bp = recbuf; argp->txnid = (DB_TXN *)&argp[1]; - bp = recbuf; memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); @@ -601,6 +448,10 @@ __txn_ckp_read(dbenv, recbuf, argpp) bp += sizeof(uinttmp); memcpy(&uinttmp, bp, sizeof(uinttmp)); + argp->envid = (u_int32_t)uinttmp; + bp += sizeof(uinttmp); + + memcpy(&uinttmp, bp, sizeof(uinttmp)); argp->rep_gen = (u_int32_t)uinttmp; bp += sizeof(uinttmp); @@ -624,31 +475,42 @@ __txn_child_log(dbenv, txnid, ret_lsnp, flags, { DBT logrec; DB_TXNLOGREC *lr; - DB_LSN *lsnp, null_lsn; + DB_LSN *lsnp, null_lsn, *rlsnp; u_int32_t uinttmp, rectype, txn_num; u_int npad; u_int8_t *bp; int is_durable, ret; + COMPQUIET(lr, NULL); + rectype = DB___txn_child; npad = 0; + rlsnp = ret_lsnp; - is_durable = 1; - if (LF_ISSET(DB_LOG_NOT_DURABLE) || - F_ISSET(dbenv, DB_ENV_TXN_NOT_DURABLE)) { + ret = 0; + + if (LF_ISSET(DB_LOG_NOT_DURABLE)) { if (txnid == NULL) return (0); is_durable = 0; - } + } else + is_durable = 1; + if (txnid == NULL) { txn_num = 0; - null_lsn.file = 0; - null_lsn.offset = 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) 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; } @@ -662,27 +524,23 @@ __txn_child_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (!is_durable && txnid != NULL) { + if (is_durable || txnid == NULL) { + if ((ret = + __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) + return (ret); + } else { if ((ret = __os_malloc(dbenv, logrec.size + sizeof(DB_TXNLOGREC), &lr)) != 0) return (ret); #ifdef DIAGNOSTIC - goto do_malloc; -#else - logrec.data = &lr->data; -#endif - } else { -#ifdef DIAGNOSTIC -do_malloc: -#endif if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) { -#ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) - (void)__os_free(dbenv, lr); -#endif + __os_free(dbenv, lr); return (ret); } +#else + logrec.data = lr->data; +#endif } if (npad > 0) memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); @@ -710,123 +568,47 @@ do_malloc: DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + if (is_durable || txnid == NULL) { + if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { + txnid->last_lsn = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } + } else { #ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) { - /* - * We set the debug bit if we are going - * to log non-durable transactions so - * they will be ignored by recovery. + /* + * Set the debug bit if we are going to log non-durable + * transactions so they will be ignored by recovery. */ memcpy(lr->data, logrec.data, logrec.size); rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - } -#endif - if (!is_durable && txnid != NULL) { + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); +#else ret = 0; - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); -#ifdef DIAGNOSTIC - goto do_put; -#endif - } else{ -#ifdef DIAGNOSTIC -do_put: #endif - ret = __log_put(dbenv, - ret_lsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); - if (ret == 0 && txnid != NULL) - txnid->last_lsn = *ret_lsnp; + STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + LSN_NOT_LOGGED(*ret_lsnp); } - if (!is_durable) - LSN_NOT_LOGGED(*ret_lsnp); #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__txn_child_print(dbenv, (DBT *)&logrec, ret_lsnp, NULL, NULL); #endif -#ifndef DIAGNOSTIC + +#ifdef DIAGNOSTIC + __os_free(dbenv, logrec.data); +#else if (is_durable || txnid == NULL) -#endif __os_free(dbenv, logrec.data); - +#endif return (ret); } -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_child_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_child_getpgnos(dbenv, rec, lsnp, notused1, summary) - DB_ENV *dbenv; - DBT *rec; - DB_LSN *lsnp; - db_recops notused1; - void *summary; -{ - TXN_RECS *t; - int ret; - COMPQUIET(rec, NULL); - COMPQUIET(notused1, DB_TXN_ABORT); - - t = (TXN_RECS *)summary; - - if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) - return (ret); - - t->array[t->npages].flags = LSN_PAGE_NOLOCK; - t->array[t->npages].lsn = *lsnp; - t->array[t->npages].fid = DB_LOGFILEID_INVALID; - memset(&t->array[t->npages].pgdesc, 0, - sizeof(t->array[t->npages].pgdesc)); - - t->npages++; - - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* - * PUBLIC: int __txn_child_print __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_child_print(dbenv, dbtp, lsnp, notused2, notused3) - DB_ENV *dbenv; - DBT *dbtp; - DB_LSN *lsnp; - db_recops notused2; - void *notused3; -{ - __txn_child_args *argp; - int ret; - - notused2 = DB_TXN_ABORT; - notused3 = NULL; - - if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0) - return (ret); - (void)printf( - "[%lu][%lu]__txn_child%s: rec: %lu txnid %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); - (void)printf("\tchild: 0x%lx\n", (u_long)argp->child); - (void)printf("\tc_lsn: [%lu][%lu]\n", - (u_long)argp->c_lsn.file, (u_long)argp->c_lsn.offset); - (void)printf("\n"); - __os_free(dbenv, argp); - - return (0); -} - /* * PUBLIC: int __txn_child_read __P((DB_ENV *, void *, __txn_child_args **)); */ @@ -844,9 +626,9 @@ __txn_child_read(dbenv, recbuf, argpp) if ((ret = __os_malloc(dbenv, sizeof(__txn_child_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); + bp = recbuf; argp->txnid = (DB_TXN *)&argp[1]; - bp = recbuf; memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); @@ -890,31 +672,42 @@ __txn_xa_regop_log(dbenv, txnid, ret_lsnp, flags, { DBT logrec; DB_TXNLOGREC *lr; - DB_LSN *lsnp, null_lsn; + DB_LSN *lsnp, null_lsn, *rlsnp; u_int32_t zero, uinttmp, rectype, txn_num; u_int npad; u_int8_t *bp; int is_durable, ret; + COMPQUIET(lr, NULL); + rectype = DB___txn_xa_regop; npad = 0; + rlsnp = ret_lsnp; + + ret = 0; - is_durable = 1; - if (LF_ISSET(DB_LOG_NOT_DURABLE) || - F_ISSET(dbenv, DB_ENV_TXN_NOT_DURABLE)) { + if (LF_ISSET(DB_LOG_NOT_DURABLE)) { if (txnid == NULL) return (0); is_durable = 0; - } + } else + is_durable = 1; + if (txnid == NULL) { txn_num = 0; - null_lsn.file = 0; - null_lsn.offset = 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) 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; } @@ -933,27 +726,23 @@ __txn_xa_regop_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (!is_durable && txnid != NULL) { + if (is_durable || txnid == NULL) { + if ((ret = + __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) + return (ret); + } else { if ((ret = __os_malloc(dbenv, logrec.size + sizeof(DB_TXNLOGREC), &lr)) != 0) return (ret); #ifdef DIAGNOSTIC - goto do_malloc; -#else - logrec.data = &lr->data; -#endif - } else { -#ifdef DIAGNOSTIC -do_malloc: -#endif if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) { -#ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) - (void)__os_free(dbenv, lr); -#endif + __os_free(dbenv, lr); return (ret); } +#else + logrec.data = lr->data; +#endif } if (npad > 0) memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); @@ -1015,140 +804,47 @@ do_malloc: DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + if (is_durable || txnid == NULL) { + if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { + txnid->last_lsn = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } + } else { #ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) { - /* - * We set the debug bit if we are going - * to log non-durable transactions so - * they will be ignored by recovery. + /* + * Set the debug bit if we are going to log non-durable + * transactions so they will be ignored by recovery. */ memcpy(lr->data, logrec.data, logrec.size); rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - } -#endif - if (!is_durable && txnid != NULL) { + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); +#else ret = 0; - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); -#ifdef DIAGNOSTIC - goto do_put; -#endif - } else{ -#ifdef DIAGNOSTIC -do_put: #endif - ret = __log_put(dbenv, - ret_lsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); - if (ret == 0 && txnid != NULL) - txnid->last_lsn = *ret_lsnp; + STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + LSN_NOT_LOGGED(*ret_lsnp); } - if (!is_durable) - LSN_NOT_LOGGED(*ret_lsnp); #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__txn_xa_regop_print(dbenv, (DBT *)&logrec, ret_lsnp, NULL, NULL); #endif -#ifndef DIAGNOSTIC + +#ifdef DIAGNOSTIC + __os_free(dbenv, logrec.data); +#else if (is_durable || txnid == NULL) -#endif __os_free(dbenv, logrec.data); - +#endif return (ret); } -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_xa_regop_getpgnos __P((DB_ENV *, DBT *, - * PUBLIC: DB_LSN *, db_recops, void *)); - */ -int -__txn_xa_regop_getpgnos(dbenv, rec, lsnp, notused1, summary) - DB_ENV *dbenv; - DBT *rec; - DB_LSN *lsnp; - db_recops notused1; - void *summary; -{ - TXN_RECS *t; - int ret; - COMPQUIET(rec, NULL); - COMPQUIET(notused1, DB_TXN_ABORT); - - t = (TXN_RECS *)summary; - - if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) - return (ret); - - t->array[t->npages].flags = LSN_PAGE_NOLOCK; - t->array[t->npages].lsn = *lsnp; - t->array[t->npages].fid = DB_LOGFILEID_INVALID; - memset(&t->array[t->npages].pgdesc, 0, - sizeof(t->array[t->npages].pgdesc)); - - t->npages++; - - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* - * PUBLIC: int __txn_xa_regop_print __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_xa_regop_print(dbenv, dbtp, lsnp, notused2, notused3) - DB_ENV *dbenv; - DBT *dbtp; - DB_LSN *lsnp; - db_recops notused2; - void *notused3; -{ - __txn_xa_regop_args *argp; - u_int32_t i; - int ch; - int ret; - - notused2 = DB_TXN_ABORT; - notused3 = NULL; - - if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0) - return (ret); - (void)printf( - "[%lu][%lu]__txn_xa_regop%s: rec: %lu txnid %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); - (void)printf("\topcode: %lu\n", (u_long)argp->opcode); - (void)printf("\txid: "); - for (i = 0; i < argp->xid.size; i++) { - ch = ((u_int8_t *)argp->xid.data)[i]; - printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch); - } - (void)printf("\n"); - (void)printf("\tformatID: %ld\n", (long)argp->formatID); - (void)printf("\tgtrid: %u\n", argp->gtrid); - (void)printf("\tbqual: %u\n", argp->bqual); - (void)printf("\tbegin_lsn: [%lu][%lu]\n", - (u_long)argp->begin_lsn.file, (u_long)argp->begin_lsn.offset); - (void)printf("\tlocks: "); - for (i = 0; i < argp->locks.size; i++) { - ch = ((u_int8_t *)argp->locks.data)[i]; - printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch); - } - (void)printf("\n"); - (void)printf("\n"); - __os_free(dbenv, argp); - - return (0); -} - /* * PUBLIC: int __txn_xa_regop_read __P((DB_ENV *, void *, * PUBLIC: __txn_xa_regop_args **)); @@ -1167,9 +863,9 @@ __txn_xa_regop_read(dbenv, recbuf, argpp) if ((ret = __os_malloc(dbenv, sizeof(__txn_xa_regop_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); + bp = recbuf; argp->txnid = (DB_TXN *)&argp[1]; - bp = recbuf; memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); @@ -1230,31 +926,42 @@ __txn_recycle_log(dbenv, txnid, ret_lsnp, flags, { DBT logrec; DB_TXNLOGREC *lr; - DB_LSN *lsnp, null_lsn; + DB_LSN *lsnp, null_lsn, *rlsnp; u_int32_t uinttmp, rectype, txn_num; u_int npad; u_int8_t *bp; int is_durable, ret; + COMPQUIET(lr, NULL); + rectype = DB___txn_recycle; npad = 0; + rlsnp = ret_lsnp; + + ret = 0; - is_durable = 1; - if (LF_ISSET(DB_LOG_NOT_DURABLE) || - F_ISSET(dbenv, DB_ENV_TXN_NOT_DURABLE)) { + if (LF_ISSET(DB_LOG_NOT_DURABLE)) { if (txnid == NULL) return (0); is_durable = 0; - } + } else + is_durable = 1; + if (txnid == NULL) { txn_num = 0; - null_lsn.file = 0; - null_lsn.offset = 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) 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; } @@ -1268,27 +975,23 @@ __txn_recycle_log(dbenv, txnid, ret_lsnp, flags, logrec.size += npad; } - if (!is_durable && txnid != NULL) { + if (is_durable || txnid == NULL) { + if ((ret = + __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) + return (ret); + } else { if ((ret = __os_malloc(dbenv, logrec.size + sizeof(DB_TXNLOGREC), &lr)) != 0) return (ret); #ifdef DIAGNOSTIC - goto do_malloc; -#else - logrec.data = &lr->data; -#endif - } else { -#ifdef DIAGNOSTIC -do_malloc: -#endif if ((ret = __os_malloc(dbenv, logrec.size, &logrec.data)) != 0) { -#ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) - (void)__os_free(dbenv, lr); -#endif + __os_free(dbenv, lr); return (ret); } +#else + logrec.data = lr->data; +#endif } if (npad > 0) memset((u_int8_t *)logrec.data + logrec.size - npad, 0, npad); @@ -1314,122 +1017,47 @@ do_malloc: DB_ASSERT((u_int32_t)(bp - (u_int8_t *)logrec.data) <= logrec.size); + if (is_durable || txnid == NULL) { + if ((ret = __log_put(dbenv, rlsnp,(DBT *)&logrec, + flags | DB_LOG_NOCOPY)) == 0 && txnid != NULL) { + txnid->last_lsn = *rlsnp; + if (rlsnp != ret_lsnp) + *ret_lsnp = *rlsnp; + } + } else { #ifdef DIAGNOSTIC - if (!is_durable && txnid != NULL) { - /* - * We set the debug bit if we are going - * to log non-durable transactions so - * they will be ignored by recovery. + /* + * Set the debug bit if we are going to log non-durable + * transactions so they will be ignored by recovery. */ memcpy(lr->data, logrec.data, logrec.size); rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - } -#endif - if (!is_durable && txnid != NULL) { + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); +#else ret = 0; - STAILQ_INSERT_HEAD(&txnid->logs, lr, links); -#ifdef DIAGNOSTIC - goto do_put; -#endif - } else{ -#ifdef DIAGNOSTIC -do_put: #endif - ret = __log_put(dbenv, - ret_lsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); - if (ret == 0 && txnid != NULL) - txnid->last_lsn = *ret_lsnp; + STAILQ_INSERT_HEAD(&txnid->logs, lr, links); + LSN_NOT_LOGGED(*ret_lsnp); } - if (!is_durable) - LSN_NOT_LOGGED(*ret_lsnp); #ifdef LOG_DIAGNOSTIC if (ret != 0) (void)__txn_recycle_print(dbenv, (DBT *)&logrec, ret_lsnp, NULL, NULL); #endif -#ifndef DIAGNOSTIC + +#ifdef DIAGNOSTIC + __os_free(dbenv, logrec.data); +#else if (is_durable || txnid == NULL) -#endif __os_free(dbenv, logrec.data); - +#endif return (ret); } -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_recycle_getpgnos __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_recycle_getpgnos(dbenv, rec, lsnp, notused1, summary) - DB_ENV *dbenv; - DBT *rec; - DB_LSN *lsnp; - db_recops notused1; - void *summary; -{ - TXN_RECS *t; - int ret; - COMPQUIET(rec, NULL); - COMPQUIET(notused1, DB_TXN_ABORT); - - t = (TXN_RECS *)summary; - - if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) - return (ret); - - t->array[t->npages].flags = LSN_PAGE_NOLOCK; - t->array[t->npages].lsn = *lsnp; - t->array[t->npages].fid = DB_LOGFILEID_INVALID; - memset(&t->array[t->npages].pgdesc, 0, - sizeof(t->array[t->npages].pgdesc)); - - t->npages++; - - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* - * PUBLIC: int __txn_recycle_print __P((DB_ENV *, DBT *, DB_LSN *, - * PUBLIC: db_recops, void *)); - */ -int -__txn_recycle_print(dbenv, dbtp, lsnp, notused2, notused3) - DB_ENV *dbenv; - DBT *dbtp; - DB_LSN *lsnp; - db_recops notused2; - void *notused3; -{ - __txn_recycle_args *argp; - int ret; - - notused2 = DB_TXN_ABORT; - notused3 = NULL; - - if ((ret = __txn_recycle_read(dbenv, dbtp->data, &argp)) != 0) - return (ret); - (void)printf( - "[%lu][%lu]__txn_recycle%s: rec: %lu txnid %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); - (void)printf("\tmin: %u\n", argp->min); - (void)printf("\tmax: %u\n", argp->max); - (void)printf("\n"); - __os_free(dbenv, argp); - - return (0); -} - /* * PUBLIC: int __txn_recycle_read __P((DB_ENV *, void *, * PUBLIC: __txn_recycle_args **)); @@ -1448,9 +1076,9 @@ __txn_recycle_read(dbenv, recbuf, argpp) if ((ret = __os_malloc(dbenv, sizeof(__txn_recycle_args) + sizeof(DB_TXN), &argp)) != 0) return (ret); + bp = recbuf; argp->txnid = (DB_TXN *)&argp[1]; - bp = recbuf; memcpy(&argp->type, bp, sizeof(argp->type)); bp += sizeof(argp->type); @@ -1473,68 +1101,6 @@ __txn_recycle_read(dbenv, recbuf, argpp) } /* - * PUBLIC: int __txn_init_print __P((DB_ENV *, int (***)(DB_ENV *, - * PUBLIC: DBT *, DB_LSN *, db_recops, void *), size_t *)); - */ -int -__txn_init_print(dbenv, dtabp, dtabsizep) - DB_ENV *dbenv; - int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); - size_t *dtabsizep; -{ - int ret; - - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_regop_print, DB___txn_regop)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_ckp_print, DB___txn_ckp)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_child_print, DB___txn_child)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_xa_regop_print, DB___txn_xa_regop)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_recycle_print, DB___txn_recycle)) != 0) - return (ret); - return (0); -} - -#ifdef HAVE_REPLICATION -/* - * PUBLIC: int __txn_init_getpgnos __P((DB_ENV *, int (***)(DB_ENV *, - * PUBLIC: DBT *, DB_LSN *, db_recops, void *), size_t *)); - */ -int -__txn_init_getpgnos(dbenv, dtabp, dtabsizep) - DB_ENV *dbenv; - int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); - size_t *dtabsizep; -{ - int ret; - - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_regop_getpgnos, DB___txn_regop)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_ckp_getpgnos, DB___txn_ckp)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_child_getpgnos, DB___txn_child)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_xa_regop_getpgnos, DB___txn_xa_regop)) != 0) - return (ret); - if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, - __txn_recycle_getpgnos, DB___txn_recycle)) != 0) - return (ret); - return (0); -} -#endif /* HAVE_REPLICATION */ - -/* * PUBLIC: int __txn_init_recover __P((DB_ENV *, int (***)(DB_ENV *, * PUBLIC: DBT *, DB_LSN *, db_recops, void *), size_t *)); */ diff --git a/db/txn/txn_autop.c b/db/txn/txn_autop.c new file mode 100644 index 000000000..dbcf61b9d --- /dev/null +++ b/db/txn/txn_autop.c @@ -0,0 +1,281 @@ +/* Do not edit: automatically built by gen_rec.awk. */ + +#include "db_config.h" + +#ifndef NO_SYSTEM_INCLUDES +#include <sys/types.h> + +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif /* HAVE_SYS_TIME_H */ +#endif /* TIME_WITH SYS_TIME */ + +#include <ctype.h> +#include <string.h> +#endif + +#include "db_int.h" +#include "dbinc/crypto.h" +#include "dbinc/db_page.h" +#include "dbinc/db_dispatch.h" +#include "dbinc/db_am.h" +#include "dbinc/db_shash.h" +#include "dbinc/lock.h" +#include "dbinc/log.h" +#include "dbinc/txn.h" + +/* + * PUBLIC: int __txn_regop_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops, void *)); + */ +int +__txn_regop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_regop_args *argp; + struct tm *lt; + time_t timeval; + int ret; + + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]__txn_regop%s: rec: %lu txnid %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); + (void)printf("\topcode: %ld\n", (long)argp->opcode); + timeval = (time_t)argp->timestamp; + lt = localtime(&timeval); + (void)printf( + "\ttimestamp: %ld (%.24s, 20%02lu%02lu%02lu%02lu%02lu.%02lu)\n", + (long)argp->timestamp, ctime(&timeval), + (u_long)lt->tm_year - 100, (u_long)lt->tm_mon+1, + (u_long)lt->tm_mday, (u_long)lt->tm_hour, + (u_long)lt->tm_min, (u_long)lt->tm_sec); + (void)printf("\tlocks: \n"); + __lock_list_print(dbenv, &argp->locks); + (void)printf("\n"); + __os_free(dbenv, argp); + return (0); +} + +/* + * PUBLIC: int __txn_ckp_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops, void *)); + */ +int +__txn_ckp_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_ckp_args *argp; + struct tm *lt; + time_t timeval; + int ret; + + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_ckp_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]__txn_ckp%s: rec: %lu txnid %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); + (void)printf("\tckp_lsn: [%lu][%lu]\n", + (u_long)argp->ckp_lsn.file, (u_long)argp->ckp_lsn.offset); + (void)printf("\tlast_ckp: [%lu][%lu]\n", + (u_long)argp->last_ckp.file, (u_long)argp->last_ckp.offset); + timeval = (time_t)argp->timestamp; + lt = localtime(&timeval); + (void)printf( + "\ttimestamp: %ld (%.24s, 20%02lu%02lu%02lu%02lu%02lu.%02lu)\n", + (long)argp->timestamp, ctime(&timeval), + (u_long)lt->tm_year - 100, (u_long)lt->tm_mon+1, + (u_long)lt->tm_mday, (u_long)lt->tm_hour, + (u_long)lt->tm_min, (u_long)lt->tm_sec); + (void)printf("\tenvid: %ld\n", (long)argp->envid); + (void)printf("\trep_gen: %ld\n", (long)argp->rep_gen); + (void)printf("\n"); + __os_free(dbenv, argp); + return (0); +} + +/* + * PUBLIC: int __txn_child_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops, void *)); + */ +int +__txn_child_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_child_args *argp; + int ret; + + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_child_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]__txn_child%s: rec: %lu txnid %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); + (void)printf("\tchild: 0x%lx\n", (u_long)argp->child); + (void)printf("\tc_lsn: [%lu][%lu]\n", + (u_long)argp->c_lsn.file, (u_long)argp->c_lsn.offset); + (void)printf("\n"); + __os_free(dbenv, argp); + return (0); +} + +/* + * PUBLIC: int __txn_xa_regop_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops, void *)); + */ +int +__txn_xa_regop_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_xa_regop_args *argp; + u_int32_t i; + int ch; + int ret; + + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_xa_regop_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]__txn_xa_regop%s: rec: %lu txnid %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); + (void)printf("\topcode: %lu\n", (u_long)argp->opcode); + (void)printf("\txid: "); + for (i = 0; i < argp->xid.size; i++) { + ch = ((u_int8_t *)argp->xid.data)[i]; + printf(isprint(ch) || ch == 0x0a ? "%c" : "%#x ", ch); + } + (void)printf("\n"); + (void)printf("\tformatID: %ld\n", (long)argp->formatID); + (void)printf("\tgtrid: %u\n", argp->gtrid); + (void)printf("\tbqual: %u\n", argp->bqual); + (void)printf("\tbegin_lsn: [%lu][%lu]\n", + (u_long)argp->begin_lsn.file, (u_long)argp->begin_lsn.offset); + (void)printf("\tlocks: \n"); + __lock_list_print(dbenv, &argp->locks); + (void)printf("\n"); + __os_free(dbenv, argp); + return (0); +} + +/* + * PUBLIC: int __txn_recycle_print __P((DB_ENV *, DBT *, DB_LSN *, + * PUBLIC: db_recops, void *)); + */ +int +__txn_recycle_print(dbenv, dbtp, lsnp, notused2, notused3) + DB_ENV *dbenv; + DBT *dbtp; + DB_LSN *lsnp; + db_recops notused2; + void *notused3; +{ + __txn_recycle_args *argp; + int ret; + + notused2 = DB_TXN_ABORT; + notused3 = NULL; + + if ((ret = __txn_recycle_read(dbenv, dbtp->data, &argp)) != 0) + return (ret); + (void)printf( + "[%lu][%lu]__txn_recycle%s: rec: %lu txnid %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); + (void)printf("\tmin: %u\n", argp->min); + (void)printf("\tmax: %u\n", argp->max); + (void)printf("\n"); + __os_free(dbenv, argp); + return (0); +} + +/* + * PUBLIC: int __txn_init_print __P((DB_ENV *, int (***)(DB_ENV *, + * PUBLIC: DBT *, DB_LSN *, db_recops, void *), size_t *)); + */ +int +__txn_init_print(dbenv, dtabp, dtabsizep) + DB_ENV *dbenv; + int (***dtabp)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); + size_t *dtabsizep; +{ + int ret; + + if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, + __txn_regop_print, DB___txn_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, + __txn_ckp_print, DB___txn_ckp)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, + __txn_child_print, DB___txn_child)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, + __txn_xa_regop_print, DB___txn_xa_regop)) != 0) + return (ret); + if ((ret = __db_add_recovery(dbenv, dtabp, dtabsizep, + __txn_recycle_print, DB___txn_recycle)) != 0) + return (ret); + return (0); +} diff --git a/db/txn/txn_method.c b/db/txn/txn_method.c index f9359f455..c13f86dee 100644 --- a/db/txn/txn_method.c +++ b/db/txn/txn_method.c @@ -1,16 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. + * + * $Id: txn_method.c,v 11.72 2004/03/23 17:24:18 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_method.c,v 11.66 2003/06/30 17:20:30 bostic Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> @@ -21,11 +19,14 @@ static const char revid[] = "$Id: txn_method.c,v 11.66 2003/06/30 17:20:30 bosti #include <string.h> #endif +#ifdef HAVE_RPC +#include "db_server.h" +#endif + #include "db_int.h" #include "dbinc/txn.h" #ifdef HAVE_RPC -#include "dbinc_auto/db_server.h" #include "dbinc_auto/rpc_client_ext.h" #endif @@ -62,6 +63,7 @@ __txn_dbenv_create(dbenv) dbenv->txn_checkpoint = __dbcl_txn_checkpoint; dbenv->txn_recover = __dbcl_txn_recover; dbenv->txn_stat = __dbcl_txn_stat; + dbenv->txn_stat_print = NULL; dbenv->txn_begin = __dbcl_txn_begin; } else #endif @@ -74,6 +76,7 @@ __txn_dbenv_create(dbenv) dbenv->txn_checkpoint = __txn_checkpoint_pp; dbenv->txn_recover = __txn_recover_pp; dbenv->txn_stat = __txn_stat_pp; + dbenv->txn_stat_print = __txn_stat_print_pp; dbenv->txn_begin = __txn_begin_pp; } } @@ -83,7 +86,15 @@ __txn_get_tx_max(dbenv, tx_maxp) DB_ENV *dbenv; u_int32_t *tx_maxp; { - *tx_maxp = dbenv->tx_max; + ENV_NOT_CONFIGURED(dbenv, + dbenv->tx_handle, "DB_ENV->get_tx_max", DB_INIT_TXN); + + if (TXN_ON(dbenv)) { + /* Cannot be set after open, no lock required to read. */ + *tx_maxp = ((DB_TXNREGION *) + ((DB_TXNMGR *)dbenv->tx_handle)->reginfo.primary)->maxtxns; + } else + *tx_maxp = dbenv->tx_max; return (0); } diff --git a/db/txn/txn_rec.c b/db/txn/txn_rec.c index be4b016b5..ea885528f 100644 --- a/db/txn/txn_rec.c +++ b/db/txn/txn_rec.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. */ /* @@ -31,14 +31,12 @@ * 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. + * + * $Id: txn_rec.c,v 11.64 2004/09/22 17:41:10 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_rec.c,v 11.54 2003/10/31 23:26:11 ubell Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> @@ -50,15 +48,13 @@ static const char revid[] = "$Id: txn_rec.c,v 11.54 2003/10/31 23:26:11 ubell Ex #include "dbinc/txn.h" #include "dbinc/db_am.h" -#define IS_XA_TXN(R) (R->xid.size != 0) - /* * PUBLIC: int __txn_regop_recover * PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)); * * These records are only ever written for commits. Normally, we redo any * committed transaction, however if we are doing recovery to a timestamp, then - * we may treat transactions that commited after the timestamp as aborted. + * we may treat transactions that committed after the timestamp as aborted. */ int __txn_regop_recover(dbenv, dbtp, lsnp, op, info) @@ -71,6 +67,7 @@ __txn_regop_recover(dbenv, dbtp, lsnp, op, info) DB_TXNHEAD *headp; __txn_regop_args *argp; int ret; + u_int32_t status; #ifdef DEBUG_RECOVER (void)__txn_regop_print(dbenv, dbtp, lsnp, op, info); @@ -86,14 +83,16 @@ __txn_regop_recover(dbenv, dbtp, lsnp, op, info) * apply to the BACKWARD_ROLL case. */ - if (op == DB_TXN_FORWARD_ROLL) + if (op == DB_TXN_FORWARD_ROLL) { /* * If this was a 2-phase-commit transaction, then it * might already have been removed from the list, and * that's OK. Ignore the return code from remove. */ - (void)__db_txnlist_remove(dbenv, info, argp->txnid->txnid); - else if ((dbenv->tx_timestamp != 0 && + if ((ret = __db_txnlist_remove(dbenv, + info, argp->txnid->txnid)) != DB_NOTFOUND && ret != 0) + goto err; + } else if ((dbenv->tx_timestamp != 0 && argp->timestamp > (int32_t)dbenv->tx_timestamp) || (!IS_ZERO_LSN(headp->trunc_lsn) && log_compare(&headp->trunc_lsn, lsnp) < 0)) { @@ -101,32 +100,24 @@ __txn_regop_recover(dbenv, dbtp, lsnp, op, info) * We failed either the timestamp check or the trunc_lsn check, * so we treat this as an abort even if it was a commit record. */ - ret = __db_txnlist_update(dbenv, - info, argp->txnid->txnid, TXN_ABORT, NULL); - - if (ret == TXN_IGNORE) - ret = TXN_OK; - else if (ret == TXN_NOTFOUND) - ret = __db_txnlist_add(dbenv, - info, argp->txnid->txnid, TXN_IGNORE, NULL); - else if (ret != TXN_OK) + if ((ret = __db_txnlist_update(dbenv, info, + argp->txnid->txnid, TXN_ABORT, NULL, &status, 1)) != 0) + goto err; + else if (status != TXN_IGNORE && status != TXN_OK) goto err; - /* else ret = 0; Not necessary because TXN_OK == 0 */ } else { /* This is a normal commit; mark it appropriately. */ - ret = __db_txnlist_update(dbenv, - info, argp->txnid->txnid, argp->opcode, lsnp); - - if (ret == TXN_IGNORE) - ret = TXN_OK; - else if (ret == TXN_NOTFOUND) - ret = __db_txnlist_add(dbenv, + if ((ret = __db_txnlist_update(dbenv, + info, argp->txnid->txnid, argp->opcode, lsnp, + &status, 0)) == DB_NOTFOUND) { + if ((ret = __db_txnlist_add(dbenv, info, argp->txnid->txnid, argp->opcode == TXN_ABORT ? - TXN_IGNORE : argp->opcode, lsnp); - else if (ret != TXN_OK) + TXN_IGNORE : argp->opcode, lsnp)) != 0) + goto err; + } else if (ret != 0 || + (status != TXN_IGNORE && status != TXN_OK)) goto err; - /* else ret = 0; Not necessary because TXN_OK == 0 */ } if (ret == 0) @@ -159,6 +150,7 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) { __txn_xa_regop_args *argp; int ret; + u_int32_t status; #ifdef DEBUG_RECOVER (void)__txn_xa_regop_print(dbenv, dbtp, lsnp, op, info); @@ -172,7 +164,14 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) goto err; } - ret = __db_txnlist_find(dbenv, info, argp->txnid->txnid); + /* + * The return value here is either a DB_NOTFOUND or it is + * the transaction status from the list. It is not a normal + * error return, so we must make sure that in each of the + * cases below, we overwrite the ret value so we return + * appropriately. + */ + ret = __db_txnlist_find(dbenv, info, argp->txnid->txnid, &status); /* * If we are rolling forward, then an aborted prepare @@ -183,9 +182,9 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) if (op == DB_TXN_FORWARD_ROLL) { if ((ret = __db_txnlist_remove(dbenv, - info, argp->txnid->txnid)) != TXN_OK) + info, argp->txnid->txnid)) != 0) goto txn_err; - } else if (op == DB_TXN_BACKWARD_ROLL && ret == TXN_PREPARE) { + } else if (op == DB_TXN_BACKWARD_ROLL && status == TXN_PREPARE) { /* * On the backward pass, we have four possibilities: * 1. The transaction is already committed, no-op. @@ -200,7 +199,8 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) if (argp->opcode == TXN_ABORT) { if ((ret = __db_txnlist_update(dbenv, info, argp->txnid->txnid, - TXN_ABORT, NULL)) != TXN_PREPARE) + TXN_ABORT, NULL, &status, 0)) != 0 && + status != TXN_PREPARE) goto txn_err; ret = 0; } @@ -212,7 +212,7 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) * after recovery (see txn_recover). */ else if ((ret = __db_txnlist_remove(dbenv, - info, argp->txnid->txnid)) != TXN_OK) { + info, argp->txnid->txnid)) != 0) { txn_err: __db_err(dbenv, "Transaction not in list %x", argp->txnid->txnid); ret = DB_NOTFOUND; @@ -287,7 +287,8 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) void *info; { __txn_child_args *argp; - int c_stat, p_stat, ret; + int ret, t_ret; + u_int32_t c_stat, p_stat, tmpstat; #ifdef DEBUG_RECOVER (void)__txn_child_print(dbenv, dbtp, lsnp, op, info); @@ -297,9 +298,9 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) /* * This is a record in a PARENT's log trail indicating that a - * child commited. If we are aborting, we need to update the + * child committed. If we are aborting, we need to update the * parent's LSN array. If we are in recovery, then if the - * parent is commiting, we set ourselves up to commit, else + * parent is committing, we set ourselves up to commit, else * we do nothing. */ if (op == DB_TXN_ABORT) { @@ -310,10 +311,35 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) info, &argp->c_lsn, TXNLIST_NEW); } else if (op == DB_TXN_BACKWARD_ROLL) { /* Child might exist -- look for it. */ - c_stat = __db_txnlist_find(dbenv, info, argp->child); - p_stat = __db_txnlist_find(dbenv, info, argp->txnid->txnid); + ret = __db_txnlist_find(dbenv, info, argp->child, &c_stat); + t_ret = + __db_txnlist_find(dbenv, info, argp->txnid->txnid, &p_stat); + if (ret != 0 && ret != DB_NOTFOUND) + goto out; + if (t_ret != 0 && t_ret != DB_NOTFOUND) { + ret = t_ret; + goto out; + } + /* + * If the parent is in state COMMIT or IGNORE, then we apply + * that to the child, else we need to abort the child. + */ - if (c_stat == TXN_EXPECTED) { + if (ret == DB_NOTFOUND || + c_stat == TXN_OK || c_stat == TXN_COMMIT) { + if (t_ret == DB_NOTFOUND || + (p_stat != TXN_COMMIT && p_stat != TXN_IGNORE)) + c_stat = TXN_ABORT; + else + c_stat = p_stat; + + if (ret == DB_NOTFOUND) + ret = __db_txnlist_add(dbenv, + info, argp->child, c_stat, NULL); + else + ret = __db_txnlist_update(dbenv, info, + argp->child, c_stat, NULL, &tmpstat, 0); + } else if (c_stat == TXN_EXPECTED) { /* * The open after this create succeeded. If the * parent succeeded, we don't want to redo; if the @@ -328,9 +354,7 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) c_stat = TXN_ABORT; } ret = __db_txnlist_update(dbenv, - info, argp->child, c_stat, NULL); - if (ret > 0) - ret = 0; + info, argp->child, c_stat, NULL, &tmpstat, 0); } else if (c_stat == TXN_UNEXPECTED) { /* * The open after this create failed. If the parent @@ -341,54 +365,30 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) */ ret = __db_txnlist_update(dbenv, info, argp->child, p_stat == TXN_COMMIT ? TXN_COMMIT : TXN_IGNORE, - NULL); - if (ret > 0) - ret = 0; - } else if (c_stat != TXN_IGNORE) { - switch (p_stat) { - case TXN_COMMIT: - c_stat = TXN_COMMIT; - break; - case TXN_IGNORE: - c_stat = TXN_IGNORE; - break; - default: - c_stat = TXN_ABORT; - } - - ret = __db_txnlist_add(dbenv, - info, argp->child, c_stat, NULL); + NULL, &tmpstat, 0); } } else if (op == DB_TXN_OPENFILES) { /* * If we have a partial subtransaction, then the whole * transaction should be ignored. */ - c_stat = __db_txnlist_find(dbenv, info, argp->child); - if (c_stat == TXN_NOTFOUND) { - p_stat = - __db_txnlist_find(dbenv, info, argp->txnid->txnid); - if (p_stat == TXN_NOTFOUND) - ret = __db_txnlist_add(dbenv, info, - argp->txnid->txnid, TXN_IGNORE, NULL); - else - ret = __db_txnlist_update(dbenv, info, - argp->txnid->txnid, TXN_IGNORE, NULL); - } + if ((ret = __db_txnlist_find(dbenv, + info, argp->child, &c_stat)) == DB_NOTFOUND) + ret = __db_txnlist_update(dbenv, info, + argp->txnid->txnid, TXN_IGNORE, + NULL, &p_stat, 1); } else if (DB_REDO(op)) { /* Forward Roll */ if ((ret = - __db_txnlist_remove(dbenv, info, argp->child)) != TXN_OK) { + __db_txnlist_remove(dbenv, info, argp->child)) != 0) __db_err(dbenv, "Transaction not in list %x", argp->child); - ret = DB_NOTFOUND; - } } if (ret == 0) *lsnp = argp->prev_lsn; - __os_free(dbenv, argp); +out: __os_free(dbenv, argp); return (ret); } @@ -401,7 +401,7 @@ __txn_child_recover(dbenv, dbtp, lsnp, op, info) * or commit and we need to respond correctly. * * lsnp is the LSN of the returned LSN - * argp is the perpare record (in an appropriate structure) + * argp is the prepare record (in an appropriate structure) * * PUBLIC: int __txn_restore_txn __P((DB_ENV *, * PUBLIC: DB_LSN *, __txn_xa_regop_args *)); @@ -426,7 +426,7 @@ __txn_restore_txn(dbenv, lsnp, argp) /* Allocate a new transaction detail structure. */ if ((ret = - __db_shalloc(mgr->reginfo.addr, sizeof(TXN_DETAIL), 0, &td)) != 0) { + __db_shalloc(&mgr->reginfo, sizeof(TXN_DETAIL), 0, &td)) != 0) { R_UNLOCK(dbenv, &mgr->reginfo); return (ret); } diff --git a/db/txn/txn_recover.c b/db/txn/txn_recover.c index 753a84dd3..0d15f57eb 100644 --- a/db/txn/txn_recover.c +++ b/db/txn/txn_recover.c @@ -1,16 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001-2003 + * Copyright (c) 2001-2004 * Sleepycat Software. All rights reserved. + * + * $Id: txn_recover.c,v 1.53 2004/09/22 17:41:10 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_recover.c,v 1.43 2003/09/16 20:50:17 sue Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> @@ -65,14 +63,14 @@ __txn_continue(env, txnp, td, off) * Return the txn that corresponds to this global ID. * * PUBLIC: int __txn_map_gid __P((DB_ENV *, - * PUBLIC: u_int8_t *, TXN_DETAIL **, size_t *)); + * PUBLIC: u_int8_t *, TXN_DETAIL **, roff_t *)); */ int __txn_map_gid(dbenv, gid, tdp, offp) DB_ENV *dbenv; u_int8_t *gid; TXN_DETAIL **tdp; - size_t *offp; + roff_t *offp; { DB_TXNMGR *mgr; DB_TXNREGION *tmr; @@ -96,7 +94,7 @@ __txn_map_gid(dbenv, gid, tdp, offp) if (*tdp == NULL) return (EINVAL); - *offp = R_OFFSET(&mgr->reginfo, *tdp); + *offp = R_OFFSET(dbenv, &mgr->reginfo, *tdp); return (0); } @@ -132,7 +130,7 @@ __txn_recover_pp(dbenv, preplist, count, retp, flags) __env_rep_enter(dbenv); ret = __txn_recover(dbenv, preplist, count, retp, flags); if (rep_check) - __env_rep_exit(dbenv); + __env_db_rep_exit(dbenv); return (ret); } @@ -180,22 +178,17 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) long *retp; u_int32_t flags; { - DBT data; - DB_LOGC *logc; - DB_LSN min, open_lsn; + DB_LSN min; DB_PREPLIST *prepp; DB_TXNMGR *mgr; DB_TXNREGION *tmr; TXN_DETAIL *td; XID *xidp; - __txn_ckp_args *ckp_args; long i; - int nrestores, open_files, ret, t_ret; - void *txninfo; + int nrestores, open_files, ret; *retp = 0; - logc = NULL; MAX_LSN(min); prepp = txns; xidp = xids; @@ -245,8 +238,13 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) if (xids != NULL) { xidp->formatID = td->format; - xidp->gtrid_length = td->gtrid; - xidp->bqual_length = td->bqual; + /* + * XID structure uses longs; we use u_int32_t's as we + * log them to disk. Cast them to make the conversion + * explicit. + */ + xidp->gtrid_length = (long)td->gtrid; + xidp->bqual_length = (long)td->bqual; memcpy(xidp->data, td->xid, sizeof(td->xid)); xidp++; } @@ -258,13 +256,14 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) goto err; } __txn_continue(dbenv, - prepp->txn, td, R_OFFSET(&mgr->reginfo, td)); + prepp->txn, td, R_OFFSET(dbenv, &mgr->reginfo, td)); F_SET(prepp->txn, TXN_MALLOC); memcpy(prepp->gid, td->xid, sizeof(td->xid)); prepp++; } - if (log_compare(&td->begin_lsn, &min) < 0) + if (!IS_ZERO_LSN(td->begin_lsn) && + log_compare(&td->begin_lsn, &min) < 0) min = td->begin_lsn; (*retp)++; @@ -283,59 +282,96 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) } if (open_files && nrestores && *retp != 0 && !IS_MAX_LSN(min)) { - /* - * Figure out the last checkpoint before the smallest - * start_lsn in the region. - */ F_SET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + ret = __txn_openfiles(dbenv, &min, 0); + F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + } +err: + return (ret); +} + +/* + * __txn_openfiles -- + * Call env_openfiles. + * + * PUBLIC: int __txn_openfiles __P((DB_ENV *, DB_LSN *, int)); + */ +int +__txn_openfiles(dbenv, min, force) + DB_ENV *dbenv; + DB_LSN *min; + int force; +{ + DBT data; + DB_LOGC *logc; + DB_LSN open_lsn; + __txn_ckp_args *ckp_args; + int ret, t_ret; + void *txninfo; - if ((ret = __log_cursor(dbenv, &logc)) != 0) - goto err; - - memset(&data, 0, sizeof(data)); - if ((ret = __txn_getckp(dbenv, &open_lsn)) == 0) - while (!IS_ZERO_LSN(open_lsn) && (ret = - __log_c_get(logc, &open_lsn, &data, DB_SET)) == 0 && - log_compare(&min, &open_lsn) < 0) { - /* Format the log record. */ - if ((ret = __txn_ckp_read(dbenv, - data.data, &ckp_args)) != 0) { - __db_err(dbenv, - "Invalid checkpoint record at [%lu][%lu]", - (u_long)open_lsn.file, - (u_long)open_lsn.offset); + /* + * Figure out the last checkpoint before the smallest + * start_lsn in the region. + */ + logc = NULL; + if ((ret = __log_cursor(dbenv, &logc)) != 0) + goto err; + + memset(&data, 0, sizeof(data)); + if ((ret = __txn_getckp(dbenv, &open_lsn)) == 0) + while (!IS_ZERO_LSN(open_lsn) && (ret = + __log_c_get(logc, &open_lsn, &data, DB_SET)) == 0 && + (force || + (min != NULL && log_compare(min, &open_lsn) < 0))) { + /* Format the log record. */ + if ((ret = __txn_ckp_read(dbenv, + data.data, &ckp_args)) != 0) { + __db_err(dbenv, + "Invalid checkpoint record at [%lu][%lu]", + (u_long)open_lsn.file, + (u_long)open_lsn.offset); + goto err; + } + /* + * If force is set, then we're forcing ourselves + * to go back far enough to open files. + * Use ckp_lsn and then break out of the loop. + */ + open_lsn = force ? ckp_args->ckp_lsn : + ckp_args->last_ckp; + __os_free(dbenv, ckp_args); + if (force) { + if ((ret = __log_c_get(logc, &open_lsn, + &data, DB_SET)) != 0) goto err; - } - open_lsn = ckp_args->last_ckp; - __os_free(dbenv, ckp_args); + break; } - - /* - * There are three ways by which we may have gotten here. - * - We got a DB_NOTFOUND -- we need to read the first - * log record. - * - We found a checkpoint before min. We're done. - * - We found a checkpoint after min who's last_ckp is 0. We - * need to start at the beginning of the log. - */ - if ((ret == DB_NOTFOUND || IS_ZERO_LSN(open_lsn)) && (ret = - __log_c_get(logc, &open_lsn, &data, DB_FIRST)) != 0) { - __db_err(dbenv, "No log records"); - goto err; } - if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txninfo)) != 0) - goto err; - ret = __env_openfiles(dbenv, logc, - txninfo, &data, &open_lsn, NULL, 0, 0); - if (txninfo != NULL) - __db_txnlist_end(dbenv, txninfo); + /* + * There are several ways by which we may have gotten here. + * - We got a DB_NOTFOUND -- we need to read the first + * log record. + * - We found a checkpoint before min. We're done. + * - We found a checkpoint after min who's last_ckp is 0. We + * need to start at the beginning of the log. + * - We are forcing an openfiles and we have our ckp_lsn. + */ + if ((ret == DB_NOTFOUND || IS_ZERO_LSN(open_lsn)) && (ret = + __log_c_get(logc, &open_lsn, &data, DB_FIRST)) != 0) { + __db_err(dbenv, "No log records"); + goto err; } -err: F_CLR((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER); + if ((ret = __db_txnlist_init(dbenv, 0, 0, NULL, &txninfo)) != 0) + goto err; + ret = __env_openfiles(dbenv, logc, + txninfo, &data, &open_lsn, NULL, 0, 0); + if (txninfo != NULL) + __db_txnlist_end(dbenv, txninfo); +err: if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0) ret = t_ret; - return (ret); } diff --git a/db/txn/txn_region.c b/db/txn/txn_region.c index 16b26a469..55a5310f9 100644 --- a/db/txn/txn_region.c +++ b/db/txn/txn_region.c @@ -1,16 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. + * + * $Id: txn_region.c,v 11.86 2004/09/22 17:41:10 bostic Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_region.c,v 11.79 2003/07/23 13:13:12 mjc Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> @@ -32,7 +30,6 @@ static const char revid[] = "$Id: txn_region.c,v 11.79 2003/07/23 13:13:12 mjc E #include "dbinc/log.h" #include "dbinc/txn.h" -static int __txn_findlastckp __P((DB_ENV *, DB_LSN *)); static int __txn_init __P((DB_ENV *, DB_TXNMGR *)); static size_t __txn_region_size __P((DB_ENV *)); @@ -56,9 +53,9 @@ __txn_open(dbenv) tmgrp->dbenv = dbenv; /* Join/create the txn region. */ + tmgrp->reginfo.dbenv = dbenv; tmgrp->reginfo.type = REGION_TYPE_TXN; tmgrp->reginfo.id = INVALID_REGION_ID; - tmgrp->reginfo.mode = dbenv->db_mode; tmgrp->reginfo.flags = REGION_JOIN_OK; if (F_ISSET(dbenv, DB_ENV_CREATE)) F_SET(&tmgrp->reginfo, REGION_CREATE_OK); @@ -73,7 +70,7 @@ __txn_open(dbenv) /* Set the local addresses. */ tmgrp->reginfo.primary = - R_ADDR(&tmgrp->reginfo, tmgrp->reginfo.rp->primary); + R_ADDR(dbenv, &tmgrp->reginfo, tmgrp->reginfo.rp->primary); /* Acquire a mutex to protect the active TXN list. */ if (F_ISSET(dbenv, DB_ENV_THREAD) && @@ -131,18 +128,18 @@ __txn_init(dbenv, tmgrp) * the last log file until we find the last checkpoint. */ if (IS_ZERO_LSN(last_ckp) && - (ret = __txn_findlastckp(dbenv, &last_ckp)) != 0) + (ret = __txn_findlastckp(dbenv, &last_ckp, NULL)) != 0) return (ret); } - if ((ret = __db_shalloc(tmgrp->reginfo.addr, + if ((ret = __db_shalloc(&tmgrp->reginfo, sizeof(DB_TXNREGION), 0, &tmgrp->reginfo.primary)) != 0) { __db_err(dbenv, "Unable to allocate memory for the transaction region"); return (ret); } tmgrp->reginfo.rp->primary = - R_OFFSET(&tmgrp->reginfo, tmgrp->reginfo.primary); + R_OFFSET(dbenv, &tmgrp->reginfo, tmgrp->reginfo.primary); region = tmgrp->reginfo.primary; memset(region, 0, sizeof(*region)); @@ -158,14 +155,14 @@ __txn_init(dbenv, tmgrp) SH_TAILQ_INIT(®ion->active_txn); #ifdef HAVE_MUTEX_SYSTEM_RESOURCES /* Allocate room for the txn maintenance info and initialize it. */ - if ((ret = __db_shalloc(tmgrp->reginfo.addr, + if ((ret = __db_shalloc(&tmgrp->reginfo, sizeof(REGMAINT) + TXN_MAINT_SIZE, 0, &addr)) != 0) { __db_err(dbenv, "Unable to allocate memory for mutex maintenance"); return (ret); } __db_maintinit(&tmgrp->reginfo, addr, TXN_MAINT_SIZE); - region->maint_off = R_OFFSET(&tmgrp->reginfo, addr); + region->maint_off = R_OFFSET(dbenv, &tmgrp->reginfo, addr); #endif return (0); } @@ -173,13 +170,16 @@ __txn_init(dbenv, tmgrp) /* * __txn_findlastckp -- * Find the last checkpoint in the log, walking backwards from the - * beginning of the last log file. (The log system looked through - * the last log file when it started up.) + * max_lsn given or the beginning of the last log file. (The + * log system looked through the last log file when it started up.) + * + * PUBLIC: int __txn_findlastckp __P((DB_ENV *, DB_LSN *, DB_LSN *)); */ -static int -__txn_findlastckp(dbenv, lsnp) +int +__txn_findlastckp(dbenv, lsnp, max_lsn) DB_ENV *dbenv; DB_LSN *lsnp; + DB_LSN *max_lsn; { DB_LOGC *logc; DB_LSN lsn; @@ -192,15 +192,22 @@ __txn_findlastckp(dbenv, lsnp) /* Get the last LSN. */ memset(&dbt, 0, sizeof(dbt)); - if ((ret = __log_c_get(logc, &lsn, &dbt, DB_LAST)) != 0) - goto err; - - /* - * Twiddle the last LSN so it points to the beginning of the last - * file; we know there's no checkpoint after that, since the log - * system already looked there. - */ - lsn.offset = 0; + if (max_lsn != NULL) { + lsn = *max_lsn; + ZERO_LSN(*lsnp); + if ((ret = __log_c_get(logc, &lsn, &dbt, DB_SET)) != 0) + goto err; + } else { + if ((ret = __log_c_get(logc, &lsn, &dbt, DB_LAST)) != 0) + goto err; + /* + * Twiddle the last LSN so it points to the + * beginning of the last file; we know there's + * no checkpoint after that, since the log + * system already looked there. + */ + lsn.offset = 0; + } /* Read backwards, looking for checkpoints. */ while ((ret = __log_c_get(logc, &lsn, &dbt, DB_PREV)) == 0) { @@ -225,7 +232,6 @@ err: if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) /* * __txn_dbenv_refresh -- * Clean up after the transaction system on a close or failed open. - * Called only from __dbenv_refresh. (Formerly called __txn_close.) * * PUBLIC: int __txn_dbenv_refresh __P((DB_ENV *)); */ @@ -235,12 +241,14 @@ __txn_dbenv_refresh(dbenv) { DB_TXN *txnp; DB_TXNMGR *tmgrp; + REGINFO *reginfo; TXN_DETAIL *td; u_int32_t txnid; int aborted, ret, t_ret; ret = 0; tmgrp = dbenv->tx_handle; + reginfo = &tmgrp->reginfo; /* * This function can only be called once per process (i.e., not @@ -257,7 +265,7 @@ __txn_dbenv_refresh(dbenv) if (TAILQ_FIRST(&tmgrp->txn_chain) != NULL) { while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL) { /* Prepared transactions are OK. */ - td = (TXN_DETAIL *)R_ADDR(&tmgrp->reginfo, txnp->off); + td = (TXN_DETAIL *)R_ADDR(dbenv, reginfo, txnp->off); txnid = txnp->txnid; if (td->status == TXN_PREPARED) { if ((ret = __txn_discard(txnp, 0)) != 0) { @@ -292,10 +300,10 @@ __txn_dbenv_refresh(dbenv) /* Discard the per-thread lock. */ if (tmgrp->mutexp != NULL) - __db_mutex_free(dbenv, &tmgrp->reginfo, tmgrp->mutexp); + __db_mutex_free(dbenv, reginfo, tmgrp->mutexp); /* Detach from the region. */ - if ((t_ret = __db_r_detach(dbenv, &tmgrp->reginfo, 0)) != 0 && ret == 0) + if ((t_ret = __db_r_detach(dbenv, reginfo, 0)) != 0 && ret == 0) ret = t_ret; __os_free(dbenv, tmgrp); @@ -338,11 +346,26 @@ __txn_region_destroy(dbenv, infop) DB_ENV *dbenv; REGINFO *infop; { - __db_shlocks_destroy(infop, (REGMAINT *)R_ADDR(infop, - ((DB_TXNREGION *)R_ADDR(infop, infop->rp->primary))->maint_off)); + /* + * This routine is called in two cases: when discarding the mutexes + * from a previous Berkeley DB run, during recovery, and two, when + * discarding the mutexes as we shut down the database environment. + * In the latter case, we also need to discard shared memory segments, + * this is the last time we use them, and the last region-specific + * call we make. + */ +#ifdef HAVE_MUTEX_SYSTEM_RESOURCES + DB_TXNREGION *region; - COMPQUIET(dbenv, NULL); - COMPQUIET(infop, NULL); + region = R_ADDR(dbenv, infop, infop->rp->primary); + + __db_shlocks_destroy(infop, R_ADDR(dbenv, infop, region->maint_off)); + if (infop->primary != NULL && F_ISSET(dbenv, DB_ENV_PRIVATE)) + __db_shalloc_free(infop, + R_ADDR(dbenv, infop, region->maint_off)); +#endif + if (infop->primary != NULL && F_ISSET(dbenv, DB_ENV_PRIVATE)) + __db_shalloc_free(infop, infop->primary); } /* diff --git a/db/txn/txn_stat.c b/db/txn/txn_stat.c index 905a2a5eb..e9536b67c 100644 --- a/db/txn/txn_stat.c +++ b/db/txn/txn_stat.c @@ -1,27 +1,44 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2003 + * Copyright (c) 1996-2004 * Sleepycat Software. All rights reserved. + * + * $Id: txn_stat.c,v 11.36 2004/09/15 21:49:21 mjc Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_stat.c,v 11.22 2003/09/13 19:20:43 bostic Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> +#if TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif + +#include <stdlib.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 __txn_stat __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); +#ifdef HAVE_STATISTICS +static int __txn_compare __P((const void *, const void *)); +static int __txn_print_all __P((DB_ENV *, u_int32_t)); +static int __txn_print_stats __P((DB_ENV *, u_int32_t)); +static int __txn_stat __P((DB_ENV *, DB_TXN_STAT **, u_int32_t)); +static void __txn_xid_stats __P((DB_ENV *, DB_MSGBUF *, DB_TXN_ACTIVE *)); /* * __txn_stat_pp -- @@ -38,7 +55,8 @@ __txn_stat_pp(dbenv, statp, flags) int rep_check, ret; PANIC_CHECK(dbenv); - ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "txn_stat", DB_INIT_TXN); + ENV_REQUIRES_CONFIG(dbenv, + dbenv->tx_handle, "DB_ENV->txn_stat", DB_INIT_TXN); if ((ret = __db_fchk(dbenv, "DB_ENV->txn_stat", flags, DB_STAT_CLEAR)) != 0) @@ -49,7 +67,7 @@ __txn_stat_pp(dbenv, statp, flags) __env_rep_enter(dbenv); ret = __txn_stat(dbenv, statp, flags); if (rep_check) - __env_rep_exit(dbenv); + __env_db_rep_exit(dbenv); return (ret); } @@ -106,7 +124,7 @@ __txn_stat(dbenv, statp, flags) stats->st_txnarray[ndx].parentid = TXN_INVALID; else stats->st_txnarray[ndx].parentid = - ((TXN_DETAIL *)R_ADDR(&mgr->reginfo, + ((TXN_DETAIL *)R_ADDR(dbenv, &mgr->reginfo, txnp->parent))->txnid; stats->st_txnarray[ndx].lsn = txnp->begin_lsn; if ((stats->st_txnarray[ndx].xa_status = txnp->xa_status) != 0) @@ -131,3 +149,282 @@ __txn_stat(dbenv, statp, flags) *statp = stats; return (0); } + +/* + * __txn_stat_print_pp -- + * DB_ENV->txn_stat_print pre/post processing. + * + * PUBLIC: int __txn_stat_print_pp __P((DB_ENV *, u_int32_t)); + */ +int +__txn_stat_print_pp(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + int rep_check, ret; + + PANIC_CHECK(dbenv); + ENV_REQUIRES_CONFIG(dbenv, + dbenv->tx_handle, "DB_ENV->txn_stat_print", DB_INIT_TXN); + + if ((ret = __db_fchk(dbenv, "DB_ENV->txn_stat", + flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0) + return (ret); + + rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0; + if (rep_check) + __env_rep_enter(dbenv); + ret = __txn_stat_print(dbenv, flags); + if (rep_check) + __env_db_rep_exit(dbenv); + return (ret); +} + +/* + * __txn_stat_print + * DB_ENV->txn_stat_print method. + * + * PUBLIC: int __txn_stat_print __P((DB_ENV *, u_int32_t)); + */ +int +__txn_stat_print(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + u_int32_t orig_flags; + int ret; + + orig_flags = flags; + LF_CLR(DB_STAT_CLEAR); + if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { + ret = __txn_print_stats(dbenv, orig_flags); + if (flags == 0 || ret != 0) + return (ret); + } + + if (LF_ISSET(DB_STAT_ALL) && + (ret = __txn_print_all(dbenv, orig_flags)) != 0) + return (ret); + + return (0); +} + +/* + * __txn_print_stats -- + * Display default transaction region statistics. + */ +static int +__txn_print_stats(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + DB_MSGBUF mb; + DB_TXN_STAT *sp; + u_int32_t i; + int ret; + + if ((ret = __txn_stat(dbenv, &sp, flags)) != 0) + return (ret); + + if (LF_ISSET(DB_STAT_ALL)) + __db_msg(dbenv, "Default transaction region information:"); + __db_msg(dbenv, "%lu/%lu\t%s", + (u_long)sp->st_last_ckp.file, (u_long)sp->st_last_ckp.offset, + sp->st_last_ckp.file == 0 ? + "No checkpoint LSN" : "File/offset for last checkpoint LSN"); + if (sp->st_time_ckp == 0) + __db_msg(dbenv, "0\tNo checkpoint timestamp"); + else + __db_msg(dbenv, "%.24s\tCheckpoint timestamp", + ctime(&sp->st_time_ckp)); + __db_msg(dbenv, "%#lx\tLast transaction ID allocated", + (u_long)sp->st_last_txnid); + __db_dl(dbenv, "Maximum number of active transactions configured", + (u_long)sp->st_maxtxns); + __db_dl(dbenv, "Active transactions", (u_long)sp->st_nactive); + __db_dl(dbenv, + "Maximum active transactions", (u_long)sp->st_maxnactive); + __db_dl(dbenv, + "Number of transactions begun", (u_long)sp->st_nbegins); + __db_dl(dbenv, + "Number of transactions aborted", (u_long)sp->st_naborts); + __db_dl(dbenv, + "Number of transactions committed", (u_long)sp->st_ncommits); + __db_dl(dbenv, + "Number of transactions restored", (u_long)sp->st_nrestores); + + __db_dlbytes(dbenv, "Transaction region size", + (u_long)0, (u_long)0, (u_long)sp->st_regsize); + __db_dl_pct(dbenv, + "The number of region locks that required waiting", + (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait, + sp->st_region_wait + sp->st_region_nowait), NULL); + + qsort(sp->st_txnarray, + sp->st_nactive, sizeof(sp->st_txnarray[0]), __txn_compare); + __db_msg(dbenv, "List of active transactions:"); + DB_MSGBUF_INIT(&mb); + for (i = 0; i < sp->st_nactive; ++i) { + __db_msgadd(dbenv, + &mb, "\tID: %lx; begin LSN: file/offset %lu/%lu", + (u_long)sp->st_txnarray[i].txnid, + (u_long)sp->st_txnarray[i].lsn.file, + (u_long)sp->st_txnarray[i].lsn.offset); + if (sp->st_txnarray[i].parentid != 0) + __db_msgadd(dbenv, &mb, "; parent: %lx", + (u_long)sp->st_txnarray[i].parentid); + if (sp->st_txnarray[i].xa_status != 0) + __txn_xid_stats(dbenv, &mb, &sp->st_txnarray[i]); + DB_MSGBUF_FLUSH(dbenv, &mb); + } + + __os_ufree(dbenv, sp); + + return (0); +} + +/* + * __txn_print_all -- + * Display debugging transaction region statistics. + */ +static int +__txn_print_all(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + static const FN fn[] = { + { TXN_IN_RECOVERY, "TXN_IN_RECOVERY" }, + { 0, NULL } + }; + DB_TXNMGR *mgr; + DB_TXNREGION *region; + + mgr = dbenv->tx_handle; + region = mgr->reginfo.primary; + + R_LOCK(dbenv, &mgr->reginfo); + + __db_print_reginfo(dbenv, &mgr->reginfo, "Transaction"); + + __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); + __db_msg(dbenv, "DB_TXNMGR handle information:"); + + __db_print_mutex(dbenv, NULL, mgr->mutexp, "DB_TXNMGR mutex", flags); + __db_dl(dbenv, + "Number of transactions discarded", (u_long)mgr->n_discards); + + __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); + __db_msg(dbenv, "DB_TXNREGION handle information:"); + STAT_ULONG("Maximum number of active txns", region->maxtxns); + STAT_HEX("Last transaction ID allocated", region->last_txnid); + STAT_HEX("Current maximum unused ID", region->cur_maxid); + + STAT_LSN("Last checkpoint LSN", ®ion->last_ckp); + __db_msg(dbenv, + "%.24s\tLast checkpoint timestamp", + region->time_ckp == 0 ? "0" : ctime(®ion->time_ckp)); + + __db_prflags(dbenv, NULL, region->flags, fn, NULL, "\tFlags"); + + __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); + __db_msg(dbenv, "XA information:"); + STAT_LONG("XA RMID", dbenv->xa_rmid); + /* + * XXX + * Display list of XA transactions in the DB_ENV handle. + */ + + R_UNLOCK(dbenv, &mgr->reginfo); + + return (0); +} + +static void +__txn_xid_stats(dbenv, mbp, txnp) + DB_ENV *dbenv; + DB_MSGBUF *mbp; + DB_TXN_ACTIVE *txnp; +{ + u_int32_t v, *xp; + u_int i; + int cnt; + const char *s; + + switch (txnp->xa_status) { + case TXN_XA_ABORTED: + s = "ABORTED"; + break; + case TXN_XA_DEADLOCKED: + s = "DEADLOCKED"; + break; + case TXN_XA_ENDED: + s = "ENDED"; + break; + case TXN_XA_PREPARED: + s = "PREPARED"; + break; + case TXN_XA_STARTED: + s = "STARTED"; + break; + case TXN_XA_SUSPENDED: + s = "SUSPENDED"; + break; + default: + s = "UNKNOWN STATE"; + __db_err(dbenv, + "XA: unknown state: %lu", (u_long)txnp->xa_status); + break; + } + __db_msgadd(dbenv, mbp, "\tXA: %s; XID:\n\t\t", s == NULL ? "" : s); + for (cnt = 0, xp = (u_int32_t *)txnp->xid, + i = 0; i < DB_XIDDATASIZE; i += sizeof(u_int32_t)) { + memcpy(&v, xp++, sizeof(u_int32_t)); + __db_msgadd(dbenv, mbp, "%#x ", v); + if (++cnt == 4) { + DB_MSGBUF_FLUSH(dbenv, mbp); + __db_msgadd(dbenv, mbp, "\t\t"); + cnt = 0; + } + } +} + +static int +__txn_compare(a1, b1) + const void *a1, *b1; +{ + const DB_TXN_ACTIVE *a, *b; + + a = a1; + b = b1; + + if (a->txnid > b->txnid) + return (1); + if (a->txnid < b->txnid) + return (-1); + return (0); +} + +#else /* !HAVE_STATISTICS */ + +int +__txn_stat_pp(dbenv, statp, flags) + DB_ENV *dbenv; + DB_TXN_STAT **statp; + u_int32_t flags; +{ + COMPQUIET(statp, NULL); + COMPQUIET(flags, 0); + + return (__db_stat_not_built(dbenv)); +} + +int +__txn_stat_print_pp(dbenv, flags) + DB_ENV *dbenv; + u_int32_t flags; +{ + COMPQUIET(flags, 0); + + return (__db_stat_not_built(dbenv)); +} +#endif diff --git a/db/txn/txn_util.c b/db/txn/txn_util.c index 1a9e901f5..ff94cd7db 100644 --- a/db/txn/txn_util.c +++ b/db/txn/txn_util.c @@ -1,16 +1,14 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001-2003 + * Copyright (c) 2001-2004 * Sleepycat Software. All rights reserved. + * + * $Id: txn_util.c,v 11.28 2004/09/16 17:55:19 margo Exp $ */ #include "db_config.h" -#ifndef lint -static const char revid[] = "$Id: txn_util.c,v 11.25 2003/12/03 14:33:07 bostic Exp $"; -#endif /* not lint */ - #ifndef NO_SYSTEM_INCLUDES #include <sys/types.h> #include <string.h> @@ -280,8 +278,8 @@ __txn_doevents(dbenv, txn, opcode, preprocess) case TXN_CLOSE: /* If we didn't abort this txn, we screwed up badly. */ DB_ASSERT(opcode == TXN_ABORT); - if ((t_ret = - __db_close(e->u.c.dbp, NULL, 0)) != 0 && ret == 0) + if ((t_ret = __db_close(e->u.c.dbp, + NULL, DB_NOSYNC)) != 0 && ret == 0) ret = t_ret; break; case TXN_REMOVE: @@ -315,7 +313,9 @@ dofree: __os_free(dbenv, e->u.r.fileid); __os_free(dbenv, e->u.r.name); break; - + case TXN_CLOSE: + case TXN_TRADE: + case TXN_TRADED: default: break; } |