1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2005-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/txn.h"
13
14/*
15 * __txn_failchk --
16 *	Check for transactions started by dead threads of control.
17 *
18 * PUBLIC: int __txn_failchk __P((ENV *));
19 */
20int
21__txn_failchk(env)
22	ENV *env;
23{
24	DB_ENV *dbenv;
25	DB_TXN *ktxn, *txn;
26	DB_TXNMGR *mgr;
27	DB_TXNREGION *region;
28	TXN_DETAIL *ktd, *td;
29	db_threadid_t tid;
30	int ret;
31	char buf[DB_THREADID_STRLEN];
32	pid_t pid;
33
34	mgr = env->tx_handle;
35	dbenv = env->dbenv;
36	region = mgr->reginfo.primary;
37
38retry:	TXN_SYSTEM_LOCK(env);
39
40	SH_TAILQ_FOREACH(td, &region->active_txn, links, __txn_detail) {
41		/*
42		 * If this is a child transaction, skip it.
43		 * The parent will take care of it.
44		 */
45		if (td->parent != INVALID_ROFF)
46			continue;
47		/*
48		 * If the txn is prepared, then it does not matter
49		 * what the state of the thread is.
50		 */
51		if (td->status == TXN_PREPARED)
52			continue;
53
54		/* If the thread is still alive, it's not a problem. */
55		if (dbenv->is_alive(dbenv, td->pid, td->tid, 0))
56			continue;
57
58		if (F_ISSET(td, TXN_DTL_INMEMORY)) {
59			TXN_SYSTEM_UNLOCK(env);
60			return (__db_failed(env,
61			     "Transaction has in memory logs",
62			     td->pid, td->tid));
63		}
64
65		/* Abort the transaction. */
66		TXN_SYSTEM_UNLOCK(env);
67		if ((ret = __os_calloc(env, 1, sizeof(DB_TXN), &txn)) != 0)
68			return (ret);
69		if ((ret = __txn_continue(env, txn, td)) != 0)
70			return (ret);
71		F_SET(txn, TXN_MALLOC);
72		SH_TAILQ_FOREACH(ktd, &td->kids, klinks, __txn_detail) {
73			if (F_ISSET(ktd, TXN_DTL_INMEMORY))
74				return (__db_failed(env,
75				     "Transaction has in memory logs",
76				     td->pid, td->tid));
77			if ((ret =
78			    __os_calloc(env, 1, sizeof(DB_TXN), &ktxn)) != 0)
79				return (ret);
80			if ((ret = __txn_continue(env, ktxn, ktd)) != 0)
81				return (ret);
82			F_SET(ktxn, TXN_MALLOC);
83			ktxn->parent = txn;
84			TAILQ_INSERT_HEAD(&txn->kids, txn, klinks);
85		}
86		TAILQ_INSERT_TAIL(&mgr->txn_chain, txn, links);
87		pid = td->pid;
88		tid = td->tid;
89		(void)dbenv->thread_id_string(dbenv, pid, tid, buf);
90		__db_msg(env,
91		    "Aborting txn %#lx: %s", (u_long)txn->txnid, buf);
92		if ((ret = __txn_abort(txn)) != 0)
93			return (__db_failed(env,
94			     "Transaction abort failed", pid, tid));
95		goto retry;
96	}
97
98	TXN_SYSTEM_UNLOCK(env);
99
100	return (0);
101}
102