1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)xa_map.c 10.4 (Sleepycat) 10/20/98";
12 #endif /* not lint */
13
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16
17 #include <errno.h>
18 #include <stdio.h>
19 #include <string.h>
20 #endif
21
22 #include "db_int.h"
23 #include "shqueue.h"
24 #include "txn.h"
25
26 /*
27 * This file contains all the mapping information that we need to support
28 * the DB/XA interface.
29 */
30
31 /*
32 * __db_rmid_to_env
33 * Return the environment associated with a given XA rmid.
34 *
35 * PUBLIC: int __db_rmid_to_env __P((int rmid, DB_ENV **envp, int open_ok));
36 */
37 int
__db_rmid_to_env(rmid,envp,open_ok)38 __db_rmid_to_env(rmid, envp, open_ok)
39 int rmid;
40 DB_ENV **envp;
41 int open_ok;
42 {
43 DB_ENV *env;
44 char *dbhome;
45
46 env = TAILQ_FIRST(&DB_GLOBAL(db_envq));
47 if (env != NULL && env->xa_rmid == rmid) {
48 *envp = env;
49 return (0);
50 }
51
52 /*
53 * When we map an rmid, move that environment to be the first one in
54 * the list of environments, so we pass the correct environment from
55 * the upcoming db_xa_open() call into db_open().
56 */
57 for (; env != NULL; env = TAILQ_NEXT(env, links))
58 if (env->xa_rmid == rmid) {
59 TAILQ_REMOVE(&DB_GLOBAL(db_envq), env, links);
60 TAILQ_INSERT_HEAD(&DB_GLOBAL(db_envq), env, links);
61 *envp = env;
62 return (0);
63 }
64
65 /*
66 * We have not found the rmid on the environment list. If we
67 * are allowed to do an open, search for the rmid on the name
68 * list and, if we find it, then open it.
69 */
70 if (!open_ok)
71 return (1);
72
73 if (__db_rmid_to_name(rmid, &dbhome) != 0)
74 return (1);
75 #undef XA_FLAGS
76 #define XA_FLAGS \
77 DB_CREATE | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN
78
79 if (__os_calloc(1, sizeof(DB_ENV), &env) != 0)
80 return (1);
81
82 if (db_appinit(dbhome, NULL, env, XA_FLAGS) != 0)
83 goto err;
84
85 if (__db_map_rmid(rmid, env) != 0)
86 goto err1;
87
88 __db_unmap_rmid_name(rmid);
89
90 *envp = env;
91 return (0);
92
93 err1: (void)db_appexit(env);
94 err: __os_free(env, sizeof(DB_ENV));
95 return (1);
96 }
97
98 /*
99 * __db_xid_to_txn
100 * Return the txn that corresponds to this XID.
101 *
102 * PUBLIC: int __db_xid_to_txn __P((DB_ENV *, XID *, size_t *));
103 */
104 int
__db_xid_to_txn(dbenv,xid,offp)105 __db_xid_to_txn(dbenv, xid, offp)
106 DB_ENV *dbenv;
107 XID *xid;
108 size_t *offp;
109 {
110 DB_TXNREGION *tmr;
111 struct __txn_detail *td;
112
113 /*
114 * Search the internal active transaction table to find the
115 * matching xid. If this is a performance hit, then we
116 * can create a hash table, but I doubt it's worth it.
117 */
118 tmr = dbenv->tx_info->region;
119
120 LOCK_TXNREGION(dbenv->tx_info);
121 for (td = SH_TAILQ_FIRST(&tmr->active_txn, __txn_detail);
122 td != NULL;
123 td = SH_TAILQ_NEXT(td, links, __txn_detail))
124 if (memcmp(xid->data, td->xid, XIDDATASIZE) == 0)
125 break;
126 UNLOCK_TXNREGION(dbenv->tx_info);
127
128 if (td == NULL)
129 return (EINVAL);
130
131 *offp = (u_int8_t *)td - (u_int8_t *)tmr;
132 return (0);
133 }
134
135 /*
136 * __db_map_rmid
137 * Create a mapping between the specified rmid and environment.
138 *
139 * PUBLIC: int __db_map_rmid __P((int, DB_ENV *));
140 */
141 int
__db_map_rmid(rmid,env)142 __db_map_rmid(rmid, env)
143 int rmid;
144 DB_ENV *env;
145 {
146 if (__os_calloc(1, sizeof(DB_TXN), &env->xa_txn) != 0)
147 return (XAER_RMERR);
148 env->xa_txn->txnid = TXN_INVALID;
149 env->xa_rmid = rmid;
150 TAILQ_INSERT_HEAD(&DB_GLOBAL(db_envq), env, links);
151 return (XA_OK);
152 }
153
154 /*
155 * __db_unmap_rmid
156 * Destroy the mapping for the given rmid.
157 *
158 * PUBLIC: int __db_unmap_rmid __P((int));
159 */
160 int
__db_unmap_rmid(rmid)161 __db_unmap_rmid(rmid)
162 int rmid;
163 {
164 DB_ENV *e;
165
166 for (e = TAILQ_FIRST(&DB_GLOBAL(db_envq));
167 e->xa_rmid != rmid;
168 e = TAILQ_NEXT(e, links));
169
170 if (e == NULL)
171 return (EINVAL);
172
173 TAILQ_REMOVE(&DB_GLOBAL(db_envq), e, links);
174 if (e->xa_txn != NULL)
175 __os_free(e->xa_txn, sizeof(DB_TXN));
176 return (0);
177 }
178
179 /*
180 * __db_map_xid
181 * Create a mapping between this XID and the transaction at
182 * "off" in the shared region.
183 *
184 * PUBLIC: int __db_map_xid __P((DB_ENV *, XID *, size_t));
185 */
186 int
__db_map_xid(env,xid,off)187 __db_map_xid(env, xid, off)
188 DB_ENV *env;
189 XID *xid;
190 size_t off;
191 {
192 DB_TXNMGR *tm;
193 TXN_DETAIL *td;
194
195 tm = env->tx_info;
196 td = (TXN_DETAIL *)((u_int8_t *)tm->region + off);
197
198 LOCK_TXNREGION(tm);
199 memcpy(td->xid, xid->data, XIDDATASIZE);
200 UNLOCK_TXNREGION(tm);
201
202 return (0);
203 }
204
205 /*
206 * __db_unmap_xid
207 * Destroy the mapping for the specified XID.
208 *
209 * PUBLIC: void __db_unmap_xid __P((DB_ENV *, XID *, size_t));
210 */
211
212 void
__db_unmap_xid(env,xid,off)213 __db_unmap_xid(env, xid, off)
214 DB_ENV *env;
215 XID *xid;
216 size_t off;
217 {
218 TXN_DETAIL *td;
219
220 COMPQUIET(xid, NULL);
221
222 td = (TXN_DETAIL *)((u_int8_t *)env->tx_info->region + off);
223 memset(td->xid, 0, sizeof(td->xid));
224 }
225
226 /*
227 * __db_map_rmid_name --
228 * Create a mapping from an rmid to a name (the xa_info argument).
229 * We use this during create and then at some later point when we are
230 * trying to map an rmid, we might indicate that it's OK to do an open
231 * in which case, we'll get the xa_info parameter from here and then
232 * free it up.
233 *
234 * PUBLIC: int __db_map_rmid_name __P((int, char *));
235 */
236
237 int
__db_map_rmid_name(rmid,dbhome)238 __db_map_rmid_name(rmid, dbhome)
239 int rmid;
240 char *dbhome;
241 {
242 struct __rmname *entry;
243 int ret;
244
245 if ((ret = __os_malloc(sizeof(struct __rmname), NULL, &entry)) != 0)
246 return (ret);
247
248 if ((ret = __os_strdup(dbhome, &entry->dbhome)) != 0) {
249 __os_free(entry, sizeof(struct __rmname));
250 return (ret);
251 }
252
253 entry->rmid = rmid;
254
255 TAILQ_INSERT_HEAD(&DB_GLOBAL(db_nameq), entry, links);
256 return (0);
257 }
258
259 /*
260 * __db_rmid_to_name --
261 * Given an rmid, return the name of the home directory for that
262 * rmid.
263 *
264 * PUBLIC: int __db_rmid_to_name __P((int, char **));
265 */
266 int
__db_rmid_to_name(rmid,dbhomep)267 __db_rmid_to_name(rmid, dbhomep)
268 int rmid;
269 char **dbhomep;
270 {
271 struct __rmname *np;
272
273 for (np = TAILQ_FIRST(&DB_GLOBAL(db_nameq)); np != NULL;
274 np = TAILQ_NEXT(np, links)) {
275 if (np->rmid == rmid) {
276 *dbhomep = np->dbhome;
277 return (0);
278 }
279 }
280 return (1);
281 }
282
283 /*
284 * __db_unmap_rmid_name --
285 * Given an rmid, remove its entry from the name list.
286 *
287 * PUBLIC: void __db_unmap_rmid_name __P((int));
288 */
289 void
__db_unmap_rmid_name(rmid)290 __db_unmap_rmid_name(rmid)
291 int rmid;
292 {
293 struct __rmname *np, *next;
294
295 for (np = TAILQ_FIRST(&DB_GLOBAL(db_nameq)); np != NULL; np = next) {
296 next = TAILQ_NEXT(np, links);
297 if (np->rmid == rmid) {
298 TAILQ_REMOVE(&DB_GLOBAL(db_nameq), np, links);
299 __os_freestr(np->dbhome);
300 __os_free(np, sizeof(struct __rmname));
301 return;
302 }
303 }
304 return;
305 }
306