xref: /illumos-gate/usr/src/cmd/sendmail/db/xa/xa_map.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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
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
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
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
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
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
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
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
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
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