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.12 (Sleepycat) 1/8/98";
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
,
91 pagep
, argp
->indx
, argp
->nbytes
)) != 0)
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
;
589 COMPQUIET(logp
, NULL
);
591 REC_PRINT(__db_debug_print
);
592 REC_NOOP_INTRO(__db_debug_read
);
594 *lsnp
= argp
->prev_lsn
;
601 * __db_noop_recover --
602 * Recovery function for noop.
604 * PUBLIC: int __db_noop_recover
605 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
608 __db_noop_recover(logp
, dbtp
, lsnp
, redo
, info
)
615 __db_noop_args
*argp
;
619 COMPQUIET(logp
, NULL
);
621 REC_PRINT(__db_noop_print
);
622 REC_NOOP_INTRO(__db_noop_read
);
624 *lsnp
= argp
->prev_lsn
;