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