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 * Copyright (c) 1996 9 * The President and Fellows of Harvard University. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 #include "config.h" 41 42 #ifndef lint 43 static const char sccsid[] = "@(#)txn_rec.c 10.15 (Sleepycat) 1/3/99"; 44 #endif /* not lint */ 45 46 #ifndef NO_SYSTEM_INCLUDES 47 #include <sys/types.h> 48 49 #include <errno.h> 50 #endif 51 52 #include "db_int.h" 53 #include "db_page.h" 54 #include "shqueue.h" 55 #include "txn.h" 56 #include "db_am.h" 57 #include "log.h" 58 #include "common_ext.h" 59 60 static int __txn_restore_txn __P((DB_ENV *, DB_LSN *, __txn_xa_regop_args *)); 61 62 #define IS_XA_TXN(R) (R->xid.size != 0) 63 64 /* 65 * PUBLIC: int __txn_regop_recover 66 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 67 * 68 * These records are only ever written for commits. 69 */ 70 int 71 __txn_regop_recover(logp, dbtp, lsnp, redo, info) 72 DB_LOG *logp; 73 DBT *dbtp; 74 DB_LSN *lsnp; 75 int redo; 76 void *info; 77 { 78 __txn_regop_args *argp; 79 int ret; 80 81 #ifdef DEBUG_RECOVER 82 (void)__txn_regop_print(logp, dbtp, lsnp, redo, info); 83 #endif 84 COMPQUIET(redo, 0); 85 COMPQUIET(logp, NULL); 86 87 if ((ret = __txn_regop_read(dbtp->data, &argp)) != 0) 88 return (ret); 89 90 if (argp->opcode != TXN_COMMIT) 91 ret = EINVAL; 92 else 93 if (__db_txnlist_find(info, argp->txnid->txnid) == DB_NOTFOUND) 94 ret = __db_txnlist_add(info, argp->txnid->txnid); 95 96 if (ret == 0) 97 *lsnp = argp->prev_lsn; 98 __os_free(argp, 0); 99 100 return (ret); 101 } 102 103 /* 104 * PUBLIC: int __txn_xa_regop_recover 105 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 106 * 107 * These records are only ever written for prepares. 108 */ 109 int 110 __txn_xa_regop_recover(logp, dbtp, lsnp, redo, info) 111 DB_LOG *logp; 112 DBT *dbtp; 113 DB_LSN *lsnp; 114 int redo; 115 void *info; 116 { 117 __txn_xa_regop_args *argp; 118 int ret; 119 120 #ifdef DEBUG_RECOVER 121 (void)__txn_xa_regop_print(logp, dbtp, lsnp, redo, info); 122 #endif 123 COMPQUIET(redo, 0); 124 COMPQUIET(logp, NULL); 125 126 if ((ret = __txn_xa_regop_read(dbtp->data, &argp)) != 0) 127 return (ret); 128 129 if (argp->opcode != TXN_PREPARE) 130 ret = EINVAL; 131 else { 132 /* 133 * Whether we are in XA or not, we need to call 134 * __db_txnlist_find so that we update the maxid. 135 * If this is an XA transaction, then we treat 136 * prepares like commits so that we roll forward to 137 * a point where we can handle commit/abort calls 138 * from the TMS. If this isn't XA, then a prepare 139 * is treated like a No-op; we only care about the 140 * commit. 141 */ 142 ret = __db_txnlist_find(info, argp->txnid->txnid); 143 if (IS_XA_TXN(argp) && ret == DB_NOTFOUND) { 144 /* 145 * This is an XA prepared, but not yet committed 146 * transaction. We need to add it to the 147 * transaction list, so that it gets rolled 148 * forward. We also have to add it to the region's 149 * internal state so it can be properly aborted 150 * or recovered. 151 */ 152 ret = __db_txnlist_add(info, argp->txnid->txnid); 153 if (ret == 0) 154 ret = __txn_restore_txn(logp->dbenv, 155 lsnp, argp); 156 } 157 } 158 159 if (ret == 0) 160 *lsnp = argp->prev_lsn; 161 __os_free(argp, 0); 162 163 return (ret); 164 } 165 166 /* 167 * PUBLIC: int __txn_ckp_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 168 */ 169 int 170 __txn_ckp_recover(logp, dbtp, lsnp, redo, info) 171 DB_LOG *logp; 172 DBT *dbtp; 173 DB_LSN *lsnp; 174 int redo; 175 void *info; 176 { 177 __txn_ckp_args *argp; 178 int ret; 179 180 #ifdef DEBUG_RECOVER 181 __txn_ckp_print(logp, dbtp, lsnp, redo, info); 182 #endif 183 COMPQUIET(logp, NULL); 184 185 if ((ret = __txn_ckp_read(dbtp->data, &argp)) != 0) 186 return (ret); 187 188 /* 189 * Check for 'restart' checkpoint record. This occurs when the 190 * checkpoint lsn is equal to the lsn of the checkpoint record 191 * and means that we could set the transaction ID back to 1, so 192 * that we don't exhaust the transaction ID name space. 193 */ 194 if (argp->ckp_lsn.file == lsnp->file && 195 argp->ckp_lsn.offset == lsnp->offset) 196 __db_txnlist_gen(info, redo ? -1 : 1); 197 198 *lsnp = argp->last_ckp; 199 __os_free(argp, 0); 200 return (DB_TXN_CKP); 201 } 202 203 /* 204 * __txn_child_recover 205 * Recover a commit record for a child transaction. 206 * 207 * PUBLIC: int __txn_child_recover 208 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *)); 209 */ 210 int 211 __txn_child_recover(logp, dbtp, lsnp, redo, info) 212 DB_LOG *logp; 213 DBT *dbtp; 214 DB_LSN *lsnp; 215 int redo; 216 void *info; 217 { 218 __txn_child_args *argp; 219 int ret; 220 221 #ifdef DEBUG_RECOVER 222 (void)__txn_child_print(logp, dbtp, lsnp, redo, info); 223 #endif 224 COMPQUIET(redo, 0); 225 COMPQUIET(logp, NULL); 226 227 if ((ret = __txn_child_read(dbtp->data, &argp)) != 0) 228 return (ret); 229 230 /* 231 * We count the child as committed only if its parent committed. 232 * So, if we are not yet in the transaction list, but our parent 233 * is, then we should go ahead and commit. 234 */ 235 if (argp->opcode != TXN_COMMIT) 236 ret = EINVAL; 237 else 238 if (__db_txnlist_find(info, argp->parent) == 0 && 239 __db_txnlist_find(info, argp->txnid->txnid) == DB_NOTFOUND) 240 ret = __db_txnlist_add(info, argp->txnid->txnid); 241 242 if (ret == 0) 243 *lsnp = argp->prev_lsn; 244 __os_free(argp, 0); 245 246 return (ret); 247 } 248 249 /* 250 * __txn_restore_txn -- 251 * Using only during XA recovery. If we find any transactions that are 252 * prepared, but not yet committed, then we need to restore the transaction's 253 * state into the shared region, because the TM is going to issue a txn_abort 254 * or txn_commit and we need to respond correctly. 255 * 256 * lsnp is the LSN of the returned LSN 257 * argp is the perpare record (in an appropriate structure) 258 */ 259 static int 260 __txn_restore_txn(dbenv, lsnp, argp) 261 DB_ENV *dbenv; 262 DB_LSN *lsnp; 263 __txn_xa_regop_args *argp; 264 { 265 DB_TXNMGR *mgr; 266 TXN_DETAIL *td; 267 int ret; 268 269 if (argp->xid.size == 0) 270 return(0); 271 272 mgr = dbenv->tx_info; 273 LOCK_TXNREGION(mgr); 274 275 /* Allocate a new transaction detail structure. */ 276 if ((ret = __db_shalloc(mgr->mem, sizeof(TXN_DETAIL), 0, &td)) != 0) 277 return (ret); 278 279 /* Place transaction on active transaction list. */ 280 SH_TAILQ_INSERT_HEAD(&mgr->region->active_txn, td, links, __txn_detail); 281 282 td->txnid = argp->txnid->txnid; 283 td->begin_lsn = argp->begin_lsn; 284 td->last_lsn = *lsnp; 285 td->last_lock = 0; 286 td->parent = 0; 287 td->status = TXN_PREPARED; 288 td->xa_status = TXN_XA_PREPARED; 289 memcpy(td->xid, argp->xid.data, argp->xid.size); 290 td->bqual = argp->bqual; 291 td->gtrid = argp->gtrid; 292 td->format = argp->formatID; 293 294 UNLOCK_TXNREGION(mgr); 295 return (0); 296 } 297