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