1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1998,2008 Oracle.  All rights reserved.
5 *
6 * $Id: xa_db.c,v 12.12 2008/01/08 20:59:00 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/txn.h"
13
14static int __xa_close __P((DB *, u_int32_t));
15static int __xa_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
16static int __xa_del __P((DB *, DB_TXN *, DBT *, u_int32_t));
17static int __xa_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
18static int __xa_open __P((DB *, DB_TXN *,
19	    const char *, const char *, DBTYPE, u_int32_t, int));
20static int __xa_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
21static int __xa_set_txn __P((DB *, DB_TXN **, int));
22static int __xa_truncate __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
23
24typedef struct __xa_methods {
25	int (*close) __P((DB *, u_int32_t));
26	int (*cursor) __P((DB *, DB_TXN *, DBC **, u_int32_t));
27	int (*del) __P((DB *, DB_TXN *, DBT *, u_int32_t));
28	int (*get) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
29	int (*open) __P((DB *, DB_TXN *,
30	    const char *, const char *, DBTYPE, u_int32_t, int));
31	int (*put) __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
32	int (*truncate) __P((DB *, DB_TXN *, u_int32_t *, u_int32_t));
33} XA_METHODS;
34
35/*
36 * __xa_set_txn --
37 *	Find a transaction handle.
38 */
39static int
40__xa_set_txn(dbp, txnpp, no_xa_txn)
41	DB *dbp;
42	DB_TXN **txnpp;
43	int no_xa_txn;
44{
45	ENV *env;
46	int ret;
47
48	env = dbp->env;
49
50	/*
51	 * It doesn't make sense for a server to specify a DB_TXN handle.
52	 * As the server can't know if other operations it has done have
53	 * committed/aborted, it can self-deadlock.  If the server wants
54	 * other transactions, it can open other DB handles and use them.
55	 * Disallow specified DB_TXN handles.
56	 */
57	if (*txnpp != NULL) {
58		__db_errx(env,
59    "transaction handles should not be directly specified to XA interfaces");
60		return (EINVAL);
61	}
62
63	/* See if the TM has declared a transaction. */
64	if ((ret = __xa_get_txn(env, txnpp, 0)) != 0)
65		return (ret);
66	if ((*txnpp)->txnid != TXN_INVALID)
67		return (0);
68
69	/*
70	 * We may be opening databases in the server initialization routine.
71	 * In that case, it's reasonable not to have an XA transaction.  It's
72	 * also reasonable to open a database as part of an XA transaction,
73	 * allow both.
74	 */
75	if (no_xa_txn) {
76		*txnpp = NULL;
77		return (0);
78	}
79
80	__db_errx(env, "no XA transaction declared");
81	return (EINVAL);
82}
83
84/*
85 * __db_xa_create --
86 *	DB XA constructor.
87 *
88 * PUBLIC: int __db_xa_create __P((DB *));
89 */
90int
91__db_xa_create(dbp)
92	DB *dbp;
93{
94	XA_METHODS *xam;
95	int ret;
96
97	/*
98	 * Allocate the XA internal structure, and wrap the open and close
99	 * calls.
100	 */
101	if ((ret = __os_calloc(dbp->env, 1, sizeof(XA_METHODS), &xam)) != 0)
102		return (ret);
103
104	dbp->xa_internal = xam;
105	xam->open = dbp->open;
106	dbp->open = __xa_open;
107	xam->close = dbp->close;
108	dbp->close = __xa_close;
109
110	return (0);
111}
112
113/*
114 * __xa_open --
115 *	XA open wrapper.
116 */
117static int
118__xa_open(dbp, txn, name, subdb, type, flags, mode)
119	DB *dbp;
120	DB_TXN *txn;
121	const char *name, *subdb;
122	DBTYPE type;
123	u_int32_t flags;
124	int mode;
125{
126	XA_METHODS *xam;
127	int ret;
128
129	xam = (XA_METHODS *)dbp->xa_internal;
130
131	if ((ret =
132	    __xa_set_txn(dbp, &txn, LF_ISSET(DB_AUTO_COMMIT) ? 1 : 0)) != 0)
133		return (ret);
134	if ((ret = xam->open(dbp, txn, name, subdb, type, flags, mode)) != 0)
135		return (ret);
136
137	/* Wrap any DB handle method that takes a TXN ID as an argument. */
138	xam->cursor = dbp->cursor;
139	xam->del = dbp->del;
140	xam->get = dbp->get;
141	xam->put = dbp->put;
142	xam->truncate = dbp->truncate;
143	dbp->cursor = __xa_cursor;
144	dbp->del = __xa_del;
145	dbp->get = __xa_get;
146	dbp->put = __xa_put;
147	dbp->truncate = __xa_truncate;
148
149	return (0);
150}
151
152static int
153__xa_cursor(dbp, txn, dbcp, flags)
154	DB *dbp;
155	DB_TXN *txn;
156	DBC **dbcp;
157	u_int32_t flags;
158{
159	int ret;
160
161	if ((ret = __xa_set_txn(dbp, &txn, 0)) != 0)
162		return (ret);
163	return (((XA_METHODS *)
164	    dbp->xa_internal)->cursor(dbp, txn, dbcp, flags));
165}
166
167static int
168__xa_del(dbp, txn, key, flags)
169	DB *dbp;
170	DB_TXN *txn;
171	DBT *key;
172	u_int32_t flags;
173{
174	int ret;
175
176	if ((ret = __xa_set_txn(dbp, &txn, 0)) != 0)
177		return (ret);
178	return (((XA_METHODS *)dbp->xa_internal)->del(dbp, txn, key, flags));
179}
180
181static int
182__xa_close(dbp, flags)
183	DB *dbp;
184	u_int32_t flags;
185{
186	int (*real_close) __P((DB *, u_int32_t));
187
188	real_close = ((XA_METHODS *)dbp->xa_internal)->close;
189
190	__os_free(dbp->env, dbp->xa_internal);
191	dbp->xa_internal = NULL;
192
193	return (real_close(dbp, flags));
194}
195
196static int
197__xa_get(dbp, txn, key, data, flags)
198	DB *dbp;
199	DB_TXN *txn;
200	DBT *key, *data;
201	u_int32_t flags;
202{
203	int ret;
204
205	if ((ret = __xa_set_txn(dbp, &txn, 0)) != 0)
206		return (ret);
207	return (((XA_METHODS *)
208	    dbp->xa_internal)->get(dbp, txn, key, data, flags));
209}
210
211static int
212__xa_put(dbp, txn, key, data, flags)
213	DB *dbp;
214	DB_TXN *txn;
215	DBT *key, *data;
216	u_int32_t flags;
217{
218	int ret;
219
220	if ((ret = __xa_set_txn(dbp, &txn, 0)) != 0)
221		return (ret);
222	return (((XA_METHODS *)
223	    dbp->xa_internal)->put(dbp, txn, key, data, flags));
224}
225
226static int
227__xa_truncate(dbp, txn, countp, flags)
228	DB *dbp;
229	DB_TXN *txn;
230	u_int32_t *countp, flags;
231{
232	int ret;
233
234	if ((ret = __xa_set_txn(dbp, &txn, 0)) != 0)
235		return (ret);
236	return (((XA_METHODS *)
237	    dbp->xa_internal)->truncate(dbp, txn, countp, flags));
238}
239