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
__txn_regop_recover(logp,dbtp,lsnp,redo,info)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
__txn_xa_regop_recover(logp,dbtp,lsnp,redo,info)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
__txn_ckp_recover(logp,dbtp,lsnp,redo,info)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
__txn_child_recover(logp,dbtp,lsnp,redo,info)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
__txn_restore_txn(dbenv,lsnp,argp)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