2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
12 #include "dbinc/log.h"
13 #include "dbinc/txn.h"
15 static int __txn_init __P((ENV *, DB_TXNMGR *));
16 static size_t __txn_region_size __P((ENV *));
20 * Open a transaction region.
22 * PUBLIC: int __txn_open __P((ENV *, int));
25 __txn_open(env, create_ok)
32 /* Create/initialize the transaction manager structure. */
33 if ((ret = __os_calloc(env, 1, sizeof(DB_TXNMGR), &mgr)) != 0)
35 TAILQ_INIT(&mgr->txn_chain);
38 /* Join/create the txn region. */
39 mgr->reginfo.env = env;
40 mgr->reginfo.type = REGION_TYPE_TXN;
41 mgr->reginfo.id = INVALID_REGION_ID;
42 mgr->reginfo.flags = REGION_JOIN_OK;
44 F_SET(&mgr->reginfo, REGION_CREATE_OK);
45 if ((ret = __env_region_attach(env,
46 &mgr->reginfo, __txn_region_size(env))) != 0)
49 /* If we created the region, initialize it. */
50 if (F_ISSET(&mgr->reginfo, REGION_CREATE))
51 if ((ret = __txn_init(env, mgr)) != 0)
54 /* Set the local addresses. */
55 mgr->reginfo.primary =
56 R_ADDR(&mgr->reginfo, mgr->reginfo.rp->primary);
58 /* If threaded, acquire a mutex to protect the active TXN list. */
59 if ((ret = __mutex_alloc(
60 env, MTX_TXN_ACTIVE, DB_MUTEX_PROCESS_ONLY, &mgr->mutex)) != 0)
66 err: env->tx_handle = NULL;
67 if (mgr->reginfo.addr != NULL)
68 (void)__env_region_detach(env, &mgr->reginfo, 0);
70 (void)__mutex_free(env, &mgr->mutex);
77 * Initialize a transaction region in shared memory.
92 * Find the last checkpoint in the log.
95 if (LOGGING_ON(env)) {
97 * The log system has already walked through the last
98 * file. Get the LSN of a checkpoint it may have found.
100 if ((ret = __log_get_cached_ckp_lsn(env, &last_ckp)) != 0)
104 * If that didn't work, look backwards from the beginning of
105 * the last log file until we find the last checkpoint.
107 if (IS_ZERO_LSN(last_ckp) &&
108 (ret = __txn_findlastckp(env, &last_ckp, NULL)) != 0)
112 if ((ret = __env_alloc(&mgr->reginfo,
113 sizeof(DB_TXNREGION), &mgr->reginfo.primary)) != 0) {
115 "Unable to allocate memory for the transaction region");
118 mgr->reginfo.rp->primary =
119 R_OFFSET(&mgr->reginfo, mgr->reginfo.primary);
120 region = mgr->reginfo.primary;
121 memset(region, 0, sizeof(*region));
123 if ((ret = __mutex_alloc(
124 env, MTX_TXN_REGION, 0, ®ion->mtx_region)) != 0)
126 mgr->reginfo.mtx_alloc = region->mtx_region;
128 region->maxtxns = dbenv->tx_max;
129 region->last_txnid = TXN_MINIMUM;
130 region->cur_maxid = TXN_MAXIMUM;
132 if ((ret = __mutex_alloc(
133 env, MTX_TXN_CHKPT, 0, ®ion->mtx_ckp)) != 0)
135 region->last_ckp = last_ckp;
136 region->time_ckp = time(NULL);
138 memset(®ion->stat, 0, sizeof(region->stat));
139 #ifdef HAVE_STATISTICS
140 region->stat.st_maxtxns = region->maxtxns;
143 SH_TAILQ_INIT(®ion->active_txn);
144 SH_TAILQ_INIT(®ion->mvcc_txn);
149 * __txn_findlastckp --
150 * Find the last checkpoint in the log, walking backwards from the
151 * max_lsn given or the beginning of the last log file. (The
152 * log system looked through the last log file when it started up.)
154 * PUBLIC: int __txn_findlastckp __P((ENV *, DB_LSN *, DB_LSN *));
157 __txn_findlastckp(env, lsnp, max_lsn)
170 if ((ret = __log_cursor(env, &logc)) != 0)
173 /* Get the last LSN. */
174 memset(&dbt, 0, sizeof(dbt));
175 if (max_lsn != NULL) {
177 if ((ret = __logc_get(logc, &lsn, &dbt, DB_SET)) != 0)
180 if ((ret = __logc_get(logc, &lsn, &dbt, DB_LAST)) != 0)
183 * Twiddle the last LSN so it points to the beginning of the
184 * last file; we know there's no checkpoint after that, since
185 * the log system already looked there.
190 /* Read backwards, looking for checkpoints. */
191 while ((ret = __logc_get(logc, &lsn, &dbt, DB_PREV)) == 0) {
192 if (dbt.size < sizeof(u_int32_t))
194 LOGCOPY_32(env, &rectype, dbt.data);
195 if (rectype == DB___txn_ckp) {
201 err: if ((t_ret = __logc_close(logc)) != 0 && ret == 0)
205 * Not finding a checkpoint is not an error; there may not exist
208 return ((ret == 0 || ret == DB_NOTFOUND) ? 0 : ret);
212 * __txn_env_refresh --
213 * Clean up after the transaction system on a close or failed open.
215 * PUBLIC: int __txn_env_refresh __P((ENV *));
218 __txn_env_refresh(env)
225 int aborted, ret, t_ret;
228 mgr = env->tx_handle;
229 reginfo = &mgr->reginfo;
232 * This function can only be called once per process (i.e., not
233 * once per thread), so no synchronization is required.
235 * The caller is probably doing something wrong if close is called with
236 * active transactions. Try and abort any active transactions that are
237 * not prepared, but it's quite likely the aborts will fail because
238 * recovery won't find open files. If we can't abort any of the
239 * unprepared transaction, panic, we have to run recovery to get back
243 if (TAILQ_FIRST(&mgr->txn_chain) != NULL) {
244 while ((txn = TAILQ_FIRST(&mgr->txn_chain)) != NULL) {
245 /* Prepared transactions are OK. */
247 if (((TXN_DETAIL *)txn->td)->status == TXN_PREPARED) {
248 if ((ret = __txn_discard_int(txn, 0)) != 0) {
250 "unable to discard txn %#lx",
257 if ((t_ret = __txn_abort(txn)) != 0) {
259 "unable to abort transaction %#lx",
261 ret = __env_panic(env, t_ret);
267 "Error: closing the transaction region with active transactions");
273 /* Discard the per-thread lock. */
274 if ((t_ret = __mutex_free(env, &mgr->mutex)) != 0 && ret == 0)
277 /* Detach from the region. */
278 if (F_ISSET(env, ENV_PRIVATE))
279 reginfo->mtx_alloc = MUTEX_INVALID;
280 if ((t_ret = __env_region_detach(env, reginfo, 0)) != 0 && ret == 0)
285 env->tx_handle = NULL;
290 * __txn_region_mutex_count --
291 * Return the number of mutexes the txn region will need.
293 * PUBLIC: u_int32_t __txn_region_mutex_count __P((ENV *));
296 __txn_region_mutex_count(env)
304 * We need a MVCC mutex for each TXN_DETAIL structure, a mutex for
305 * DB_TXNMGR structure, two mutexes for the DB_TXNREGION structure.
307 return (dbenv->tx_max + 1 + 2);
311 * __txn_region_size --
312 * Return the amount of space needed for the txn region.
315 __txn_region_size(env)
324 * Make the region large enough to hold the primary transaction region
325 * structure, txn_max transaction detail structures, txn_max chunks of
326 * overhead required by the underlying shared region allocator for each
327 * chunk of memory, txn_max transaction names, at an average of 20
328 * bytes each, and 10KB for safety.
330 s = sizeof(DB_TXNREGION) +
331 dbenv->tx_max * (sizeof(TXN_DETAIL) + __env_alloc_overhead() + 20) +
338 * Set the current transaction ID and current maximum unused ID (for
339 * testing purposes only).
341 * PUBLIC: int __txn_id_set __P((ENV *, u_int32_t, u_int32_t));
344 __txn_id_set(env, cur_txnid, max_txnid)
346 u_int32_t cur_txnid, max_txnid;
349 DB_TXNREGION *region;
352 ENV_REQUIRES_CONFIG(env, env->tx_handle, "txn_id_set", DB_INIT_TXN);
354 mgr = env->tx_handle;
355 region = mgr->reginfo.primary;
356 region->last_txnid = cur_txnid;
357 region->cur_maxid = max_txnid;
360 if (cur_txnid < TXN_MINIMUM) {
361 __db_errx(env, "Current ID value %lu below minimum",
365 if (max_txnid < TXN_MINIMUM) {
366 __db_errx(env, "Maximum ID value %lu below minimum",
374 * __txn_oldest_reader --
375 * Find the oldest "read LSN" of any active transaction'
376 * MVCC changes older than this can safely be discarded from the cache.
378 * PUBLIC: int __txn_oldest_reader __P((ENV *, DB_LSN *));
381 __txn_oldest_reader(env, lsnp)
387 DB_TXNREGION *region;
391 if ((mgr = env->tx_handle) == NULL)
393 region = mgr->reginfo.primary;
395 if ((ret = __log_current_lsn(env, &old_lsn, NULL, NULL)) != 0)
398 TXN_SYSTEM_LOCK(env);
399 SH_TAILQ_FOREACH(td, ®ion->active_txn, links, __txn_detail)
400 if (LOG_COMPARE(&td->read_lsn, &old_lsn) < 0)
401 old_lsn = td->read_lsn;
404 TXN_SYSTEM_UNLOCK(env);
410 * __txn_add_buffer --
411 * Add to the count of buffers created by the given transaction.
413 * PUBLIC: int __txn_add_buffer __P((ENV *, TXN_DETAIL *));
416 __txn_add_buffer(env, td)
420 DB_ASSERT(env, td != NULL);
422 MUTEX_LOCK(env, td->mvcc_mtx);
423 DB_ASSERT(env, td->mvcc_ref < UINT32_MAX);
425 MUTEX_UNLOCK(env, td->mvcc_mtx);
427 COMPQUIET(env, NULL);
432 * __txn_remove_buffer --
433 * Remove a buffer from a transaction -- free the transaction if necessary.
435 * PUBLIC: int __txn_remove_buffer __P((ENV *, TXN_DETAIL *, db_mutex_t));
438 __txn_remove_buffer(env, td, hash_mtx)
444 DB_TXNREGION *region;
447 DB_ASSERT(env, td != NULL);
449 mgr = env->tx_handle;
450 region = mgr->reginfo.primary;
452 MUTEX_LOCK(env, td->mvcc_mtx);
453 DB_ASSERT(env, td->mvcc_ref > 0);
456 * We free the transaction detail here only if this is the last
457 * reference and td is on the list of committed snapshot transactions
460 need_free = (--td->mvcc_ref == 0) && F_ISSET(td, TXN_DTL_SNAPSHOT);
461 MUTEX_UNLOCK(env, td->mvcc_mtx);
464 MUTEX_UNLOCK(env, hash_mtx);
466 ret = __mutex_free(env, &td->mvcc_mtx);
467 td->mvcc_mtx = MUTEX_INVALID;
469 TXN_SYSTEM_LOCK(env);
470 SH_TAILQ_REMOVE(®ion->mvcc_txn, td, links, __txn_detail);
471 #ifdef HAVE_STATISTICS
472 --region->stat.st_nsnapshot;
474 __env_alloc_free(&mgr->reginfo, td);
475 TXN_SYSTEM_UNLOCK(env);
477 MUTEX_READLOCK(env, hash_mtx);