diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2015-02-17 17:25:57 +0000 |
---|---|---|
committer | <> | 2015-03-17 16:26:24 +0000 |
commit | 780b92ada9afcf1d58085a83a0b9e6bc982203d1 (patch) | |
tree | 598f8b9fa431b228d29897e798de4ac0c1d3d970 /src/txn | |
parent | 7a2660ba9cc2dc03a69ddfcfd95369395cc87444 (diff) | |
download | berkeleydb-780b92ada9afcf1d58085a83a0b9e6bc982203d1.tar.gz |
Diffstat (limited to 'src/txn')
-rw-r--r-- | src/txn/txn.c | 42 | ||||
-rw-r--r-- | src/txn/txn.src | 2 | ||||
-rw-r--r-- | src/txn/txn_chkpt.c | 4 | ||||
-rw-r--r-- | src/txn/txn_failchk.c | 4 | ||||
-rw-r--r-- | src/txn/txn_method.c | 2 | ||||
-rw-r--r-- | src/txn/txn_rec.c | 7 | ||||
-rw-r--r-- | src/txn/txn_recover.c | 6 | ||||
-rw-r--r-- | src/txn/txn_region.c | 121 | ||||
-rw-r--r-- | src/txn/txn_stat.c | 2 | ||||
-rw-r--r-- | src/txn/txn_util.c | 43 |
10 files changed, 168 insertions, 65 deletions
diff --git a/src/txn/txn.c b/src/txn/txn.c index 81225e5c..91652cb7 100644 --- a/src/txn/txn.c +++ b/src/txn/txn.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 1995, 1996 @@ -227,8 +227,15 @@ __txn_begin(env, ip, parent, txnpp, flags) if (LF_ISSET(DB_TXN_FAMILY)) F_SET(txn, TXN_FAMILY | TXN_INFAMILY | TXN_READONLY); 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); + (parent != NULL && F_ISSET(parent, TXN_SNAPSHOT))) { + if (IS_REP_CLIENT(env)) { + __db_errx(env, DB_STR("4572", + "DB_TXN_SNAPSHOT may not be used on a replication client")); + ret = (EINVAL); + goto err; + } else + F_SET(txn, TXN_SNAPSHOT); + } if (LF_ISSET(DB_IGNORE_LEASE)) F_SET(txn, TXN_IGNORE_LEASE); @@ -581,8 +588,7 @@ __txn_continue(env, txn, td, ip, add_to_list) txn->set_timeout = __txn_set_timeout; txn->set_txn_lsnp = __txn_set_txn_lsnp; - /* XXX Do we need to explicitly set a SYNC flag here? */ - txn->flags = TXN_MALLOC | + txn->flags = TXN_MALLOC | TXN_SYNC | (F_ISSET(td, TXN_DTL_NOWAIT) ? TXN_NOWAIT : 0); txn->xa_thr_status = TXN_XA_THREAD_NOTA; @@ -795,8 +801,9 @@ __txn_commit(txn, flags) if (ret == 0) { DB_LSN s_lsn; - DB_ASSERT(env, __log_current_lsn_int( - env, &s_lsn, NULL, NULL) == 0); + if ((ret = __log_current_lsn_int( + env, &s_lsn, NULL, NULL)) != 0) + goto err; DB_ASSERT(env, LOG_COMPARE( &td->visible_lsn, &s_lsn) <= 0); COMPQUIET(s_lsn.file, 0); @@ -890,17 +897,16 @@ static int __txn_close_cursors(txn) DB_TXN *txn; { - int ret, tret; + int ret, t_ret; DBC *dbc; - ret = tret = 0; + ret = t_ret = 0; dbc = NULL; if (txn == NULL) return (0); while ((dbc = TAILQ_FIRST(&txn->my_cursors)) != NULL) { - DB_ASSERT(dbc->env, txn == dbc->txn); /* @@ -913,21 +919,21 @@ __txn_close_cursors(txn) /* Removed from the active queue here. */ if (F_ISSET(dbc, DBC_ACTIVE)) - ret = __dbc_close(dbc); + t_ret = __dbc_close(dbc); dbc->txn = NULL; /* We have to close all cursors anyway, so continue on error. */ - if (ret != 0) { - __db_err(dbc->env, ret, "__dbc_close"); - if (tret == 0) - tret = ret; + if (t_ret != 0) { + __db_err(dbc->env, t_ret, "__dbc_close"); + if (ret == 0) + ret = t_ret; } } txn->my_cursors.tqh_first = NULL; txn->my_cursors.tqh_last = NULL; - return (tret);/* Return the first error if any. */ + return (ret); /* Return the first error, if any. */ } /* @@ -1050,7 +1056,7 @@ __txn_abort(txn) * it, however make sure that it is aborted when the last process * tries to abort it. */ - if (txn->xa_thr_status != TXN_XA_THREAD_NOTA && td->xa_ref > 1) { + if (txn->xa_thr_status != TXN_XA_THREAD_NOTA && td->xa_ref > 1) { td->status = TXN_NEED_ABORT; return (0); } @@ -2165,5 +2171,5 @@ __txn_applied(env, ip, commit_info, timeout) if (renv->envid == commit_info->envid && LOG_COMPARE(&commit_info->lsn, &lsn) <= 0) return (0); - return (DB_NOTFOUND); + return (USR_ERR(env, DB_NOTFOUND)); } diff --git a/src/txn/txn.src b/src/txn/txn.src index 7e82dc82..d9af5318 100644 --- a/src/txn/txn.src +++ b/src/txn/txn.src @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ diff --git a/src/txn/txn_chkpt.c b/src/txn/txn_chkpt.c index 73715b10..a909767f 100644 --- a/src/txn/txn_chkpt.c +++ b/src/txn/txn_chkpt.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 1995, 1996 @@ -377,7 +377,7 @@ __txn_getckp(env, lsnp) TXN_SYSTEM_UNLOCK(env); if (IS_ZERO_LSN(lsn)) - return (DB_NOTFOUND); + return (USR_ERR(env, DB_NOTFOUND)); *lsnp = lsn; return (0); diff --git a/src/txn/txn_failchk.c b/src/txn/txn_failchk.c index b2007ad6..94f22ec2 100644 --- a/src/txn/txn_failchk.c +++ b/src/txn/txn_failchk.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2005, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -57,7 +57,7 @@ retry: TXN_SYSTEM_LOCK(env); if (F_ISSET(td, TXN_DTL_INMEMORY)) { TXN_SYSTEM_UNLOCK(env); - return (__db_failed(env, DB_STR("4501", + return (__db_failed(env, DB_STR("4573", "Transaction has in memory logs"), td->pid, td->tid)); } diff --git a/src/txn/txn_method.c b/src/txn/txn_method.c index 629eac04..357e78c6 100644 --- a/src/txn/txn_method.c +++ b/src/txn/txn_method.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ diff --git a/src/txn/txn_rec.c b/src/txn/txn_rec.c index b39d56d1..708af98a 100644 --- a/src/txn/txn_rec.c +++ b/src/txn/txn_rec.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 1996 @@ -210,11 +210,12 @@ __txn_prepare_recover(env, dbtp, lsnp, op, info) */ else if ((ret = __db_txnlist_remove(env, info, argp->txnp->txnid)) != 0) { -txn_err: __db_errx(env, +txn_err: + ret = USR_ERR(env, DB_NOTFOUND); + __db_errx(env, DB_STR_A("4515", "transaction not in list %lx", "%lx"), (u_long)argp->txnp->txnid); - ret = DB_NOTFOUND; } else if (IS_ZERO_LSN(headp->trunc_lsn) || LOG_COMPARE(&headp->trunc_lsn, lsnp) >= 0) { if ((ret = __db_txnlist_add(env, diff --git a/src/txn/txn_recover.c b/src/txn/txn_recover.c index 67f24439..915a289f 100644 --- a/src/txn/txn_recover.c +++ b/src/txn/txn_recover.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -305,8 +305,8 @@ __txn_openfiles(env, ip, min, force) if ((ret = __db_txnlist_init(env, ip, 0, 0, NULL, &txninfo)) != 0) goto err; - ret = __env_openfiles( - env, logc, txninfo, &data, &open_lsn, NULL, (double)0, 0); + ret = __env_openfiles(env, + logc, txninfo, &data, &open_lsn, NULL, (double)0, 0); if (txninfo != NULL) __db_txnlist_end(env, txninfo); diff --git a/src/txn/txn_region.c b/src/txn/txn_region.c index 6f43d45f..7fef66e6 100644 --- a/src/txn/txn_region.c +++ b/src/txn/txn_region.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -13,6 +13,7 @@ #include "dbinc/txn.h" static int __txn_init __P((ENV *, DB_TXNMGR *)); +static int lsn_hi_to_low __P((const void *, const void *)); /* * __txn_open -- @@ -57,12 +58,30 @@ __txn_open(env) env->tx_handle = mgr; return (0); -err: env->tx_handle = NULL; - if (mgr->reginfo.addr != NULL) - (void)__env_region_detach(env, &mgr->reginfo, 0); +err: (void)__mutex_free(env, &mgr->mutex); + (void)__txn_region_detach(env, mgr); - (void)__mutex_free(env, &mgr->mutex); - __os_free(env, mgr); + return (ret); +} + +/* + * __txn_region_detach -- + * + * PUBLIC: int __txn_region_detach __P((ENV *, DB_TXNMGR *)); + */ +int +__txn_region_detach(env, mgr) + ENV *env; + DB_TXNMGR *mgr; +{ + int ret; + + ret = 0; + if (mgr != NULL) { + ret = __env_region_detach(env, &mgr->reginfo, 0); + __os_free(env, mgr); + env->tx_handle = NULL; + } return (ret); } @@ -409,39 +428,101 @@ __txn_id_set(env, cur_txnid, max_txnid) } /* - * __txn_oldest_reader -- - * Find the oldest "read LSN" of any active transaction' - * MVCC changes older than this can safely be discarded from the cache. + * lsn_hi_to_low -- + * Compare lsns, sorting them from high to low. This is the opposite of + * __rep_lsn_cmp. + */ +static int +lsn_hi_to_low(lsn1, lsn2) + const void *lsn1, *lsn2; +{ + return (LOG_COMPARE((DB_LSN *)lsn2, (DB_LSN *)lsn1)); +} + +/* + * __txn_get_readers -- + * Find the read LSN of all active transactions. + * MVCC versions older than the oldest active transaction can safely be + * discarded from the cache. MVCC versions not quite so old can be + * discarded if they are not visible to any active transaction. * - * PUBLIC: int __txn_oldest_reader __P((ENV *, DB_LSN *)); + * Returns: + * An error code, or 0. + * If 0 was returned, *readers has been filled in with an __os_malloc()'d + * array of active transactions with read_lsns, sorted from newest + * (largest) to oldest (smallest). *ntxnsp indicates how many are there. + * The last lsn is that of the oldest active mvcc-supporting transaction. + * The caller must __os_free() *readers whenever it is non-NULL. + * + * PUBLIC: int __txn_get_readers __P((ENV *, DB_LSN **, int *)); */ +#define TXN_READERS_SIZE 64 /* Initial number of LSNs to allocate. */ int -__txn_oldest_reader(env, lsnp) +__txn_get_readers(env, readers, ntxnsp) ENV *env; - DB_LSN *lsnp; + DB_LSN **readers; + int *ntxnsp; { - DB_LSN old_lsn; + DB_LSN current, *lsns; DB_TXNMGR *mgr; DB_TXNREGION *region; TXN_DETAIL *td; - int ret; + int cmp, is_sorted, ret; + unsigned count, txnmax; + + *ntxnsp = 0; + *readers = NULL; if ((mgr = env->tx_handle) == NULL) return (0); region = mgr->reginfo.primary; + lsns = NULL; + + if ((ret = __log_current_lsn_int(env, ¤t, NULL, NULL)) != 0) + return (ret); - if ((ret = __log_current_lsn_int(env, &old_lsn, NULL, NULL)) != 0) + txnmax = TXN_READERS_SIZE; + if ((ret = __os_malloc(env, txnmax * sizeof(lsns[0]), &lsns)) != 0) return (ret); TXN_SYSTEM_LOCK(env); - SH_TAILQ_FOREACH(td, ®ion->active_txn, links, __txn_detail) - if (LOG_COMPARE(&td->read_lsn, &old_lsn) < 0) - old_lsn = td->read_lsn; + /* The array always has at least the current lsn. */ + lsns[0] = current; + count = 1; + is_sorted = TRUE; - *lsnp = old_lsn; + /* + * Build up our array in most-recent (largest) to first-started (oldest) + * order. Delete adjacent dups. Detect when the txns need to be sorted. + */ + SH_TAILQ_FOREACH(td, ®ion->active_txn, links, __txn_detail) { + if (IS_MAX_LSN(td->read_lsn) || + (cmp = LOG_COMPARE(&td->read_lsn, &lsns[count - 1])) == 0) + continue; + if (cmp > 0) + is_sorted = FALSE; + if (count >= txnmax) { + txnmax += txnmax; + if ((ret = __os_realloc(env, + txnmax * sizeof(lsns[0]), &lsns)) != 0) + goto err; + } + lsns[count] = td->read_lsn; + count++; + } + +err: TXN_SYSTEM_UNLOCK(env); - return (0); + if (ret != 0) + __os_free(env, lsns); + else { + if (!is_sorted) + qsort(lsns, count, sizeof(lsns[0]), lsn_hi_to_low); + *ntxnsp = (int)count; + *readers = lsns; + } + return (ret); } /* diff --git a/src/txn/txn_stat.c b/src/txn/txn_stat.c index 62fe622d..231ac3c5 100644 --- a/src/txn/txn_stat.c +++ b/src/txn/txn_stat.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ diff --git a/src/txn/txn_util.c b/src/txn/txn_util.c index 0ecd7f6c..9f3b8cf6 100644 --- a/src/txn/txn_util.c +++ b/src/txn/txn_util.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -9,6 +9,7 @@ #include "db_config.h" #include "db_int.h" +#include "dbinc/blob.h" #include "dbinc/db_page.h" #include "dbinc/lock.h" #include "dbinc/mp.h" @@ -209,7 +210,7 @@ __txn_remlock(env, txn, lock, locker) for (e = TAILQ_FIRST(&txn->events); e != NULL; e = next_e) { next_e = TAILQ_NEXT(e, links); - if ((e->op != TXN_TRADE && e->op != TXN_TRADED && + if ((e->op != TXN_TRADE && e->op != TXN_TRADED && e->op != TXN_XTRADE) || (e->u.t.lock.off != lock->off && e->u.t.locker != locker)) continue; @@ -280,13 +281,21 @@ __txn_doevents(env, txn, opcode, preprocess) e != NULL; e = enext) { enext = TAILQ_NEXT(e, links); /* - * Move all exclusive handle locks and + * Move all exclusive handle locks and * read handle locks to the handle locker. */ if (!(opcode == TXN_COMMIT && e->op == TXN_XTRADE) && - (e->op != TXN_TRADE || - IS_WRITELOCK(e->u.t.lock.mode))) + (e->op != TXN_TRADE || + IS_WRITELOCK(e->u.t.lock.mode))) { + if (opcode == TXN_PREPARE && + e->op == TXN_REMOVE) { + __db_errx(env, DB_STR_A("4501", +"TXN->prepare is not allowed because this transaction removes \"%s\"", "%s"), + e->u.r.name); + return (EINVAL); + } continue; + } DO_TRADE; if (txn->parent != NULL) { TAILQ_REMOVE(&txn->events, e, links); @@ -321,17 +330,26 @@ __txn_doevents(env, txn, opcode, preprocess) ret = t_ret; break; case TXN_REMOVE: - if (txn->parent != NULL) + if (txn->parent != NULL) { TAILQ_INSERT_TAIL( &txn->parent->events, e, links); - else if (e->u.r.fileid != NULL) { + continue; + } else if (e->u.r.fileid != NULL) { if ((t_ret = __memp_nameop(env, e->u.r.fileid, NULL, e->u.r.name, NULL, e->u.r.inmem)) != 0 && ret == 0) ret = t_ret; - } else if ((t_ret = - __os_unlink(env, e->u.r.name, 0)) != 0 && ret == 0) - ret = t_ret; + } else if ((t_ret = __os_unlink( + env, e->u.r.name, 0)) != 0 && ret == 0) { + /* + * It is possible for blob files to be deleted + * multiple times when truncating a database, + * so ignore ENOENT errors with blob files. + */ + if (t_ret != ENOENT || strstr( + e->u.r.name, BLOB_FILE_PREFIX) == NULL) + ret = t_ret; + } break; case TXN_TRADE: case TXN_XTRADE: @@ -371,8 +389,6 @@ dofree: /* Free resources here. */ switch (e->op) { case TXN_REMOVE: - if (txn->parent != NULL) - continue; if (e->u.r.fileid != NULL) __os_free(env, e->u.r.fileid); __os_free(env, e->u.r.name); @@ -548,9 +564,8 @@ __txn_reset_fe_watermarks(txn) { DB *db; - if (txn->parent) { + if (txn->parent) DB_ASSERT(txn->mgrp->env, TAILQ_FIRST(&txn->femfs) == NULL); - } while ((db = TAILQ_FIRST(&txn->femfs))) __clear_fe_watermark(txn, db); |