summaryrefslogtreecommitdiff
path: root/src/txn/txn_region.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/txn/txn_region.c')
-rw-r--r--src/txn/txn_region.c121
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, &current, 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, &region->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, &region->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);
}
/*