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