2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)db_rec.c 10.16 (Sleepycat) 4/28/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
28 * PUBLIC: int __db_addrem_recover
29 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
31 * This log message is generated whenever we add or remove a duplicate
32 * to/from a duplicate page. On recover, we just do the opposite.
35 __db_addrem_recover(logp
, dbtp
, lsnp
, redo
, info
)
42 __db_addrem_args
*argp
;
47 int cmp_n
, cmp_p
, ret
;
49 REC_PRINT(__db_addrem_print
);
50 REC_INTRO(__db_addrem_read
);
52 if ((ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
)) != 0) {
55 * We are undoing and the page doesn't exist. That
56 * is equivalent to having a pagelsn of 0, so we
57 * would not have to undo anything. In this case,
58 * don't bother creating a page.
60 *lsnp
= argp
->prev_lsn
;
64 if ((ret
= memp_fget(mpf
,
65 &argp
->pgno
, DB_MPOOL_CREATE
, &pagep
)) != 0)
69 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
70 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
72 if ((cmp_p
== 0 && redo
&& argp
->opcode
== DB_ADD_DUP
) ||
73 (cmp_n
== 0 && !redo
&& argp
->opcode
== DB_REM_DUP
)) {
75 /* Need to redo an add, or undo a delete. */
76 if ((ret
= __db_pitem(file_dbp
, pagep
, argp
->indx
, argp
->nbytes
,
77 argp
->hdr
.size
== 0 ? NULL
: &argp
->hdr
,
78 argp
->dbt
.size
== 0 ? NULL
: &argp
->dbt
)) != 0)
81 change
= DB_MPOOL_DIRTY
;
83 } else if ((cmp_n
== 0 && !redo
&& argp
->opcode
== DB_ADD_DUP
) ||
84 (cmp_p
== 0 && redo
&& argp
->opcode
== DB_REM_DUP
)) {
85 /* Need to undo an add, or redo a delete. */
86 if ((ret
= __db_ditem(file_dbp
,
87 pagep
, argp
->indx
, argp
->nbytes
)) != 0)
89 change
= DB_MPOOL_DIRTY
;
96 LSN(pagep
) = argp
->pagelsn
;
99 if ((ret
= memp_fput(mpf
, pagep
, change
)) == 0)
100 *lsnp
= argp
->prev_lsn
;
106 * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
109 __db_split_recover(logp
, dbtp
, lsnp
, redo
, info
)
116 __db_split_args
*argp
;
120 int change
, cmp_n
, cmp_p
, ret
;
122 REC_PRINT(__db_split_print
);
123 REC_INTRO(__db_split_read
);
125 if ((ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
)) != 0) {
128 * We are undoing and the page doesn't exist. That
129 * is equivalent to having a pagelsn of 0, so we
130 * would not have to undo anything. In this case,
131 * don't bother creating a page.
133 *lsnp
= argp
->prev_lsn
;
137 if ((ret
= memp_fget(mpf
,
138 &argp
->pgno
, DB_MPOOL_CREATE
, &pagep
)) != 0)
143 * There are two types of log messages here, one for the old page
144 * and one for the new pages created. The original image in the
145 * SPLITOLD record is used for undo. The image in the SPLITNEW
146 * is used for redo. We should never have a case where there is
147 * a redo operation and the SPLITOLD record is on disk, but not
148 * the SPLITNEW record. Therefore, we only redo NEW messages
149 * and only undo OLD messages.
153 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
154 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
155 if (cmp_p
== 0 && redo
) {
156 if (argp
->opcode
== DB_SPLITNEW
) {
157 /* Need to redo the split described. */
159 argp
->pageimage
.data
, argp
->pageimage
.size
);
162 change
= DB_MPOOL_DIRTY
;
163 } else if (cmp_n
== 0 && !redo
) {
164 if (argp
->opcode
== DB_SPLITOLD
) {
165 /* Put back the old image. */
167 argp
->pageimage
.data
, argp
->pageimage
.size
);
169 LSN(pagep
) = argp
->pagelsn
;
170 change
= DB_MPOOL_DIRTY
;
172 if ((ret
= memp_fput(mpf
, pagep
, change
)) == 0)
173 *lsnp
= argp
->prev_lsn
;
179 * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
182 __db_big_recover(logp
, dbtp
, lsnp
, redo
, info
)
194 int cmp_n
, cmp_p
, ret
;
196 REC_PRINT(__db_big_print
);
197 REC_INTRO(__db_big_read
);
199 if ((ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
)) != 0) {
202 * We are undoing and the page doesn't exist. That
203 * is equivalent to having a pagelsn of 0, so we
204 * would not have to undo anything. In this case,
205 * don't bother creating a page.
210 if ((ret
= memp_fget(mpf
,
211 &argp
->pgno
, DB_MPOOL_CREATE
, &pagep
)) != 0)
216 * There are three pages we need to check. The one on which we are
217 * adding data, the previous one whose next_pointer may have
218 * been updated, and the next one whose prev_pointer may have
221 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
222 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
224 if ((cmp_p
== 0 && redo
&& argp
->opcode
== DB_ADD_BIG
) ||
225 (cmp_n
== 0 && !redo
&& argp
->opcode
== DB_REM_BIG
)) {
226 /* We are either redo-ing an add, or undoing a delete. */
227 P_INIT(pagep
, file_dbp
->pgsize
, argp
->pgno
, argp
->prev_pgno
,
228 argp
->next_pgno
, 0, P_OVERFLOW
);
229 OV_LEN(pagep
) = argp
->dbt
.size
;
231 memcpy((u_int8_t
*)pagep
+ P_OVERHEAD
, argp
->dbt
.data
,
233 PREV_PGNO(pagep
) = argp
->prev_pgno
;
234 change
= DB_MPOOL_DIRTY
;
235 } else if ((cmp_n
== 0 && !redo
&& argp
->opcode
== DB_ADD_BIG
) ||
236 (cmp_p
== 0 && redo
&& argp
->opcode
== DB_REM_BIG
)) {
238 * We are either undo-ing an add or redo-ing a delete.
239 * The page is about to be reclaimed in either case, so
240 * there really isn't anything to do here.
242 change
= DB_MPOOL_DIRTY
;
245 LSN(pagep
) = redo
? *lsnp
: argp
->pagelsn
;
247 if ((ret
= memp_fput(mpf
, pagep
, change
)) != 0)
250 /* Now check the previous page. */
251 ppage
: if (argp
->prev_pgno
!= PGNO_INVALID
) {
253 if ((ret
= memp_fget(mpf
, &argp
->prev_pgno
, 0, &pagep
)) != 0) {
256 * We are undoing and the page doesn't exist.
257 * That is equivalent to having a pagelsn of 0,
258 * so we would not have to undo anything. In
259 * this case, don't bother creating a page.
261 *lsnp
= argp
->prev_lsn
;
265 if ((ret
= memp_fget(mpf
, &argp
->prev_pgno
,
266 DB_MPOOL_CREATE
, &pagep
)) != 0)
270 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
271 cmp_p
= log_compare(&LSN(pagep
), &argp
->prevlsn
);
273 if ((cmp_p
== 0 && redo
&& argp
->opcode
== DB_ADD_BIG
) ||
274 (cmp_n
== 0 && !redo
&& argp
->opcode
== DB_REM_BIG
)) {
275 /* Redo add, undo delete. */
276 NEXT_PGNO(pagep
) = argp
->pgno
;
277 change
= DB_MPOOL_DIRTY
;
278 } else if ((cmp_n
== 0 &&
279 !redo
&& argp
->opcode
== DB_ADD_BIG
) ||
280 (cmp_p
== 0 && redo
&& argp
->opcode
== DB_REM_BIG
)) {
281 /* Redo delete, undo add. */
282 NEXT_PGNO(pagep
) = argp
->next_pgno
;
283 change
= DB_MPOOL_DIRTY
;
286 LSN(pagep
) = redo
? *lsnp
: argp
->prevlsn
;
287 if ((ret
= memp_fput(mpf
, pagep
, change
)) != 0)
291 /* Now check the next page. Can only be set on a delete. */
292 npage
: if (argp
->next_pgno
!= PGNO_INVALID
) {
294 if ((ret
= memp_fget(mpf
, &argp
->next_pgno
, 0, &pagep
)) != 0) {
297 * We are undoing and the page doesn't exist.
298 * That is equivalent to having a pagelsn of 0,
299 * so we would not have to undo anything. In
300 * this case, don't bother creating a page.
302 *lsnp
= argp
->prev_lsn
;
306 if ((ret
= memp_fget(mpf
, &argp
->next_pgno
,
307 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
;
507 int cmp_n
, cmp_p
, ret
;
509 REC_PRINT(__db_addpage_print
);
510 REC_INTRO(__db_addpage_read
);
513 * We need to check two pages: the old one and the new one onto
514 * which we're going to add duplicates. Do the old one first.
516 if ((ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
)) != 0)
520 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
521 cmp_p
= log_compare(&LSN(pagep
), &argp
->lsn
);
522 if (cmp_p
== 0 && redo
) {
523 NEXT_PGNO(pagep
) = argp
->nextpgno
;
526 change
= DB_MPOOL_DIRTY
;
527 } else if (cmp_n
== 0 && !redo
) {
528 NEXT_PGNO(pagep
) = PGNO_INVALID
;
530 LSN(pagep
) = argp
->lsn
;
531 change
= DB_MPOOL_DIRTY
;
533 if ((ret
= memp_fput(mpf
, pagep
, change
)) != 0)
536 if ((ret
= memp_fget(mpf
, &argp
->nextpgno
, 0, &pagep
)) != 0) {
539 * We are undoing and the page doesn't exist. That
540 * is equivalent to having a pagelsn of 0, so we
541 * would not have to undo anything. In this case,
542 * don't bother creating a page.
547 if ((ret
= memp_fget(mpf
,
548 &argp
->nextpgno
, DB_MPOOL_CREATE
, &pagep
)) != 0)
553 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
554 cmp_p
= log_compare(&LSN(pagep
), &argp
->nextlsn
);
555 if (cmp_p
== 0 && redo
) {
556 PREV_PGNO(pagep
) = argp
->pgno
;
559 change
= DB_MPOOL_DIRTY
;
560 } else if (cmp_n
== 0 && !redo
) {
561 PREV_PGNO(pagep
) = PGNO_INVALID
;
563 LSN(pagep
) = argp
->nextlsn
;
564 change
= DB_MPOOL_DIRTY
;
566 ret
= memp_fput(mpf
, pagep
, change
);
569 *lsnp
= argp
->prev_lsn
;
574 * __db_debug_recover --
575 * Recovery function for debug.
577 * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
580 __db_debug_recover(logp
, dbtp
, lsnp
, redo
, info
)
587 __db_debug_args
*argp
;
591 COMPQUIET(logp
, NULL
);
593 REC_PRINT(__db_debug_print
);
594 REC_NOOP_INTRO(__db_debug_read
);
596 *lsnp
= argp
->prev_lsn
;
603 * __db_noop_recover --
604 * Recovery function for noop.
606 * PUBLIC: int __db_noop_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
609 __db_noop_recover(logp
, dbtp
, lsnp
, redo
, info
)
616 __db_noop_args
*argp
;
621 int cmp_n
, cmp_p
, ret
;
623 REC_PRINT(__db_noop_print
);
624 REC_INTRO(__db_noop_read
);
626 if ((ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
)) != 0)
629 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
630 cmp_p
= log_compare(&LSN(pagep
), &argp
->prevlsn
);
632 if (cmp_p
== 0 && redo
) {
634 change
= DB_MPOOL_DIRTY
;
635 } else if (cmp_n
== 0 && !redo
) {
636 LSN(pagep
) = argp
->prevlsn
;
637 change
= DB_MPOOL_DIRTY
;
639 *lsnp
= argp
->prev_lsn
;
640 ret
= memp_fput(mpf
, pagep
, change
);