diff options
author | Panu Matilainen <pmatilai@redhat.com> | 2007-07-30 11:58:31 +0300 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2007-07-30 11:58:31 +0300 |
commit | cab228435bde1b5496522c03a4ce9840f2ef3701 (patch) | |
tree | 2c37b65d176e2de097603333f4de071c31eeff3d /db/txn | |
parent | 2d07882d45e9e575c00f8f402d4c7271bb65cfe9 (diff) | |
download | librpm-tizen-cab228435bde1b5496522c03a4ce9840f2ef3701.tar.gz librpm-tizen-cab228435bde1b5496522c03a4ce9840f2ef3701.tar.bz2 librpm-tizen-cab228435bde1b5496522c03a4ce9840f2ef3701.zip |
Update internal BDB to version 4.6.18.
Diffstat (limited to 'db/txn')
-rw-r--r-- | db/txn/txn.c | 240 | ||||
-rw-r--r-- | db/txn/txn.src | 28 | ||||
-rw-r--r-- | db/txn/txn_auto.c | 48 | ||||
-rw-r--r-- | db/txn/txn_autop.c | 20 | ||||
-rw-r--r-- | db/txn/txn_chkpt.c | 93 | ||||
-rw-r--r-- | db/txn/txn_failchk.c | 11 | ||||
-rw-r--r-- | db/txn/txn_method.c | 17 | ||||
-rw-r--r-- | db/txn/txn_rec.c | 71 | ||||
-rw-r--r-- | db/txn/txn_recover.c | 72 | ||||
-rw-r--r-- | db/txn/txn_region.c | 82 | ||||
-rw-r--r-- | db/txn/txn_stat.c | 14 | ||||
-rw-r--r-- | db/txn/txn_util.c | 132 |
12 files changed, 533 insertions, 295 deletions
diff --git a/db/txn/txn.c b/db/txn/txn.c index 527c483d1..2154f0962 100644 --- a/db/txn/txn.c +++ b/db/txn/txn.c @@ -1,8 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. */ /* * Copyright (c) 1995, 1996 @@ -35,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: txn.c,v 12.55 2006/08/24 14:46:52 bostic Exp $ + * $Id: txn.c,v 12.78 2007/06/29 00:25:02 margo Exp $ */ #include "db_config.h" @@ -50,21 +49,10 @@ #include "dbinc/mp.h" #include "dbinc/txn.h" -#define SET_LOG_FLAGS(dbenv, txn, lflags) \ - do { \ - lflags = DB_LOG_COMMIT; \ - if (F_ISSET(txn, TXN_SYNC)) \ - lflags |= DB_FLUSH; \ - else if (F_ISSET(txn, TXN_WRITE_NOSYNC)) \ - lflags |= DB_LOG_WRNOSYNC; \ - else if (!F_ISSET(txn, TXN_NOSYNC) && \ - !F_ISSET(dbenv, DB_ENV_TXN_NOSYNC)) { \ - if (F_ISSET(dbenv, DB_ENV_TXN_WRITE_NOSYNC)) \ - lflags |= DB_LOG_WRNOSYNC; \ - else \ - lflags |= DB_FLUSH; \ - } \ - } while (0) +#define LOG_FLAGS(txn) \ + (DB_LOG_COMMIT | (F_ISSET(txn, TXN_SYNC) ? \ + DB_FLUSH : (F_ISSET(txn, TXN_WRITE_NOSYNC) ? \ + DB_LOG_WRNOSYNC : 0))) /* * __txn_isvalid enumerated types. We cannot simply use the transaction @@ -79,11 +67,11 @@ typedef enum { } txnop_t; static int __txn_abort_pp __P((DB_TXN *)); -static int __txn_begin_int __P((DB_TXN *, int)); +static int __txn_begin_int __P((DB_TXN *)); static int __txn_commit_pp __P((DB_TXN *, u_int32_t)); static int __txn_discard __P((DB_TXN *, u_int32_t)); static int __txn_dispatch_undo - __P((DB_ENV *, DB_TXN *, DBT *, DB_LSN *, void *)); + __P((DB_ENV *, DB_TXN *, DBT *, DB_LSN *, DB_TXNHEAD *)); static int __txn_end __P((DB_TXN *, int)); static int __txn_isvalid __P((const DB_TXN *, txnop_t)); static int __txn_undo __P((DB_TXN *)); @@ -109,9 +97,9 @@ __txn_begin_pp(dbenv, parent, txnpp, flags) if ((ret = __db_fchk(dbenv, "txn_begin", flags, - DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_TXN_NOWAIT | + DB_READ_COMMITTED | DB_READ_UNCOMMITTED | DB_TXN_NOSYNC | DB_TXN_SNAPSHOT | DB_TXN_SYNC | - DB_TXN_WRITE_NOSYNC)) != 0) + DB_TXN_WAIT | DB_TXN_WRITE_NOSYNC | DB_TXN_NOWAIT)) != 0) return (ret); if ((ret = __db_fcchk(dbenv, "txn_begin", flags, DB_TXN_WRITE_NOSYNC | DB_TXN_NOSYNC, DB_TXN_SYNC)) != 0) @@ -182,23 +170,36 @@ __txn_begin(dbenv, parent, txnpp, flags) TAILQ_INIT(&txn->events); STAILQ_INIT(&txn->logs); txn->flags = TXN_MALLOC; + + /* + * Set the sync mode for commit. Any local bits override those + * in the environment. SYNC is the default. + */ + if (LF_ISSET(DB_TXN_SYNC)) + F_SET(txn, TXN_SYNC); + else if (LF_ISSET(DB_TXN_NOSYNC)) + F_SET(txn, TXN_NOSYNC); + else if (LF_ISSET(DB_TXN_WRITE_NOSYNC)) + F_SET(txn, TXN_WRITE_NOSYNC); + else if (F_ISSET(dbenv, DB_ENV_TXN_NOSYNC)) + F_SET(txn, TXN_NOSYNC); + else if (F_ISSET(dbenv, DB_ENV_TXN_WRITE_NOSYNC)) + F_SET(txn, TXN_WRITE_NOSYNC); + else + F_SET(txn, TXN_SYNC); + + if (LF_ISSET(DB_TXN_NOWAIT) || + (F_ISSET(dbenv, DB_ENV_TXN_NOWAIT) && !LF_ISSET(DB_TXN_WAIT))) + F_SET(txn, TXN_NOWAIT); if (LF_ISSET(DB_READ_COMMITTED)) F_SET(txn, TXN_READ_COMMITTED); if (LF_ISSET(DB_READ_UNCOMMITTED)) F_SET(txn, TXN_READ_UNCOMMITTED); - if (LF_ISSET(DB_TXN_NOSYNC)) - F_SET(txn, TXN_NOSYNC); if (LF_ISSET(DB_TXN_SNAPSHOT) || F_ISSET(dbenv, DB_ENV_TXN_SNAPSHOT) || (parent != NULL && F_ISSET(parent, TXN_SNAPSHOT))) F_SET(txn, TXN_SNAPSHOT); - if (LF_ISSET(DB_TXN_SYNC)) - F_SET(txn, TXN_SYNC); - if (LF_ISSET(DB_TXN_NOWAIT)) - F_SET(txn, TXN_NOWAIT); - if (LF_ISSET(DB_TXN_WRITE_NOSYNC)) - F_SET(txn, TXN_WRITE_NOSYNC); - if ((ret = __txn_begin_int(txn, 0)) != 0) + if ((ret = __txn_begin_int(txn)) != 0) goto err; td = txn->td; @@ -212,7 +213,7 @@ __txn_begin(dbenv, parent, txnpp, flags) region = dbenv->lk_handle->reginfo.primary; if (parent != NULL) { ret = __lock_inherit_timeout(dbenv, - parent->txnid, txn->txnid); + parent->locker, txn->locker); /* No parent locker set yet. */ if (ret == EINVAL) { parent = NULL; @@ -227,7 +228,7 @@ __txn_begin(dbenv, parent, txnpp, flags) * or it has no timeouts set. */ if (parent == NULL && region->tx_timeout != 0) - if ((ret = __lock_set_timeout(dbenv, txn->txnid, + if ((ret = __lock_set_timeout(dbenv, txn->locker, region->tx_timeout, DB_SET_TXN_TIMEOUT)) != 0) goto err; } @@ -267,7 +268,7 @@ __txn_xa_begin(dbenv, txn) memset(&txn->lock_timeout, 0, sizeof(db_timeout_t)); memset(&txn->expire, 0, sizeof(db_timeout_t)); - return (__txn_begin_int(txn, 0)); + return (__txn_begin_int(txn)); } /* @@ -342,7 +343,7 @@ __txn_compensate_begin(dbenv, txnpp) txn->flags = TXN_COMPENSATE | TXN_MALLOC; *txnpp = txn; - return (__txn_begin_int(txn, 1)); + return (__txn_begin_int(txn)); } /* @@ -350,9 +351,8 @@ __txn_compensate_begin(dbenv, txnpp) * Normal DB version of txn_begin. */ static int -__txn_begin_int(txn, internal) +__txn_begin_int(txn) DB_TXN *txn; - int internal; { DB_ENV *dbenv; DB_TXNMGR *mgr; @@ -372,14 +372,6 @@ __txn_begin_int(txn, internal) goto err; } - /* Make sure that we aren't still recovering prepared transactions. */ - if (!internal && region->stat.st_nrestores != 0) { - __db_errx(dbenv, - "recovery of prepared but not yet committed transactions is incomplete"); - ret = EINVAL; - goto err; - } - /* * Allocate a new transaction id. Our current valid range can span * the maximum valid value, so check for it and wrap manually. @@ -394,7 +386,7 @@ __txn_begin_int(txn, internal) /* Allocate a new transaction detail structure. */ if ((ret = - __db_shalloc(&mgr->reginfo, sizeof(TXN_DETAIL), 0, &td)) != 0) { + __env_alloc(&mgr->reginfo, sizeof(TXN_DETAIL), &td)) != 0) { __db_errx(dbenv, "Unable to allocate memory for transaction detail"); goto err; @@ -404,12 +396,21 @@ __txn_begin_int(txn, internal) SH_TAILQ_INSERT_HEAD(®ion->active_txn, td, links, __txn_detail); id = ++region->last_txnid; + +#ifdef HAVE_STATISTICS ++region->stat.st_nbegins; if (++region->stat.st_nactive > region->stat.st_maxnactive) region->stat.st_maxnactive = region->stat.st_nactive; +#endif td->txnid = id; dbenv->thread_id(dbenv, &td->pid, &td->tid); + + /* allocate a locker for this txn */ + if (LOCKING_ON(dbenv) && (ret = + __lock_getlocker(dbenv->lk_handle, id, 1, &txn->locker)) != 0) + goto err; + ZERO_LSN(td->last_lsn); ZERO_LSN(td->begin_lsn); SH_TAILQ_INIT(&td->kids); @@ -425,6 +426,9 @@ __txn_begin_int(txn, internal) td->status = TXN_RUNNING; td->flags = 0; td->xa_status = 0; + td->nlog_dbs = 0; + td->nlog_slots = TXN_NSLOTS; + td->log_dbs = R_OFFSET(&mgr->reginfo, td->slots); TXN_SYSTEM_UNLOCK(dbenv); @@ -467,14 +471,18 @@ err: TXN_SYSTEM_UNLOCK(dbenv); * Fill in the fields of the local transaction structure given * the detail transaction structure. * - * PUBLIC: void __txn_continue __P((DB_ENV *, DB_TXN *, TXN_DETAIL *)); + * PUBLIC: int __txn_continue __P((DB_ENV *, DB_TXN *, TXN_DETAIL *)); */ -void +int __txn_continue(env, txn, td) DB_ENV *env; DB_TXN *txn; TXN_DETAIL *td; { + int ret; + + ret = 0; + txn->mgrp = env->tx_handle; txn->parent = NULL; txn->txnid = td->txnid; @@ -489,8 +497,19 @@ __txn_continue(env, txn, td) txn->set_name = __txn_set_name; txn->flags = 0; + /* + * If this is a restored transaction, we need to propagate that fact + * to the process-local structure. However, if it's not a restored + * transaction, then we're running in XA and we need to make sure + * that we have a locker associated with this transaction. + */ if (F_ISSET(td, TXN_DTL_RESTORED)) F_SET(txn, TXN_RESTORED); + else + ret = __lock_getlocker(env->lk_handle, + txn->txnid, 0, &txn->locker); + + return (ret); } /* @@ -537,7 +556,7 @@ __txn_commit(txn, flags) REGENV *renv; REGINFO *infop; TXN_DETAIL *td; - u_int32_t id, lflags; + u_int32_t id; int ret, t_ret; dbenv = txn->mgrp->dbenv; @@ -550,7 +569,7 @@ __txn_commit(txn, flags) * return. If the transaction deadlocked, they want abort, not commit. */ if (F_ISSET(txn, TXN_DEADLOCK)) { - ret = __db_txn_deadlock_err(dbenv); + ret = __db_txn_deadlock_err(dbenv, txn); goto err; } @@ -633,13 +652,13 @@ __txn_commit(txn, flags) request.obj = &list_dbt; } ret = __lock_vec(dbenv, - txn->txnid, 0, &request, 1, NULL); + txn->locker, 0, &request, 1, NULL); } if (ret == 0 && !IS_ZERO_LSN(td->last_lsn)) { - SET_LOG_FLAGS(dbenv, txn, lflags); ret = __txn_regop_log(dbenv, txn, - &td->visible_lsn, lflags, TXN_COMMIT, + &td->visible_lsn, LOG_FLAGS(txn), + TXN_COMMIT, (int32_t)time(NULL), id, request.obj); if (ret == 0) td->last_lsn = td->visible_lsn; @@ -762,7 +781,7 @@ __txn_abort(txn) REGENV *renv; REGINFO *infop; TXN_DETAIL *td; - u_int32_t id, lflags; + u_int32_t id; int ret; dbenv = txn->mgrp->dbenv; @@ -806,6 +825,11 @@ __txn_abort(txn) } if (LOCKING_ON(dbenv)) { + /* Allocate a locker for this restored txn if necessary. */ + if (txn->locker == NULL && + (ret = __lock_getlocker(dbenv->lk_handle, + txn->txnid, 1, &txn->locker)) != 0) + return (__db_panic(dbenv, ret)); /* * We are about to free all the read locks for this transaction * below. Some of those locks might be handle locks which @@ -818,17 +842,17 @@ __txn_abort(txn) /* Turn off timeouts. */ if ((ret = __lock_set_timeout(dbenv, - txn->txnid, 0, DB_SET_TXN_TIMEOUT)) != 0) + txn->locker, 0, DB_SET_TXN_TIMEOUT)) != 0) return (__db_panic(dbenv, ret)); if ((ret = __lock_set_timeout(dbenv, - txn->txnid, 0, DB_SET_LOCK_TIMEOUT)) != 0) + txn->locker, 0, DB_SET_LOCK_TIMEOUT)) != 0) return (__db_panic(dbenv, ret)); request.op = DB_LOCK_UPGRADE_WRITE; request.obj = NULL; if ((ret = __lock_vec( - dbenv, txn->txnid, DB_LOCK_ABORT, &request, 1, NULL)) != 0) + dbenv, txn->locker, DB_LOCK_ABORT, &request, 1, NULL)) != 0) return (__db_panic(dbenv, ret)); } undo: if ((ret = __txn_undo(txn)) != 0) @@ -840,10 +864,9 @@ undo: if ((ret = __txn_undo(txn)) != 0) * then we log the abort so we know that this transaction * was actually completed. */ -done: SET_LOG_FLAGS(dbenv, txn, lflags); - if (DBENV_LOGGING(dbenv) && td->status == TXN_PREPARED && +done: if (DBENV_LOGGING(dbenv) && td->status == TXN_PREPARED && (ret = __txn_regop_log(dbenv, txn, &td->last_lsn, - lflags, TXN_ABORT, (int32_t)time(NULL), id, NULL)) != 0) + LOG_FLAGS(txn), TXN_ABORT, (int32_t)time(NULL), id, NULL)) != 0) return (__db_panic(dbenv, ret)); /* __txn_end always panics if it errors, so pass the return along. */ @@ -861,12 +884,15 @@ __txn_discard(txn, flags) { DB_ENV *dbenv; DB_THREAD_INFO *ip; - int ret; + int ret, t_ret; dbenv = txn->mgrp->dbenv; ENV_ENTER(dbenv, ip); ret = __txn_discard_int(txn, flags); + if (IS_ENV_REPLICATED(dbenv) && + (t_ret = __op_rep_exit(dbenv)) != 0 && ret == 0) + ret = t_ret; ENV_LEAVE(dbenv, ip); return (ret); } @@ -943,7 +969,7 @@ __txn_prepare(txn, gid) if ((ret = __txn_isvalid(txn, TXN_OP_PREPARE)) != 0) return (ret); if (F_ISSET(txn, TXN_DEADLOCK)) - return (__db_txn_deadlock_err(dbenv)); + return (__db_txn_deadlock_err(dbenv, txn)); ENV_ENTER(dbenv, ip); @@ -971,13 +997,12 @@ __txn_prepare(txn, gid) memset(&request, 0, sizeof(request)); if (LOCKING_ON(dbenv)) { request.op = DB_LOCK_PUT_READ; - if (IS_REP_MASTER(dbenv) && - !IS_ZERO_LSN(td->last_lsn)) { + if (!IS_ZERO_LSN(td->last_lsn)) { memset(&list_dbt, 0, sizeof(list_dbt)); request.obj = &list_dbt; } if ((ret = __lock_vec(dbenv, - txn->txnid, 0, &request, 1, NULL)) != 0) + txn->locker, 0, &request, 1, NULL)) != 0) goto err; } @@ -1072,11 +1097,11 @@ __txn_set_name(txn, name) ENV_ENTER(dbenv, ip); TXN_SYSTEM_LOCK(dbenv); if (td->name != INVALID_ROFF) { - __db_shalloc_free( + __env_alloc_free( &mgr->reginfo, R_ADDR(&mgr->reginfo, td->name)); td->name = INVALID_ROFF; } - if ((ret = __db_shalloc(&mgr->reginfo, len, 0, &p)) != 0) { + if ((ret = __env_alloc(&mgr->reginfo, len, &p)) != 0) { TXN_SYSTEM_UNLOCK(dbenv); __db_errx(dbenv, "Unable to allocate memory for transaction name"); @@ -1116,15 +1141,17 @@ __txn_set_timeout(txn, timeout, op) db_timeout_t timeout; u_int32_t op; { + DB_ENV *dbenv; DB_THREAD_INFO *ip; int ret; - if (op != DB_SET_TXN_TIMEOUT && op != DB_SET_LOCK_TIMEOUT) - return (__db_ferr(txn->mgrp->dbenv, "DB_TXN->set_timeout", 0)); + dbenv = txn->mgrp->dbenv; - ENV_ENTER(txn->mgrp->dbenv, ip); - ret = __lock_set_timeout( - txn->mgrp->dbenv, txn->txnid, timeout, op); + if (op != DB_SET_TXN_TIMEOUT && op != DB_SET_LOCK_TIMEOUT) + return (__db_ferr(dbenv, "DB_TXN->set_timeout", 0)); + + ENV_ENTER(dbenv, ip); + ret = __lock_set_timeout( dbenv, txn->locker, timeout, op); ENV_LEAVE(txn->mgrp->dbenv, ip); return (ret); } @@ -1276,18 +1303,26 @@ __txn_end(txn, is_commit) * so DB_LOCK_DEADLOCK is just as fatal as any other error. */ if (LOCKING_ON(dbenv)) { + /* Allocate a locker for this restored txn if necessary. */ + if (txn->locker == NULL && + (ret = __lock_getlocker(dbenv->lk_handle, + txn->txnid, 1, &txn->locker)) != 0) + return (__db_panic(dbenv, ret)); request.op = txn->parent == NULL || is_commit == 0 ? DB_LOCK_PUT_ALL : DB_LOCK_INHERIT; request.obj = NULL; if ((ret = __lock_vec(dbenv, - txn->txnid, 0, &request, 1, NULL)) != 0) + txn->locker, 0, &request, 1, NULL)) != 0) return (__db_panic(dbenv, ret)); } /* End the transaction. */ + td = txn->td; + if (td->nlog_dbs != 0 && (ret = __txn_dref_fname(dbenv, txn)) != 0) + return (__db_panic(dbenv, ret)); + TXN_SYSTEM_LOCK(dbenv); - td = txn->td; td->status = is_commit ? TXN_COMMITTED : TXN_ABORTED; SH_TAILQ_REMOVE(®ion->active_txn, td, links, __txn_detail); if (F_ISSET(td, TXN_DTL_RESTORED)) { @@ -1296,7 +1331,7 @@ __txn_end(txn, is_commit) } if (td->name != INVALID_ROFF) { - __db_shalloc_free( + __env_alloc_free( &mgr->reginfo, R_ADDR(&mgr->reginfo, td->name)); td->name = INVALID_ROFF; } @@ -1311,10 +1346,12 @@ __txn_end(txn, is_commit) if (td->mvcc_ref != 0) { SH_TAILQ_INSERT_HEAD(®ion->mvcc_txn, td, links, __txn_detail); +#ifdef HAVE_STATISTICS if (++region->stat.st_nsnapshot > region->stat.st_maxnsnapshot) region->stat.st_maxnsnapshot = region->stat.st_nsnapshot; +#endif td = NULL; } MUTEX_UNLOCK(dbenv, mvcc_mtx); @@ -1323,14 +1360,20 @@ __txn_end(txn, is_commit) return (__db_panic(dbenv, ret)); } - if (td != NULL) - __db_shalloc_free(&mgr->reginfo, td); + if (td != NULL) { + if (td->nlog_slots != TXN_NSLOTS) + __env_alloc_free(&mgr->reginfo, + R_ADDR(&mgr->reginfo, td->log_dbs)); + __env_alloc_free(&mgr->reginfo, td); + } +#ifdef HAVE_STATISTICS if (is_commit) region->stat.st_ncommits++; else region->stat.st_naborts++; --region->stat.st_nactive; +#endif TXN_SYSTEM_UNLOCK(dbenv); @@ -1339,7 +1382,7 @@ __txn_end(txn, is_commit) * if any. */ if (LOCKING_ON(dbenv) && (ret = - __lock_freefamilylocker(dbenv->lk_handle, txn->txnid)) != 0) + __lock_freefamilylocker(dbenv->lk_handle, txn->locker)) != 0) return (__db_panic(dbenv, ret)); if (txn->parent != NULL) TAILQ_REMOVE(&txn->parent->kids, txn, klinks); @@ -1362,11 +1405,19 @@ __txn_end(txn, is_commit) } if (do_closefiles) { - F_SET(dbenv->lg_handle, DBLOG_RECOVER); - (void)__dbreg_close_files(dbenv); - F_CLR(dbenv->lg_handle, DBLOG_RECOVER); + /* + * Otherwise, we have resolved the last outstanding prepared + * txn and need to invalidate the fileids that were left + * open for those txns and then close them. + */ + (void)__dbreg_invalidate_files(dbenv, 1); + (void)__dbreg_close_files(dbenv, 1); + if (IS_REP_MASTER(dbenv)) + F_CLR(dbenv->rep_handle, DBREP_OPENFILES); + F_CLR(dbenv->lg_handle, DBLOG_OPENFILES); mgr->n_discards = 0; - (void)__txn_checkpoint(dbenv, 0, 0, DB_FORCE); + (void)__txn_checkpoint(dbenv, 0, 0, + DB_CKP_INTERNAL | DB_FORCE); } return (0); @@ -1378,10 +1429,11 @@ __txn_dispatch_undo(dbenv, txn, rdbt, key_lsn, txnlist) DB_TXN *txn; DBT *rdbt; DB_LSN *key_lsn; - void *txnlist; + DB_TXNHEAD *txnlist; { int ret; + txnlist->td = txn->td; ret = __db_dispatch(dbenv, dbenv->recover_dtab, dbenv->recover_dtab_size, rdbt, key_lsn, DB_TXN_ABORT, txnlist); if (ret == DB_SURPRISE_KID) { @@ -1418,7 +1470,7 @@ __txn_undo(txn) txnlist = NULL; ret = 0; - if (!DBENV_LOGGING(dbenv)) + if (!LOGGING_ON(dbenv)) return (0); /* @@ -1474,7 +1526,7 @@ __txn_undo(txn) * The dispatch routine returns the lsn of the record * before the current one in the key_lsn argument. */ - if ((ret = __log_c_get(logc, &key_lsn, &rdbt, DB_SET)) == 0) { + if ((ret = __logc_get(logc, &key_lsn, &rdbt, DB_SET)) == 0) { ret = __txn_dispatch_undo(dbenv, txn, &rdbt, &key_lsn, txnlist); } @@ -1491,7 +1543,7 @@ __txn_undo(txn) ret = __db_do_the_limbo(dbenv, ptxn, txn, txnlist, LIMBO_NORMAL); #endif -err: if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0) +err: if (logc != NULL && (t_ret = __logc_close(logc)) != 0 && ret == 0) ret = t_ret; if (ptxn == NULL && txnlist != NULL) @@ -1586,10 +1638,10 @@ __txn_force_abort(dbenv, buffer) } /* - * __txn_preclose - * Before we can close an environment, we need to check if we - * were in the midst of taking care of restored transactions. If - * so, then we need to close the files that we opened. + * __txn_preclose -- + * Before we can close an environment, we need to check if we were in the + * middle of taking care of restored transactions. If so, close the files + * we opened. * * PUBLIC: int __txn_preclose __P((DB_ENV *)); */ @@ -1614,12 +1666,12 @@ __txn_preclose(dbenv) if (do_closefiles) { /* - * Set the DBLOG_RECOVER flag while closing these - * files so they do not create additional log records - * that will confuse future recoveries. + * Set the DBLOG_RECOVER flag while closing these files so they + * do not create additional log records that will confuse future + * recoveries. */ F_SET(dbenv->lg_handle, DBLOG_RECOVER); - ret = __dbreg_close_files(dbenv); + ret = __dbreg_close_files(dbenv, 0); F_CLR(dbenv->lg_handle, DBLOG_RECOVER); } else ret = 0; diff --git a/db/txn/txn.src b/db/txn/txn.src index 0cd2bbcaa..ada4862d5 100644 --- a/db/txn/txn.src +++ b/db/txn/txn.src @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. * - * $Id: txn.src,v 12.7 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn.src,v 12.11 2007/06/01 17:35:16 sue Exp $ */ PREFIX __txn @@ -29,15 +28,15 @@ INCLUDE * Environment ID of this operation (4.4+). */ BEGIN_COMPAT regop 42 10 -ARG opcode u_int32_t ld +ARG opcode u_int32_t lu TIME timestamp int32_t ld LOCKS locks DBT s END BEGIN regop 44 10 -ARG opcode u_int32_t ld +ARG opcode u_int32_t lu TIME timestamp int32_t ld -ARG envid u_int32_t ld +ARG envid u_int32_t lu LOCKS locks DBT s END @@ -57,21 +56,22 @@ END * envid: * Environment ID of this checkpoint (4.3+). * rep_gen: - * Persistent replication generation number. + * Persistent replication generation number (4.2-4.5 only). + * Renamed to 'spare' in 4.6. */ BEGIN_COMPAT ckp 42 11 POINTER ckp_lsn DB_LSN * lu POINTER last_ckp DB_LSN * lu TIME timestamp int32_t ld -ARG rep_gen u_int32_t ld +ARG rep_gen u_int32_t lu END BEGIN ckp 43 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 +ARG envid u_int32_t lu +ARG spare u_int32_t lu END /* @@ -93,8 +93,8 @@ BEGIN xa_regop 42 13 ARG opcode u_int32_t lu DBT xid DBT s ARG formatID int32_t ld -ARG gtrid u_int32_t u -ARG bqual u_int32_t u +ARG gtrid u_int32_t lu +ARG bqual u_int32_t lu POINTER begin_lsn DB_LSN * lu LOCKS locks DBT s END @@ -103,6 +103,6 @@ END * Log the fact that we are recycling txnids. */ BEGIN recycle 42 14 -ARG min u_int32_t u -ARG max u_int32_t u +ARG min u_int32_t lu +ARG max u_int32_t lu END diff --git a/db/txn/txn_auto.c b/db/txn/txn_auto.c index 3a8cda986..d72869d5b 100644 --- a/db/txn/txn_auto.c +++ b/db/txn/txn_auto.c @@ -196,6 +196,7 @@ __txn_regop_log(dbenv, txnp, ret_lsnp, flags, *ret_lsnp = *rlsnp; } } else { + ret = 0; #ifdef DIAGNOSTIC /* * Set the debug bit if we are going to log non-durable @@ -205,10 +206,9 @@ __txn_regop_log(dbenv, txnp, ret_lsnp, flags, rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - ret = __log_put(dbenv, - rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); -#else - ret = 0; + if (!IS_REP_CLIENT(dbenv)) + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); #endif STAILQ_INSERT_HEAD(&txnp->logs, lr, links); F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); @@ -336,7 +336,7 @@ __txn_ckp_42_read(dbenv, recbuf, argpp) */ int __txn_ckp_log(dbenv, txnp, ret_lsnp, flags, - ckp_lsn, last_ckp, timestamp, envid, rep_gen) + ckp_lsn, last_ckp, timestamp, envid, spare) DB_ENV *dbenv; DB_TXN *txnp; DB_LSN *ret_lsnp; @@ -345,7 +345,7 @@ __txn_ckp_log(dbenv, txnp, ret_lsnp, flags, DB_LSN * last_ckp; int32_t timestamp; u_int32_t envid; - u_int32_t rep_gen; + u_int32_t spare; { DBT logrec; DB_TXNLOGREC *lr; @@ -454,7 +454,7 @@ __txn_ckp_log(dbenv, txnp, ret_lsnp, flags, memcpy(bp, &uinttmp, sizeof(uinttmp)); bp += sizeof(uinttmp); - uinttmp = (u_int32_t)rep_gen; + uinttmp = (u_int32_t)spare; memcpy(bp, &uinttmp, sizeof(uinttmp)); bp += sizeof(uinttmp); @@ -469,6 +469,7 @@ __txn_ckp_log(dbenv, txnp, ret_lsnp, flags, *ret_lsnp = *rlsnp; } } else { + ret = 0; #ifdef DIAGNOSTIC /* * Set the debug bit if we are going to log non-durable @@ -478,10 +479,9 @@ __txn_ckp_log(dbenv, txnp, ret_lsnp, flags, rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - ret = __log_put(dbenv, - rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); -#else - ret = 0; + if (!IS_REP_CLIENT(dbenv)) + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); #endif STAILQ_INSERT_HEAD(&txnp->logs, lr, links); F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); @@ -548,7 +548,7 @@ __txn_ckp_read(dbenv, recbuf, argpp) bp += sizeof(uinttmp); memcpy(&uinttmp, bp, sizeof(uinttmp)); - argp->rep_gen = (u_int32_t)uinttmp; + argp->spare = (u_int32_t)uinttmp; bp += sizeof(uinttmp); *argpp = argp; @@ -674,6 +674,7 @@ __txn_child_log(dbenv, txnp, ret_lsnp, flags, *ret_lsnp = *rlsnp; } } else { + ret = 0; #ifdef DIAGNOSTIC /* * Set the debug bit if we are going to log non-durable @@ -683,10 +684,9 @@ __txn_child_log(dbenv, txnp, ret_lsnp, flags, rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - ret = __log_put(dbenv, - rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); -#else - ret = 0; + if (!IS_REP_CLIENT(dbenv)) + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); #endif STAILQ_INSERT_HEAD(&txnp->logs, lr, links); F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); @@ -914,6 +914,7 @@ __txn_xa_regop_log(dbenv, txnp, ret_lsnp, flags, *ret_lsnp = *rlsnp; } } else { + ret = 0; #ifdef DIAGNOSTIC /* * Set the debug bit if we are going to log non-durable @@ -923,10 +924,9 @@ __txn_xa_regop_log(dbenv, txnp, ret_lsnp, flags, rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - ret = __log_put(dbenv, - rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); -#else - ret = 0; + if (!IS_REP_CLIENT(dbenv)) + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); #endif STAILQ_INSERT_HEAD(&txnp->logs, lr, links); F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); @@ -1131,6 +1131,7 @@ __txn_recycle_log(dbenv, txnp, ret_lsnp, flags, *ret_lsnp = *rlsnp; } } else { + ret = 0; #ifdef DIAGNOSTIC /* * Set the debug bit if we are going to log non-durable @@ -1140,10 +1141,9 @@ __txn_recycle_log(dbenv, txnp, ret_lsnp, flags, rectype |= DB_debug_FLAG; memcpy(logrec.data, &rectype, sizeof(rectype)); - ret = __log_put(dbenv, - rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); -#else - ret = 0; + if (!IS_REP_CLIENT(dbenv)) + ret = __log_put(dbenv, + rlsnp, (DBT *)&logrec, flags | DB_LOG_NOCOPY); #endif STAILQ_INSERT_HEAD(&txnp->logs, lr, links); F_SET((TXN_DETAIL *)txnp->td, TXN_DTL_INMEMORY); diff --git a/db/txn/txn_autop.c b/db/txn/txn_autop.c index c993e0fad..1cc878bd5 100644 --- a/db/txn/txn_autop.c +++ b/db/txn/txn_autop.c @@ -41,7 +41,7 @@ __txn_regop_42_print(dbenv, dbtp, lsnp, notused2, notused3) (u_long)argp->type, (u_long)argp->txnp->txnid, (u_long)argp->prev_lsn.file, (u_long)argp->prev_lsn.offset); - (void)printf("\topcode: %ld\n", (long)argp->opcode); + (void)printf("\topcode: %lu\n", (u_long)argp->opcode); timeval = (time_t)argp->timestamp; lt = localtime(&timeval); (void)printf( @@ -87,7 +87,7 @@ __txn_regop_print(dbenv, dbtp, lsnp, notused2, notused3) (u_long)argp->type, (u_long)argp->txnp->txnid, (u_long)argp->prev_lsn.file, (u_long)argp->prev_lsn.offset); - (void)printf("\topcode: %ld\n", (long)argp->opcode); + (void)printf("\topcode: %lu\n", (u_long)argp->opcode); timeval = (time_t)argp->timestamp; lt = localtime(&timeval); (void)printf( @@ -96,7 +96,7 @@ __txn_regop_print(dbenv, dbtp, lsnp, notused2, notused3) (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("\tenvid: %lu\n", (u_long)argp->envid); (void)printf("\tlocks: \n"); __lock_list_print(dbenv, &argp->locks); (void)printf("\n"); @@ -146,7 +146,7 @@ __txn_ckp_42_print(dbenv, dbtp, lsnp, notused2, notused3) (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("\trep_gen: %lu\n", (u_long)argp->rep_gen); (void)printf("\n"); __os_free(dbenv, argp); return (0); @@ -194,8 +194,8 @@ __txn_ckp_print(dbenv, dbtp, lsnp, notused2, notused3) (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("\tenvid: %lu\n", (u_long)argp->envid); + (void)printf("\tspare: %lu\n", (u_long)argp->spare); (void)printf("\n"); __os_free(dbenv, argp); return (0); @@ -273,8 +273,8 @@ __txn_xa_regop_print(dbenv, dbtp, lsnp, notused2, notused3) } (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("\tgtrid: %lu\n", (u_long)argp->gtrid); + (void)printf("\tbqual: %lu\n", (u_long)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"); @@ -311,8 +311,8 @@ __txn_recycle_print(dbenv, dbtp, lsnp, notused2, notused3) (u_long)argp->type, (u_long)argp->txnp->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("\tmin: %lu\n", (u_long)argp->min); + (void)printf("\tmax: %lu\n", (u_long)argp->max); (void)printf("\n"); __os_free(dbenv, argp); return (0); diff --git a/db/txn/txn_chkpt.c b/db/txn/txn_chkpt.c index 59ddf5509..89cf670e6 100644 --- a/db/txn/txn_chkpt.c +++ b/db/txn/txn_chkpt.c @@ -1,8 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. */ /* * Copyright (c) 1995, 1996 @@ -35,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: txn_chkpt.c,v 12.27 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_chkpt.c,v 12.47 2007/06/08 17:34:57 bostic Exp $ */ #include "db_config.h" @@ -101,22 +100,11 @@ __txn_checkpoint(dbenv, kbytes, minutes, flags) REGENV *renv; REGINFO *infop; time_t last_ckp_time, now; - u_int32_t bytes, gen, id, logflags, mbytes; + u_int32_t bytes, id, logflags, mbytes, op; int ret; - ret = gen = 0; - /* - * A client will only call through here during recovery, - * so just sync the Mpool and go home. - */ - if (IS_REP_CLIENT(dbenv)) { - if (MPOOL_ON(dbenv) && (ret = __memp_sync(dbenv, NULL)) != 0) { - __db_err(dbenv, ret, - "txn_checkpoint: failed to flush the buffer cache"); - return (ret); - } - return (0); - } + DB_ASSERT(dbenv, !IS_REP_CLIENT(dbenv)); + ret = 0; mgr = dbenv->tx_handle; region = mgr->reginfo.primary; @@ -177,17 +165,68 @@ __txn_checkpoint(dbenv, kbytes, minutes, flags) * sees a later chk_lsn but competes first. An archive process could * then remove a log this checkpoint depends on. */ -do_ckp: MUTEX_LOCK(dbenv, region->mtx_ckp); +do_ckp: + MUTEX_LOCK(dbenv, region->mtx_ckp); if ((ret = __txn_getactive(dbenv, &ckp_lsn)) != 0) goto err; - if (MPOOL_ON(dbenv) && (ret = __memp_sync(dbenv, NULL)) != 0) { + /* + * Checkpoints in replication groups can cause performance problems. + * + * As on the master, checkpoint on the replica requires the cache be + * flushed. The problem occurs when a client has dirty cache pages + * to write when the checkpoint record arrives, and the client's PERM + * response is necessary in order to meet the system's durability + * guarantees. In this case, the master will have to wait until the + * client completes its cache flush and writes the checkpoint record + * before subsequent transactions can be committed. The delay may + * cause transactions to timeout waiting on client response, which + * can cause nasty ripple effects in the system's overall throughput. + * [#15338] + * + * First, we send a start-sync record when the checkpoint starts so + * clients can start flushing their cache in preparation for the + * arrival of the checkpoint record. + */ + if (LOGGING_ON(dbenv) && + IS_REP_MASTER(dbenv) && dbenv->rep_handle->send != NULL) + (void)__rep_send_message(dbenv, + DB_EID_BROADCAST, REP_START_SYNC, &ckp_lsn, NULL, 0, 0); + + /* Flush the cache. */ + if (MPOOL_ON(dbenv) && + (ret = __memp_sync_int( + dbenv, NULL, 0, DB_SYNC_CHECKPOINT, NULL, NULL)) != 0) { __db_err(dbenv, ret, "txn_checkpoint: failed to flush the buffer cache"); goto err; } /* + * The client won't have more dirty pages to flush from its cache than + * the master did, but there may be differences between the hardware, + * I/O configuration and workload on the master and the client that + * can result in the client being unable to finish its cache flush as + * fast as the master. A way to avoid the problem is to pause after + * the master completes its checkpoint and before the actual checkpoint + * record is logged, giving the replicas additional time to finish. + * + * !!! + * We do not currently surface an API to modify this value, + * + * !!! + * Currently turned off when testing, because it makes the test suite + * take a long time to run. + */ +#ifndef CONFIG_TEST + if (LOGGING_ON(dbenv) && + IS_REP_MASTER(dbenv) && dbenv->rep_handle->send != NULL && + !LF_ISSET(DB_CKP_INTERNAL) && + dbenv->rep_handle->region->chkpt_delay != 0) + __os_sleep(dbenv, dbenv->rep_handle->region->chkpt_delay, 0); +#endif + + /* * Because we can't be a replication client here, and because * recovery (somewhat unusually) calls txn_checkpoint and expects * it to write a log message, LOGGING_ON is the correct macro here. @@ -196,9 +235,6 @@ do_ckp: MUTEX_LOCK(dbenv, region->mtx_ckp); TXN_SYSTEM_LOCK(dbenv); last_ckp = region->last_ckp; TXN_SYSTEM_UNLOCK(dbenv); - if (REP_ON(dbenv) && (ret = __rep_get_gen(dbenv, &gen)) != 0) - goto err; - /* * Put out records for the open files before we log * the checkpoint. The records are certain to be at @@ -208,11 +244,20 @@ do_ckp: MUTEX_LOCK(dbenv, region->mtx_ckp); * checkpoint. */ logflags = DB_LOG_CHKPNT; + /* + * If this is a normal checkpoint, log files as checkpoints. + * If we are recovering, only log as DBREG_RCLOSE if + * there are no prepared txns. Otherwise, it should + * stay as DBREG_CHKPNT. + */ + op = DBREG_CHKPNT; if (!IS_RECOVERING(dbenv)) logflags |= DB_FLUSH; - if ((ret = __dbreg_log_files(dbenv)) != 0 || + else if (region->stat.st_nrestores == 0) + op = DBREG_RCLOSE; + if ((ret = __dbreg_log_files(dbenv, op)) != 0 || (ret = __txn_ckp_log(dbenv, NULL, &ckp_lsn, logflags, - &ckp_lsn, &last_ckp, (int32_t)time(NULL), id, gen)) != 0) { + &ckp_lsn, &last_ckp, (int32_t)time(NULL), id, 0)) != 0) { __db_err(dbenv, ret, "txn_checkpoint: log failed at LSN [%ld %ld]", (long)ckp_lsn.file, (long)ckp_lsn.offset); diff --git a/db/txn/txn_failchk.c b/db/txn/txn_failchk.c index 4301fdab8..92bb24d3a 100644 --- a/db/txn/txn_failchk.c +++ b/db/txn/txn_failchk.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2005-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 2005,2007 Oracle. All rights reserved. * - * $Id: txn_failchk.c,v 12.6 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_failchk.c,v 12.9 2007/06/29 00:25:02 margo Exp $ */ #include "db_config.h" @@ -63,7 +62,8 @@ retry: TXN_SYSTEM_LOCK(dbenv); TXN_SYSTEM_UNLOCK(dbenv); if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXN), &txn)) != 0) return (ret); - __txn_continue(dbenv, txn, td); + if ((ret = __txn_continue(dbenv, txn, td)) != 0) + return (ret); F_SET(txn, TXN_MALLOC); SH_TAILQ_FOREACH(ktd, &td->kids, klinks, __txn_detail) { if (F_ISSET(ktd, TXN_DTL_INMEMORY)) @@ -73,7 +73,8 @@ retry: TXN_SYSTEM_LOCK(dbenv); if ((ret = __os_calloc(dbenv, 1, sizeof(DB_TXN), &ktxn)) != 0) return (ret); - __txn_continue(dbenv, ktxn, ktd); + if ((ret = __txn_continue(dbenv, ktxn, ktd)) != 0) + return (ret); F_SET(ktxn, TXN_MALLOC); ktxn->parent = txn; TAILQ_INSERT_HEAD(&txn->kids, txn, klinks); diff --git a/db/txn/txn_method.c b/db/txn/txn_method.c index f56867473..d1c46da2b 100644 --- a/db/txn/txn_method.c +++ b/db/txn/txn_method.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. * - * $Id: txn_method.c,v 12.6 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_method.c,v 12.9 2007/05/17 15:16:00 bostic Exp $ */ #include "db_config.h" @@ -13,13 +12,13 @@ #include "dbinc/txn.h" /* - * __txn_dbenv_create -- + * __txn_env_create -- * Transaction specific initialization of the DB_ENV structure. * - * PUBLIC: int __txn_dbenv_create __P((DB_ENV *)); + * PUBLIC: int __txn_env_create __P((DB_ENV *)); */ int -__txn_dbenv_create(dbenv) +__txn_env_create(dbenv) DB_ENV *dbenv; { /* @@ -34,13 +33,13 @@ __txn_dbenv_create(dbenv) } /* - * __txn_dbenv_destroy -- + * __txn_env_destroy -- * Transaction specific destruction of the DB_ENV structure. * - * PUBLIC: void __txn_dbenv_destroy __P((DB_ENV *)); + * PUBLIC: void __txn_env_destroy __P((DB_ENV *)); */ void -__txn_dbenv_destroy(dbenv) +__txn_env_destroy(dbenv) DB_ENV *dbenv; { COMPQUIET(dbenv, NULL); diff --git a/db/txn/txn_rec.c b/db/txn/txn_rec.c index c81a9dcae..263ae28f2 100644 --- a/db/txn/txn_rec.c +++ b/db/txn/txn_rec.c @@ -1,8 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. */ /* * Copyright (c) 1996 @@ -32,13 +31,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: txn_rec.c,v 12.14 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_rec.c,v 12.25 2007/06/01 15:36:52 sue Exp $ */ #include "db_config.h" #include "db_int.h" #include "dbinc/db_page.h" +#include "dbinc/lock.h" #include "dbinc/txn.h" #include "dbinc/db_am.h" @@ -142,6 +142,9 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) db_recops op; void *info; { + DBT *lock_dbt; + DB_TXNHEAD *headp; + DB_LOCKTAB *lt; __txn_xa_regop_args *argp; int ret; u_int32_t status; @@ -157,6 +160,7 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) ret = EINVAL; goto err; } + headp = info; /* * The return value here is either a DB_NOTFOUND or it is @@ -169,9 +173,8 @@ __txn_xa_regop_recover(dbenv, dbtp, lsnp, op, info) /* * If we are rolling forward, then an aborted prepare - * indicates that this may the last record we'll see for - * this transaction ID, so we should remove it from the - * list. + * indicates that this may be the last record we'll see for + * this transaction ID, so we should remove it from the list. */ if (op == DB_TXN_FORWARD_ROLL) { @@ -211,9 +214,27 @@ txn_err: __db_errx(dbenv, "transaction not in list %lx", (u_long)argp->txnp->txnid); ret = DB_NOTFOUND; - } else if ((ret = __db_txnlist_add(dbenv, - info, argp->txnp->txnid, TXN_COMMIT, lsnp)) == 0) - ret = __txn_restore_txn(dbenv, lsnp, argp); + } else if (IS_ZERO_LSN(headp->trunc_lsn) || + LOG_COMPARE(&headp->trunc_lsn, lsnp) >= 0) { + if ((ret = __db_txnlist_add(dbenv, + info, argp->txnp->txnid, TXN_COMMIT, lsnp)) == 0) { + /* Re-acquire the locks for this transaction. */ + lock_dbt = &argp->locks; + if (LOCKING_ON(dbenv)) { + lt = dbenv->lk_handle; + if ((ret = __lock_getlocker(lt, + argp->txnp->txnid, 1, + &argp->txnp->locker)) != 0) + goto err; + if ((ret = __lock_get_list(dbenv, + argp->txnp->locker, 0, + DB_LOCK_WRITE, lock_dbt)) != 0) + goto err; + } + + ret = __txn_restore_txn(dbenv, lsnp, argp); + } + } } else ret = 0; @@ -237,8 +258,6 @@ __txn_ckp_recover(dbenv, dbtp, lsnp, op, info) db_recops op; void *info; { - DB_REP *db_rep; - REP *rep; __txn_ckp_args *argp; int ret; @@ -251,16 +270,6 @@ __txn_ckp_recover(dbenv, dbtp, lsnp, op, info) if (op == DB_TXN_BACKWARD_ROLL) __db_txnlist_ckp(dbenv, info, lsnp); - if (op == DB_TXN_FORWARD_ROLL) { - /* Record the max generation number that we've seen. */ - if (REP_ON(dbenv)) { - db_rep = dbenv->rep_handle; - rep = db_rep->region; - if (argp->rep_gen > rep->recover_gen) - rep->recover_gen = argp->rep_gen; - } - } - *lsnp = argp->last_ckp; __os_free(dbenv, argp); return (DB_TXN_CKP); @@ -418,8 +427,7 @@ __txn_restore_txn(dbenv, lsnp, argp) TXN_SYSTEM_LOCK(dbenv); /* Allocate a new transaction detail structure. */ - if ((ret = - __db_shalloc(&mgr->reginfo, sizeof(TXN_DETAIL), 0, &td)) != 0) { + if ((ret = __env_alloc(&mgr->reginfo, sizeof(TXN_DETAIL), &td)) != 0) { TXN_SYSTEM_UNLOCK(dbenv); return (ret); } @@ -445,11 +453,16 @@ __txn_restore_txn(dbenv, lsnp, argp) td->bqual = argp->bqual; td->gtrid = argp->gtrid; td->format = argp->formatID; + td->nlog_dbs = 0; + td->nlog_slots = TXN_NSLOTS; + td->log_dbs = R_OFFSET(&mgr->reginfo, td->slots); region->stat.st_nrestores++; +#ifdef HAVE_STATISTICS region->stat.st_nactive++; if (region->stat.st_nactive > region->stat.st_maxnactive) region->stat.st_maxnactive = region->stat.st_nactive; +#endif TXN_SYSTEM_UNLOCK(dbenv); return (0); } @@ -587,8 +600,6 @@ __txn_ckp_42_recover(dbenv, dbtp, lsnp, op, info) db_recops op; void *info; { - DB_REP *db_rep; - REP *rep; __txn_ckp_42_args *argp; int ret; @@ -601,16 +612,6 @@ __txn_ckp_42_recover(dbenv, dbtp, lsnp, op, info) if (op == DB_TXN_BACKWARD_ROLL) __db_txnlist_ckp(dbenv, info, lsnp); - if (op == DB_TXN_FORWARD_ROLL) { - /* Record the max generation number that we've seen. */ - if (REP_ON(dbenv)) { - db_rep = dbenv->rep_handle; - rep = db_rep->region; - if (argp->rep_gen > rep->recover_gen) - rep->recover_gen = argp->rep_gen; - } - } - *lsnp = argp->last_ckp; __os_free(dbenv, argp); return (DB_TXN_CKP); diff --git a/db/txn/txn_recover.c b/db/txn/txn_recover.c index 961f0c39c..81c8d0c6e 100644 --- a/db/txn/txn_recover.c +++ b/db/txn/txn_recover.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 2001,2007 Oracle. All rights reserved. * - * $Id: txn_recover.c,v 12.19 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_recover.c,v 12.29 2007/06/29 00:25:02 margo Exp $ */ #include "db_config.h" @@ -134,7 +133,7 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) XID *xids; DB_PREPLIST *txns; long count; /* This is long for XA compatibility. */ - long *retp; + long *retp; u_int32_t flags; { DB_LSN min; @@ -144,15 +143,14 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) TXN_DETAIL *td; XID *xidp; long i; - int nrestores, open_files, ret; + int restored, ret; *retp = 0; MAX_LSN(min); prepp = txns; xidp = xids; - nrestores = ret = 0; - open_files = 1; + restored = ret = 0; /* * If we are starting a scan, then we traverse the active transaction @@ -173,24 +171,18 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) * restored, then we never crashed; just the main server did). */ TXN_SYSTEM_LOCK(dbenv); - if (flags == DB_FIRST) { - SH_TAILQ_FOREACH(td, ®ion->active_txn, links, __txn_detail) { - if (F_ISSET(td, TXN_DTL_RESTORED)) - nrestores++; - F_CLR(td, TXN_DTL_COLLECTED); - } - mgr->n_discards = 0; - } else - open_files = 0; /* Now begin collecting active transactions. */ for (td = SH_TAILQ_FIRST(®ion->active_txn, __txn_detail); td != NULL && *retp < count; td = SH_TAILQ_NEXT(td, links, __txn_detail)) { if (td->status != TXN_PREPARED || - F_ISSET(td, TXN_DTL_COLLECTED)) + (flags != DB_FIRST && F_ISSET(td, TXN_DTL_COLLECTED))) continue; + if (F_ISSET(td, TXN_DTL_RESTORED)) + restored = 1; + if (xids != NULL) { xidp->formatID = td->format; /* @@ -210,7 +202,8 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) TXN_SYSTEM_UNLOCK(dbenv); goto err; } - __txn_continue(dbenv, prepp->txn, td); + if ((ret = __txn_continue(dbenv, prepp->txn, td)) != 0) + goto err; F_SET(prepp->txn, TXN_MALLOC); memcpy(prepp->gid, td->xid, sizeof(td->xid)); prepp++; @@ -222,30 +215,43 @@ __txn_get_prepared(dbenv, xids, txns, count, retp, flags) (*retp)++; F_SET(td, TXN_DTL_COLLECTED); - if (IS_ENV_REPLICATED(dbenv) && - (ret = __op_rep_enter(dbenv)) != 0) - goto err; } + if (flags == DB_FIRST) + for (; td != NULL; td = SH_TAILQ_NEXT(td, links, __txn_detail)) + F_CLR(td, TXN_DTL_COLLECTED); TXN_SYSTEM_UNLOCK(dbenv); /* * Now link all the transactions into the transaction manager's list. */ - if (txns != NULL) { + if (txns != NULL && *retp != 0) { MUTEX_LOCK(dbenv, mgr->mutex); for (i = 0; i < *retp; i++) TAILQ_INSERT_TAIL(&mgr->txn_chain, txns[i].txn, links); MUTEX_UNLOCK(dbenv, mgr->mutex); - } - if (open_files && nrestores && *retp != 0 && !IS_MAX_LSN(min)) { - F_SET(dbenv->lg_handle, DBLOG_RECOVER); - ret = __txn_openfiles(dbenv, &min, 0); - F_CLR(dbenv->lg_handle, DBLOG_RECOVER); + /* + * If we are restoring, update our count of outstanding + * transactions. + */ + if (REP_ON(dbenv)) { + REP_SYSTEM_LOCK(dbenv); + dbenv->rep_handle->region->op_cnt += (u_long)*retp; + REP_SYSTEM_UNLOCK(dbenv); + } + } - return (0); + /* + * If recovery already opened the files for us, don't + * do it here. + */ + if (restored != 0 && flags == DB_FIRST && + !F_ISSET(dbenv->lg_handle, DBLOG_OPENFILES)) + ret = __txn_openfiles(dbenv, &min, 0); -err: TXN_SYSTEM_UNLOCK(dbenv); + if (0) { +err: TXN_SYSTEM_UNLOCK(dbenv); + } return (ret); } @@ -279,7 +285,7 @@ __txn_openfiles(dbenv, min, force) 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 && + __logc_get(logc, &open_lsn, &data, DB_SET)) == 0 && (force || (min != NULL && LOG_COMPARE(min, &open_lsn) < 0))) { /* Format the log record. */ @@ -300,7 +306,7 @@ __txn_openfiles(dbenv, min, force) ckp_args->last_ckp; __os_free(dbenv, ckp_args); if (force) { - if ((ret = __log_c_get(logc, &open_lsn, + if ((ret = __logc_get(logc, &open_lsn, &data, DB_SET)) != 0) goto err; break; @@ -317,7 +323,7 @@ __txn_openfiles(dbenv, min, force) * - 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) { + __logc_get(logc, &open_lsn, &data, DB_FIRST)) != 0) { __db_errx(dbenv, "No log records"); goto err; } @@ -330,7 +336,7 @@ __txn_openfiles(dbenv, min, force) __db_txnlist_end(dbenv, txninfo); err: - if (logc != NULL && (t_ret = __log_c_close(logc)) != 0 && ret == 0) + if (logc != NULL && (t_ret = __logc_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 0b5547bb5..bbe908048 100644 --- a/db/txn/txn_region.c +++ b/db/txn/txn_region.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. * - * $Id: txn_region.c,v 12.20 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_region.c,v 12.31 2007/05/17 15:16:00 bostic Exp $ */ #include "db_config.h" @@ -20,11 +19,12 @@ static size_t __txn_region_size __P((DB_ENV *)); * __txn_open -- * Open a transaction region. * - * PUBLIC: int __txn_open __P((DB_ENV *)); + * PUBLIC: int __txn_open __P((DB_ENV *, int)); */ int -__txn_open(dbenv) +__txn_open(dbenv, create_ok) DB_ENV *dbenv; + int create_ok; { DB_TXNMGR *mgr; int ret; @@ -40,9 +40,9 @@ __txn_open(dbenv) mgr->reginfo.type = REGION_TYPE_TXN; mgr->reginfo.id = INVALID_REGION_ID; mgr->reginfo.flags = REGION_JOIN_OK; - if (F_ISSET(dbenv, DB_ENV_CREATE)) + if (create_ok) F_SET(&mgr->reginfo, REGION_CREATE_OK); - if ((ret = __db_r_attach(dbenv, + if ((ret = __env_region_attach(dbenv, &mgr->reginfo, __txn_region_size(dbenv))) != 0) goto err; @@ -65,7 +65,7 @@ __txn_open(dbenv) err: dbenv->tx_handle = NULL; if (mgr->reginfo.addr != NULL) - (void)__db_r_detach(dbenv, &mgr->reginfo, 0); + (void)__env_region_detach(dbenv, &mgr->reginfo, 0); (void)__mutex_free(dbenv, &mgr->mutex); __os_free(dbenv, mgr); @@ -106,8 +106,8 @@ __txn_init(dbenv, mgr) return (ret); } - if ((ret = __db_shalloc(&mgr->reginfo, - sizeof(DB_TXNREGION), 0, &mgr->reginfo.primary)) != 0) { + if ((ret = __env_alloc(&mgr->reginfo, + sizeof(DB_TXNREGION), &mgr->reginfo.primary)) != 0) { __db_errx(dbenv, "Unable to allocate memory for the transaction region"); return (ret); @@ -132,7 +132,9 @@ __txn_init(dbenv, mgr) region->time_ckp = time(NULL); memset(®ion->stat, 0, sizeof(region->stat)); +#ifdef HAVE_STATISTICS region->stat.st_maxtxns = region->maxtxns; +#endif SH_TAILQ_INIT(®ion->active_txn); SH_TAILQ_INIT(®ion->mvcc_txn); @@ -168,10 +170,10 @@ __txn_findlastckp(dbenv, lsnp, max_lsn) memset(&dbt, 0, sizeof(dbt)); if (max_lsn != NULL) { lsn = *max_lsn; - if ((ret = __log_c_get(logc, &lsn, &dbt, DB_SET)) != 0) + if ((ret = __logc_get(logc, &lsn, &dbt, DB_SET)) != 0) goto err; } else { - if ((ret = __log_c_get(logc, &lsn, &dbt, DB_LAST)) != 0) + if ((ret = __logc_get(logc, &lsn, &dbt, DB_LAST)) != 0) goto err; /* * Twiddle the last LSN so it points to the beginning of the @@ -182,7 +184,7 @@ __txn_findlastckp(dbenv, lsnp, max_lsn) } /* Read backwards, looking for checkpoints. */ - while ((ret = __log_c_get(logc, &lsn, &dbt, DB_PREV)) == 0) { + while ((ret = __logc_get(logc, &lsn, &dbt, DB_PREV)) == 0) { if (dbt.size < sizeof(u_int32_t)) continue; memcpy(&rectype, dbt.data, sizeof(u_int32_t)); @@ -192,7 +194,7 @@ __txn_findlastckp(dbenv, lsnp, max_lsn) } } -err: if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) +err: if ((t_ret = __logc_close(logc)) != 0 && ret == 0) ret = t_ret; /* @@ -203,13 +205,13 @@ err: if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) } /* - * __txn_dbenv_refresh -- + * __txn_env_refresh -- * Clean up after the transaction system on a close or failed open. * - * PUBLIC: int __txn_dbenv_refresh __P((DB_ENV *)); + * PUBLIC: int __txn_env_refresh __P((DB_ENV *)); */ int -__txn_dbenv_refresh(dbenv) +__txn_env_refresh(dbenv) DB_ENV *dbenv; { DB_TXN *txn; @@ -269,7 +271,7 @@ __txn_dbenv_refresh(dbenv) ret = t_ret; /* Detach from the region. */ - if ((t_ret = __db_r_detach(dbenv, reginfo, 0)) != 0 && ret == 0) + if ((t_ret = __env_region_detach(dbenv, reginfo, 0)) != 0 && ret == 0) ret = t_ret; __os_free(dbenv, mgr); @@ -279,12 +281,25 @@ __txn_dbenv_refresh(dbenv) } /* + * __txn_region_mutex_count -- + * Return the number of mutexes the txn region will need. + * + * PUBLIC: u_int32_t __txn_region_mutex_count __P((DB_ENV *)); + */ +u_int32_t +__txn_region_mutex_count(dbenv) + DB_ENV *dbenv; +{ + /* + * We need a MVCC mutex for each TXN_DETAIL structure, a mutex for + * DB_TXNMGR structure, two mutexes for the DB_TXNREGION structure. + */ + return (dbenv->tx_max + 1 + 2); +} + +/* * __txn_region_size -- - * Return the amount of space needed for the txn region. Make the - * region large enough to hold txn_max transaction detail structures - * plus some space to hold thread handles and the beginning of the - * shalloc region and anything we need for mutex system resource - * recording. + * Return the amount of space needed for the txn region. */ static size_t __txn_region_size(dbenv) @@ -292,8 +307,16 @@ __txn_region_size(dbenv) { size_t s; + /* + * Make the region large enough to hold the primary transaction region + * structure, txn_max transaction detail structures, txn_max chunks of + * overhead required by the underlying shared region allocator for each + * chunk of memory, txn_max transaction names, at an average of 20 + * bytes each, and 10KB for safety. + */ s = sizeof(DB_TXNREGION) + - dbenv->tx_max * sizeof(TXN_DETAIL) + 10 * 1024; + dbenv->tx_max * (sizeof(TXN_DETAIL) + __env_alloc_overhead() + 20) + + 10 * 1024; return (s); } @@ -377,7 +400,8 @@ __txn_oldest_reader(dbenv, lsnp) * * PUBLIC: int __txn_add_buffer __P((DB_ENV *, TXN_DETAIL *)); */ -int __txn_add_buffer(dbenv, td) +int +__txn_add_buffer(dbenv, td) DB_ENV *dbenv; TXN_DETAIL *td; { @@ -388,6 +412,7 @@ int __txn_add_buffer(dbenv, td) ++td->mvcc_ref; MUTEX_UNLOCK(dbenv, td->mvcc_mtx); + COMPQUIET(dbenv, NULL); return (0); } @@ -397,7 +422,8 @@ int __txn_add_buffer(dbenv, td) * * PUBLIC: int __txn_remove_buffer __P((DB_ENV *, TXN_DETAIL *, db_mutex_t)); */ -int __txn_remove_buffer(dbenv, td, hash_mtx) +int +__txn_remove_buffer(dbenv, td, hash_mtx) DB_ENV *dbenv; TXN_DETAIL *td; db_mutex_t hash_mtx; @@ -425,8 +451,10 @@ int __txn_remove_buffer(dbenv, td, hash_mtx) TXN_SYSTEM_LOCK(dbenv); SH_TAILQ_REMOVE(®ion->mvcc_txn, td, links, __txn_detail); +#ifdef HAVE_STATISTICS --region->stat.st_nsnapshot; - __db_shalloc_free(&mgr->reginfo, td); +#endif + __env_alloc_free(&mgr->reginfo, td); TXN_SYSTEM_UNLOCK(dbenv); MUTEX_LOCK(dbenv, hash_mtx); diff --git a/db/txn/txn_stat.c b/db/txn/txn_stat.c index 2f7cf95e5..a2c4f1fe2 100644 --- a/db/txn/txn_stat.c +++ b/db/txn/txn_stat.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 1996,2007 Oracle. All rights reserved. * - * $Id: txn_stat.c,v 12.18 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_stat.c,v 12.23 2007/06/22 18:27:51 bostic Exp $ */ #include "db_config.h" @@ -134,7 +133,8 @@ __txn_stat(dbenv, statp, flags) &stats->st_region_wait, &stats->st_region_nowait); stats->st_regsize = mgr->reginfo.rp->size; if (LF_ISSET(DB_STAT_CLEAR)) { - __mutex_clear(dbenv, region->mtx_region); + if (!LF_ISSET(DB_STAT_SUBSYSTEM)) + __mutex_clear(dbenv, region->mtx_region); memset(®ion->stat, 0, sizeof(region->stat)); region->stat.st_maxtxns = region->maxtxns; region->stat.st_maxnactive = @@ -167,7 +167,7 @@ __txn_stat_print_pp(dbenv, flags) ENV_REQUIRES_CONFIG(dbenv, dbenv->tx_handle, "DB_ENV->txn_stat_print", DB_INIT_TXN); - if ((ret = __db_fchk(dbenv, "DB_ENV->txn_stat", + if ((ret = __db_fchk(dbenv, "DB_ENV->txn_stat_print", flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0) return (ret); @@ -192,7 +192,7 @@ __txn_stat_print(dbenv, flags) int ret; orig_flags = flags; - LF_CLR(DB_STAT_CLEAR); + LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM); if (flags == 0 || LF_ISSET(DB_STAT_ALL)) { ret = __txn_print_stats(dbenv, orig_flags); if (flags == 0 || ret != 0) @@ -317,7 +317,7 @@ __txn_print_all(dbenv, flags) TXN_SYSTEM_LOCK(dbenv); - __db_print_reginfo(dbenv, &mgr->reginfo, "Transaction"); + __db_print_reginfo(dbenv, &mgr->reginfo, "Transaction", flags); __db_msg(dbenv, "%s", DB_GLOBAL(db_line)); __db_msg(dbenv, "DB_TXNMGR handle information:"); diff --git a/db/txn/txn_util.c b/db/txn/txn_util.c index fea21c76f..a455a2ff2 100644 --- a/db/txn/txn_util.c +++ b/db/txn/txn_util.c @@ -1,10 +1,9 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001-2006 - * Oracle Corporation. All rights reserved. + * Copyright (c) 2001,2007 Oracle. All rights reserved. * - * $Id: txn_util.c,v 12.8 2006/08/24 14:46:53 bostic Exp $ + * $Id: txn_util.c,v 12.18 2007/06/13 18:21:32 ubell Exp $ */ #include "db_config.h" @@ -14,6 +13,7 @@ #include "dbinc/lock.h" #include "dbinc/mp.h" #include "dbinc/txn.h" +#include "dbinc/log.h" #include "dbinc/db_am.h" typedef struct __txn_event TXN_EVENT; @@ -34,7 +34,7 @@ struct __txn_event { struct { /* Lock event. */ DB_LOCK lock; - u_int32_t locker; + DB_LOCKER *locker; DB *dbp; } t; } u; @@ -149,7 +149,7 @@ __txn_remrem(dbenv, txn, name) * trade. * * PUBLIC: int __txn_lockevent __P((DB_ENV *, - * PUBLIC: DB_TXN *, DB *, DB_LOCK *, u_int32_t)); + * PUBLIC: DB_TXN *, DB *, DB_LOCK *, DB_LOCKER *)); */ int __txn_lockevent(dbenv, txn, dbp, lock, locker) @@ -157,7 +157,7 @@ __txn_lockevent(dbenv, txn, dbp, lock, locker) DB_TXN *txn; DB *dbp; DB_LOCK *lock; - u_int32_t locker; + DB_LOCKER *locker; { int ret; TXN_EVENT *e; @@ -174,6 +174,7 @@ __txn_lockevent(dbenv, txn, dbp, lock, locker) e->u.t.dbp = dbp; e->op = TXN_TRADE; TAILQ_INSERT_TAIL(&txn->events, e, links); + dbp->cur_txn = txn; return (0); } @@ -183,14 +184,14 @@ __txn_lockevent(dbenv, txn, dbp, lock, locker) * Remove a lock event because the locker is going away. We can remove * by lock (using offset) or by locker_id (or by both). * - * PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, u_int32_t)); + * PUBLIC: void __txn_remlock __P((DB_ENV *, DB_TXN *, DB_LOCK *, DB_LOCKER *)); */ void __txn_remlock(dbenv, txn, lock, locker) DB_ENV *dbenv; DB_TXN *txn; DB_LOCK *lock; - u_int32_t locker; + DB_LOCKER *locker; { TXN_EVENT *e, *next_e; @@ -218,9 +219,10 @@ __txn_remlock(dbenv, txn, lock, locker) req.lock = e->u.t.lock; \ req.op = DB_LOCK_TRADE; \ t_ret = __lock_vec(dbenv, e->u.t.locker, 0, &req, 1, NULL); \ - if (t_ret == 0) \ - e->u.t.dbp->cur_lid = e->u.t.locker; \ - else if (t_ret == DB_NOTFOUND) \ + if (t_ret == 0) { \ + e->u.t.dbp->cur_locker = e->u.t.locker; \ + e->u.t.dbp->cur_txn = NULL; \ + } else if (t_ret == DB_NOTFOUND) \ t_ret = 0; \ if (t_ret != 0 && ret == 0) \ ret = t_ret; \ @@ -275,8 +277,6 @@ __txn_doevents(dbenv, txn, opcode, preprocess) goto dofree; switch (e->op) { case TXN_CLOSE: - /* If we didn't abort this txn, we screwed up badly. */ - DB_ASSERT(dbenv, opcode == TXN_ABORT); if ((t_ret = __db_close(e->u.c.dbp, NULL, DB_NOSYNC)) != 0 && ret == 0) ret = t_ret; @@ -323,3 +323,109 @@ dofree: return (ret); } + +/* + * PUBLIC: int __txn_record_fname __P((DB_ENV *, DB_TXN *, FNAME *)); + */ +int +__txn_record_fname(dbenv, txn, fname) + DB_ENV *dbenv; + DB_TXN *txn; + FNAME *fname; +{ + DB_TXNMGR *mgr; + DB_LOG *dblp; + TXN_DETAIL *td; + roff_t fname_off; + roff_t *np, *ldbs; + u_int32_t i; + int ret; + + if ((td = txn->td) == NULL) + return (0); + mgr = dbenv->tx_handle; + dblp = dbenv->lg_handle; + fname_off = R_OFFSET(&dblp->reginfo, fname); + + /* See if we already have a ref to this DB handle. */ + ldbs = R_ADDR(&mgr->reginfo, td->log_dbs); + for (i = 0, np = ldbs; i < td->nlog_dbs; i++, np++) + if (*np == fname_off) + return (0); + + if (td->nlog_slots <= td->nlog_dbs) { + TXN_SYSTEM_LOCK(dbenv); + if ((ret = __env_alloc(&mgr->reginfo, + sizeof(roff_t) * (td->nlog_slots << 1), &np)) != 0) + return (ret); + memcpy(np, ldbs, td->nlog_dbs * sizeof(roff_t)); + if (td->nlog_slots > TXN_NSLOTS) + __env_alloc_free(&mgr->reginfo, ldbs); + + TXN_SYSTEM_UNLOCK(dbenv); + td->log_dbs = R_OFFSET(&mgr->reginfo, np); + ldbs = np; + td->nlog_slots = td->nlog_slots << 1; + } + + ldbs[td->nlog_dbs] = fname_off; + td->nlog_dbs++; + fname->txn_ref++; + + return (0); +} + +/* + * __txn_dref_fnam -- + * Either pass the fname to our parent txn or decrement the refcount + * and close the fileid if it goes to zero. + * + * PUBLIC: int __txn_dref_fname __P((DB_ENV *, DB_TXN *)); + */ +int +__txn_dref_fname(dbenv, txn) + DB_ENV *dbenv; + DB_TXN *txn; +{ + DB_TXNMGR *mgr; + DB_LOG *dblp; + FNAME *fname; + roff_t *np; + TXN_DETAIL *ptd, *td; + u_int32_t i; + int ret; + + td = txn->td; + + if (td->nlog_dbs == 0) + return (0); + + mgr = dbenv->tx_handle; + dblp = dbenv->lg_handle; + ret = 0; + + ptd = txn->parent != NULL ? txn->parent->td : NULL; + + np = R_ADDR(&mgr->reginfo, td->log_dbs); + for (i = 0; i < td->nlog_dbs; i++, np++) { + fname = R_ADDR(&dblp->reginfo, *np); + MUTEX_LOCK(dbenv, fname->mutex); + if (ptd != NULL) { + fname->txn_ref--; + ret = __txn_record_fname(dbenv, txn->parent, fname); + MUTEX_UNLOCK(dbenv, fname->mutex); + } else if (fname->txn_ref == 1) { + MUTEX_UNLOCK(dbenv, fname->mutex); + DB_ASSERT(dbenv, fname->txn_ref != 0); + ret = __dbreg_close_id_int( + dbenv, fname, DBREG_CLOSE, 0); + } else { + fname->txn_ref--; + MUTEX_UNLOCK(dbenv, fname->mutex); + } + if (ret != 0) + break; + } + + return (ret); +} |