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