diff options
Diffstat (limited to 'src/txn/txn_region.c')
-rw-r--r-- | src/txn/txn_region.c | 121 |
1 files changed, 101 insertions, 20 deletions
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); } /* |