2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid[] = "@(#)db_rec.c 10.10 (Sleepycat) 11/2/97";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
27 #include "db_dispatch.h"
33 * PUBLIC: int __db_addrem_recover
34 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
36 * This log message is generated whenever we add or remove a duplicate
37 * to/from a duplicate page. On recover, we just do the opposite.
40 __db_addrem_recover(logp, dbtp, lsnp, redo, info)
47 __db_addrem_args *argp;
51 int change, cmp_n, cmp_p, ret;
53 REC_PRINT(__db_addrem_print);
54 REC_INTRO(__db_addrem_read);
56 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
59 * We are undoing and the page doesn't exist. That
60 * is equivalent to having a pagelsn of 0, so we
61 * would not have to undo anything. In this case,
62 * don't bother creating a page.
64 *lsnp = argp->prev_lsn;
68 if ((ret = memp_fget(mpf,
69 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
73 cmp_n = log_compare(lsnp, &LSN(pagep));
74 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
76 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_DUP) ||
77 (cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
79 /* Need to redo an add, or undo a delete. */
80 if ((ret = __db_pitem(file_dbp, pagep, argp->indx, argp->nbytes,
81 argp->hdr.size == 0 ? NULL : &argp->hdr,
82 argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
85 change = DB_MPOOL_DIRTY;
87 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
88 (cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
89 /* Need to undo an add, or redo a delete. */
90 if ((ret = __db_ditem(file_dbp, pagep, argp->indx,
93 change = DB_MPOOL_DIRTY;
100 LSN(pagep) = argp->pagelsn;
102 if ((ret = memp_fput(mpf, pagep, change)) == 0)
103 *lsnp = argp->prev_lsn;
109 * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
112 __db_split_recover(logp, dbtp, lsnp, redo, info)
119 __db_split_args *argp;
123 int change, cmp_n, cmp_p, ret;
125 REC_PRINT(__db_split_print);
126 REC_INTRO(__db_split_read);
128 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
131 * We are undoing and the page doesn't exist. That
132 * is equivalent to having a pagelsn of 0, so we
133 * would not have to undo anything. In this case,
134 * don't bother creating a page.
136 *lsnp = argp->prev_lsn;
140 if ((ret = memp_fget(mpf,
141 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
146 * There are two types of log messages here, one for the old page
147 * and one for the new pages created. The original image in the
148 * SPLITOLD record is used for undo. The image in the SPLITNEW
149 * is used for redo. We should never have a case where there is
150 * a redo operation and the SPLITOLD record is on disk, but not
151 * the SPLITNEW record. Therefore, we only redo NEW messages
152 * and only undo OLD messages.
156 cmp_n = log_compare(lsnp, &LSN(pagep));
157 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
158 if (cmp_p == 0 && redo) {
159 if (argp->opcode == DB_SPLITNEW) {
160 /* Need to redo the split described. */
162 argp->pageimage.data, argp->pageimage.size);
165 change = DB_MPOOL_DIRTY;
166 } else if (cmp_n == 0 && !redo) {
167 if (argp->opcode == DB_SPLITOLD) {
168 /* Put back the old image. */
170 argp->pageimage.data, argp->pageimage.size);
172 LSN(pagep) = argp->pagelsn;
173 change = DB_MPOOL_DIRTY;
175 if ((ret = memp_fput(mpf, pagep, change)) == 0)
176 *lsnp = argp->prev_lsn;
182 * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
185 __db_big_recover(logp, dbtp, lsnp, redo, info)
196 int change, cmp_n, cmp_p, ret;
198 REC_PRINT(__db_big_print);
199 REC_INTRO(__db_big_read);
201 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
204 * We are undoing and the page doesn't exist. That
205 * is equivalent to having a pagelsn of 0, so we
206 * would not have to undo anything. In this case,
207 * don't bother creating a page.
212 if ((ret = memp_fget(mpf,
213 &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
218 * There are three pages we need to check. The one on which we are
219 * adding data, the previous one whose next_pointer may have
220 * been updated, and the next one whose prev_pointer may have
223 cmp_n = log_compare(lsnp, &LSN(pagep));
224 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
226 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
227 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
228 /* We are either redo-ing an add, or undoing a delete. */
229 P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
230 argp->next_pgno, 0, P_OVERFLOW);
231 OV_LEN(pagep) = argp->dbt.size;
233 memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
235 PREV_PGNO(pagep) = argp->prev_pgno;
236 change = DB_MPOOL_DIRTY;
237 } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_BIG) ||
238 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
240 * We are either undo-ing an add or redo-ing a delete.
241 * The page is about to be reclaimed in either case, so
242 * there really isn't anything to do here.
244 change = DB_MPOOL_DIRTY;
247 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
249 if ((ret = memp_fput(mpf, pagep, change)) != 0)
252 /* Now check the previous page. */
253 ppage: if (argp->prev_pgno != PGNO_INVALID) {
255 if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0)
258 * We are undoing and the page doesn't exist.
259 * That is equivalent to having a pagelsn of 0,
260 * so we would not have to undo anything. In
261 * this case, don't bother creating a page.
263 *lsnp = argp->prev_lsn;
267 if ((ret = memp_fget(mpf, &argp->prev_pgno,
268 DB_MPOOL_CREATE, &pagep)) != 0)
271 cmp_n = log_compare(lsnp, &LSN(pagep));
272 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
274 if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
275 (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
276 /* Redo add, undo delete. */
277 NEXT_PGNO(pagep) = argp->pgno;
278 change = DB_MPOOL_DIRTY;
279 } else if ((cmp_n == 0 &&
280 !redo && argp->opcode == DB_ADD_BIG) ||
281 (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
282 /* Redo delete, undo add. */
283 NEXT_PGNO(pagep) = argp->next_pgno;
284 change = DB_MPOOL_DIRTY;
287 LSN(pagep) = redo ? *lsnp : argp->prevlsn;
288 if ((ret = memp_fput(mpf, pagep, change)) != 0)
292 /* Now check the next page. Can only be set on a delete. */
293 npage: if (argp->next_pgno != PGNO_INVALID) {
295 if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0)
298 * We are undoing and the page doesn't exist.
299 * That is equivalent to having a pagelsn of 0,
300 * so we would not have to undo anything. In
301 * this case, don't bother creating a page.
303 *lsnp = argp->prev_lsn;
307 if ((ret = memp_fget(mpf, &argp->next_pgno,
308 DB_MPOOL_CREATE, &pagep)) != 0)
311 cmp_n = log_compare(lsnp, &LSN(pagep));
312 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
313 if (cmp_p == 0 && redo) {
314 PREV_PGNO(pagep) = PGNO_INVALID;
315 change = DB_MPOOL_DIRTY;
316 } else if (cmp_n == 0 && !redo) {
317 PREV_PGNO(pagep) = argp->pgno;
318 change = DB_MPOOL_DIRTY;
321 LSN(pagep) = redo ? *lsnp : argp->nextlsn;
322 if ((ret = memp_fput(mpf, pagep, change)) != 0)
326 *lsnp = argp->prev_lsn;
332 * __db_ovref_recover --
333 * Recovery function for __db_ovref().
335 * PUBLIC: int __db_ovref_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
338 __db_ovref_recover(logp, dbtp, lsnp, redo, info)
345 __db_ovref_args *argp;
351 REC_PRINT(__db_ovref_print);
352 REC_INTRO(__db_ovref_read);
354 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
355 (void)__db_pgerr(file_dbp, argp->pgno);
360 if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
361 /* Need to redo update described. */
362 OV_REF(pagep) += argp->adjust;
366 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
367 /* Need to undo update described. */
368 OV_REF(pagep) -= argp->adjust;
370 pagep->lsn = argp->lsn;
373 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) == 0)
374 *lsnp = argp->prev_lsn;
380 * __db_relink_recover --
381 * Recovery function for relink.
383 * PUBLIC: int __db_relink_recover
384 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
387 __db_relink_recover(logp, dbtp, lsnp, redo, info)
394 __db_relink_args *argp;
400 REC_PRINT(__db_relink_print);
401 REC_INTRO(__db_relink_read);
404 * There are three pages we need to check -- the page, and the
405 * previous and next pages, if they existed.
407 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
409 (void)__db_pgerr(file_dbp, argp->pgno);
415 if (log_compare(&LSN(pagep), &argp->lsn) == 0 && redo) {
416 /* Redo the relink. */
419 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
420 /* Undo the relink. */
421 pagep->next_pgno = argp->next;
422 pagep->prev_pgno = argp->prev;
424 pagep->lsn = argp->lsn;
427 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
428 (void)__db_panic(file_dbp);
432 next: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
434 (void)__db_pgerr(file_dbp, argp->next);
440 if (log_compare(&LSN(pagep), &argp->lsn_next) == 0 && redo) {
441 /* Redo the relink. */
442 pagep->prev_pgno = argp->prev;
446 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
447 /* Undo the relink. */
448 pagep->prev_pgno = argp->pgno;
450 pagep->lsn = argp->lsn_next;
453 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
454 (void)__db_panic(file_dbp);
458 prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
460 (void)__db_pgerr(file_dbp, argp->prev);
466 if (log_compare(&LSN(pagep), &argp->lsn_prev) == 0 && redo) {
467 /* Redo the relink. */
468 pagep->next_pgno = argp->next;
472 } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
473 /* Undo the relink. */
474 pagep->next_pgno = argp->pgno;
476 pagep->lsn = argp->lsn_prev;
479 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
480 (void) __db_panic(file_dbp);
484 done: *lsnp = argp->prev_lsn;
491 * PUBLIC: int __db_addpage_recover
492 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
495 __db_addpage_recover(logp, dbtp, lsnp, redo, info)
502 __db_addpage_args *argp;
506 int change, cmp_n, cmp_p, ret;
508 REC_PRINT(__db_addpage_print);
509 REC_INTRO(__db_addpage_read);
512 * We need to check two pages: the old one and the new one onto
513 * which we're going to add duplicates. Do the old one first.
515 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
519 cmp_n = log_compare(lsnp, &LSN(pagep));
520 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
521 if (cmp_p == 0 && redo) {
522 NEXT_PGNO(pagep) = argp->nextpgno;
525 change = DB_MPOOL_DIRTY;
526 } else if (cmp_n == 0 && !redo) {
527 NEXT_PGNO(pagep) = PGNO_INVALID;
529 LSN(pagep) = argp->lsn;
530 change = DB_MPOOL_DIRTY;
532 if ((ret = memp_fput(mpf, pagep, change)) != 0)
535 if ((ret = memp_fget(mpf, &argp->nextpgno, 0, &pagep)) != 0)
538 * We are undoing and the page doesn't exist. That
539 * is equivalent to having a pagelsn of 0, so we
540 * would not have to undo anything. In this case,
541 * don't bother creating a page.
546 if ((ret = memp_fget(mpf,
547 &argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
551 cmp_n = log_compare(lsnp, &LSN(pagep));
552 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
553 if (cmp_p == 0 && redo) {
554 PREV_PGNO(pagep) = argp->pgno;
557 change = DB_MPOOL_DIRTY;
558 } else if (cmp_n == 0 && !redo) {
559 PREV_PGNO(pagep) = PGNO_INVALID;
561 LSN(pagep) = argp->nextlsn;
562 change = DB_MPOOL_DIRTY;
564 ret = memp_fput(mpf, pagep, change);
567 *lsnp = argp->prev_lsn;
572 * __db_debug_recover --
573 * Recovery function for debug.
575 * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
578 __db_debug_recover(logp, dbtp, lsnp, redo, info)
585 __db_debug_args *argp;
588 REC_PRINT(__db_debug_print);
589 REC_NOOP_INTRO(__db_debug_read);
591 *lsnp = argp->prev_lsn;
598 * __db_noop_recover --
599 * Recovery function for noop.
601 * PUBLIC: int __db_noop_recover
602 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
605 __db_noop_recover(logp, dbtp, lsnp, redo, info)
612 __db_noop_args *argp;
615 REC_PRINT(__db_noop_print);
616 REC_NOOP_INTRO(__db_noop_read);
618 *lsnp = argp->prev_lsn;