2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
8 * Copyright (c) 1995, 1996
9 * Margo Seltzer. All rights reserved.
12 * Copyright (c) 1995, 1996
13 * The President and Fellows of Harvard University. All rights reserved.
15 * This code is derived from software contributed to Berkeley by
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the University of
29 * California, Berkeley and its contributors.
30 * 4. Neither the name of the University nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 static const char sccsid
[] = "@(#)hash_rec.c 10.19 (Sleepycat) 5/23/98";
53 #ifndef NO_SYSTEM_INCLUDES
54 #include <sys/types.h>
66 #include "common_ext.h"
69 * __ham_insdel_recover --
71 * PUBLIC: int __ham_insdel_recover
72 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
75 __ham_insdel_recover(logp
, dbtp
, lsnp
, redo
, info
)
82 __ham_insdel_args
*argp
;
88 int cmp_n
, cmp_p
, getmeta
, ret
;
91 hashp
= NULL
; /* XXX: shut the compiler up. */
92 REC_PRINT(__ham_insdel_print
);
93 REC_INTRO(__ham_insdel_read
);
95 ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
);
99 * We are undoing and the page doesn't exist. That
100 * is equivalent to having a pagelsn of 0, so we
101 * would not have to undo anything. In this case,
102 * don't bother creating a page.
104 *lsnp
= argp
->prev_lsn
;
107 } else if ((ret
= memp_fget(mpf
, &argp
->pgno
,
108 DB_MPOOL_CREATE
, &pagep
)) != 0)
112 hashp
= (HTAB
*)file_dbp
->internal
;
113 GET_META(file_dbp
, hashp
);
116 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
117 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
119 * Two possible things going on:
120 * redo a delete/undo a put: delete the item from the page.
121 * redo a put/undo a delete: add the item to the page.
122 * If we are undoing a delete, then the information logged is the
123 * entire entry off the page, not just the data of a dbt. In
124 * this case, we want to copy it back onto the page verbatim.
125 * We do this by calling __putitem with the type H_OFFPAGE instead
128 op
= OPCODE_OF(argp
->opcode
);
130 if ((op
== DELPAIR
&& cmp_n
== 0 && !redo
) ||
131 (op
== PUTPAIR
&& cmp_p
== 0 && redo
)) {
133 * Need to redo a PUT or undo a delete. If we are undoing a
134 * delete, we've got to restore the item back to its original
135 * position. That's a royal pain in the butt (because we do
136 * not store item lengths on the page), but there's no choice.
139 argp
->ndx
== (u_int32_t
)H_NUMPAIRS(pagep
)) {
140 __ham_putitem(pagep
, &argp
->key
,
141 !redo
|| PAIR_ISKEYBIG(argp
->opcode
) ?
142 H_OFFPAGE
: H_KEYDATA
);
143 __ham_putitem(pagep
, &argp
->data
,
144 !redo
|| PAIR_ISDATABIG(argp
->opcode
) ?
145 H_OFFPAGE
: H_KEYDATA
);
147 (void) __ham_reputpair(pagep
, hashp
->hdr
->pagesize
,
148 argp
->ndx
, &argp
->key
, &argp
->data
);
150 LSN(pagep
) = redo
? *lsnp
: argp
->pagelsn
;
151 if ((ret
= __ham_put_page(file_dbp
, pagep
, 1)) != 0)
154 } else if ((op
== DELPAIR
&& cmp_p
== 0 && redo
)
155 || (op
== PUTPAIR
&& cmp_n
== 0 && !redo
)) {
156 /* Need to undo a put or redo a delete. */
157 __ham_dpair(file_dbp
, pagep
, argp
->ndx
);
158 LSN(pagep
) = redo
? *lsnp
: argp
->pagelsn
;
159 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 1)) != 0)
162 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 0)) != 0)
165 /* Return the previous LSN. */
166 *lsnp
= argp
->prev_lsn
;
169 RELEASE_META(file_dbp
, hashp
);
174 * __ham_newpage_recover --
175 * This log message is used when we add/remove overflow pages. This
176 * message takes care of the pointer chains, not the data on the pages.
178 * PUBLIC: int __ham_newpage_recover
179 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
182 __ham_newpage_recover(logp
, dbtp
, lsnp
, redo
, info
)
189 __ham_newpage_args
*argp
;
194 int cmp_n
, cmp_p
, change
, getmeta
, ret
;
197 hashp
= NULL
; /* XXX: shut the compiler up. */
198 REC_PRINT(__ham_newpage_print
);
199 REC_INTRO(__ham_newpage_read
);
201 ret
= memp_fget(mpf
, &argp
->new_pgno
, 0, &pagep
);
205 * We are undoing and the page doesn't exist. That
206 * is equivalent to having a pagelsn of 0, so we
207 * would not have to undo anything. In this case,
208 * don't bother creating a page.
212 } else if ((ret
= memp_fget(mpf
, &argp
->new_pgno
,
213 DB_MPOOL_CREATE
, &pagep
)) != 0)
217 hashp
= (HTAB
*)file_dbp
->internal
;
218 GET_META(file_dbp
, hashp
);
222 * There are potentially three pages we need to check: the one
223 * that we created/deleted, the one before it and the one after
227 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
228 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
231 if ((cmp_p
== 0 && redo
&& argp
->opcode
== PUTOVFL
) ||
232 (cmp_n
== 0 && !redo
&& argp
->opcode
== DELOVFL
)) {
233 /* Redo a create new page or undo a delete new page. */
234 P_INIT(pagep
, file_dbp
->pgsize
, argp
->new_pgno
,
235 argp
->prev_pgno
, argp
->next_pgno
, 0, P_HASH
);
237 } else if ((cmp_p
== 0 && redo
&& argp
->opcode
== DELOVFL
) ||
238 (cmp_n
== 0 && !redo
&& argp
->opcode
== PUTOVFL
)) {
240 * Redo a delete or undo a create new page. All we
241 * really need to do is change the LSN.
247 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 0)) != 0)
250 LSN(pagep
) = redo
? *lsnp
: argp
->pagelsn
;
251 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 1)) != 0)
255 /* Now do the prev page. */
256 ppage
: if (argp
->prev_pgno
!= PGNO_INVALID
) {
257 ret
= memp_fget(mpf
, &argp
->prev_pgno
, 0, &pagep
);
262 * We are undoing and the page doesn't exist.
263 * That is equivalent to having a pagelsn of 0,
264 * so we would not have to undo anything. In
265 * this case, don't bother creating a page.
270 memp_fget(mpf
, &argp
->prev_pgno
,
271 DB_MPOOL_CREATE
, &pagep
)) != 0)
275 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
276 cmp_p
= log_compare(&LSN(pagep
), &argp
->prevlsn
);
279 if ((cmp_p
== 0 && redo
&& argp
->opcode
== PUTOVFL
) ||
280 (cmp_n
== 0 && !redo
&& argp
->opcode
== DELOVFL
)) {
281 /* Redo a create new page or undo a delete new page. */
282 pagep
->next_pgno
= argp
->new_pgno
;
284 } else if ((cmp_p
== 0 && redo
&& argp
->opcode
== DELOVFL
) ||
285 (cmp_n
== 0 && !redo
&& argp
->opcode
== PUTOVFL
)) {
286 /* Redo a delete or undo a create new page. */
287 pagep
->next_pgno
= argp
->next_pgno
;
292 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 0)) != 0)
295 LSN(pagep
) = redo
? *lsnp
: argp
->prevlsn
;
296 if ((ret
= __ham_put_page(file_dbp
, (PAGE
*)pagep
, 1)) != 0)
301 /* Now time to do the next page */
302 npage
: if (argp
->next_pgno
!= PGNO_INVALID
) {
303 ret
= memp_fget(mpf
, &argp
->next_pgno
, 0, &pagep
);
308 * We are undoing and the page doesn't exist.
309 * That is equivalent to having a pagelsn of 0,
310 * so we would not have to undo anything. In
311 * this case, don't bother creating a page.
313 *lsnp
= argp
->prev_lsn
;
317 memp_fget(mpf
, &argp
->next_pgno
,
318 DB_MPOOL_CREATE
, &pagep
)) != 0)
322 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
323 cmp_p
= log_compare(&LSN(pagep
), &argp
->nextlsn
);
326 if ((cmp_p
== 0 && redo
&& argp
->opcode
== PUTOVFL
) ||
327 (cmp_n
== 0 && !redo
&& argp
->opcode
== DELOVFL
)) {
328 /* Redo a create new page or undo a delete new page. */
329 pagep
->prev_pgno
= argp
->new_pgno
;
331 } else if ((cmp_p
== 0 && redo
&& argp
->opcode
== DELOVFL
) ||
332 (cmp_n
== 0 && !redo
&& argp
->opcode
== PUTOVFL
)) {
333 /* Redo a delete or undo a create new page. */
334 pagep
->prev_pgno
= argp
->prev_pgno
;
340 __ham_put_page(file_dbp
, (PAGE
*)pagep
, 0)) != 0)
343 LSN(pagep
) = redo
? *lsnp
: argp
->nextlsn
;
345 __ham_put_page(file_dbp
, (PAGE
*)pagep
, 1)) != 0)
349 *lsnp
= argp
->prev_lsn
;
352 RELEASE_META(file_dbp
, hashp
);
358 * __ham_replace_recover --
359 * This log message refers to partial puts that are local to a single
360 * page. You can think of them as special cases of the more general
361 * insdel log message.
363 * PUBLIC: int __ham_replace_recover
364 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
367 __ham_replace_recover(logp
, dbtp
, lsnp
, redo
, info
)
374 __ham_replace_args
*argp
;
381 int change
, cmp_n
, cmp_p
, getmeta
, ret
;
385 hashp
= NULL
; /* XXX: shut the compiler up. */
386 REC_PRINT(__ham_replace_print
);
387 REC_INTRO(__ham_replace_read
);
389 ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
);
393 * We are undoing and the page doesn't exist. That
394 * is equivalent to having a pagelsn of 0, so we
395 * would not have to undo anything. In this case,
396 * don't bother creating a page.
398 *lsnp
= argp
->prev_lsn
;
401 } else if ((ret
= memp_fget(mpf
, &argp
->pgno
,
402 DB_MPOOL_CREATE
, &pagep
)) != 0)
406 hashp
= (HTAB
*)file_dbp
->internal
;
407 GET_META(file_dbp
, hashp
);
410 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
411 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
413 if (cmp_p
== 0 && redo
) {
415 /* Reapply the change as specified. */
416 dbt
.data
= argp
->newitem
.data
;
417 dbt
.size
= argp
->newitem
.size
;
418 grow
= argp
->newitem
.size
- argp
->olditem
.size
;
420 } else if (cmp_n
== 0 && !redo
) {
422 /* Undo the already applied change. */
423 dbt
.data
= argp
->olditem
.data
;
424 dbt
.size
= argp
->olditem
.size
;
425 grow
= argp
->olditem
.size
- argp
->newitem
.size
;
426 LSN(pagep
) = argp
->pagelsn
;
433 __ham_onpage_replace(pagep
,
434 file_dbp
->pgsize
, argp
->ndx
, argp
->off
, grow
, &dbt
);
436 hk
= P_ENTRY(pagep
, argp
->ndx
);
438 HPAGE_PTYPE(hk
) = H_DUPLICATE
;
440 HPAGE_PTYPE(hk
) = H_KEYDATA
;
444 if ((ret
= __ham_put_page(file_dbp
, pagep
, change
)) != 0)
447 *lsnp
= argp
->prev_lsn
;
450 RELEASE_META(file_dbp
, hashp
);
455 * __ham_newpgno_recover --
456 * This log message is used when allocating or deleting an overflow
457 * page. It takes care of modifying the meta data.
459 * PUBLIC: int __ham_newpgno_recover
460 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
463 __ham_newpgno_recover(logp
, dbtp
, lsnp
, redo
, info
)
470 __ham_newpgno_args
*argp
;
475 int change
, cmp_n
, cmp_p
, getmeta
, ret
;
478 hashp
= NULL
; /* XXX: shut the compiler up. */
479 REC_PRINT(__ham_newpgno_print
);
480 REC_INTRO(__ham_newpgno_read
);
482 hashp
= (HTAB
*)file_dbp
->internal
;
483 GET_META(file_dbp
, hashp
);
487 * There are two phases to the recovery here. First we need
488 * to update the meta data; then we need to update the page.
489 * We'll do the meta-data first.
491 cmp_n
= log_compare(lsnp
, &hashp
->hdr
->lsn
);
492 cmp_p
= log_compare(&hashp
->hdr
->lsn
, &argp
->metalsn
);
495 if ((cmp_p
== 0 && redo
&& argp
->opcode
== ALLOCPGNO
) ||
496 (cmp_n
== 0 && !redo
&& argp
->opcode
== DELPGNO
)) {
497 /* Need to redo an allocation or undo a deletion. */
498 hashp
->hdr
->last_freed
= argp
->free_pgno
;
499 if (redo
&& argp
->old_pgno
!= 0) /* Must be ALLOCPGNO */
500 hashp
->hdr
->spares
[hashp
->hdr
->ovfl_point
]++;
502 } else if (cmp_p
== 0 && redo
&& argp
->opcode
== DELPGNO
) {
503 /* Need to redo a deletion */
504 hashp
->hdr
->last_freed
= argp
->pgno
;
506 } else if (cmp_n
== 0 && !redo
&& argp
->opcode
== ALLOCPGNO
) {
507 /* undo an allocation. */
508 if (argp
->old_pgno
== 0)
509 hashp
->hdr
->last_freed
= argp
->pgno
;
511 hashp
->hdr
->spares
[hashp
->hdr
->ovfl_point
]--;
512 hashp
->hdr
->last_freed
= 0;
517 hashp
->hdr
->lsn
= redo
? *lsnp
: argp
->metalsn
;
518 F_SET(file_dbp
, DB_HS_DIRTYMETA
);
522 /* Now check the newly allocated/freed page. */
523 ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
);
528 * We are undoing and the page doesn't exist. That
529 * is equivalent to having a pagelsn of 0, so we
530 * would not have to undo anything. In this case,
531 * don't bother creating a page.
533 *lsnp
= argp
->prev_lsn
;
536 } else if ((ret
= memp_fget(mpf
, &argp
->pgno
,
537 DB_MPOOL_CREATE
, &pagep
)) != 0)
541 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
542 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
545 if (cmp_p
== 0 && redo
&& argp
->opcode
== ALLOCPGNO
) {
546 /* Need to redo an allocation. */
547 P_INIT(pagep
, file_dbp
->pgsize
, argp
->pgno
, PGNO_INVALID
,
548 PGNO_INVALID
, 0, argp
->new_type
);
550 } else if (cmp_n
== 0 && !redo
&& argp
->opcode
== DELPGNO
) {
551 /* Undoing a delete. */
552 P_INIT(pagep
, file_dbp
->pgsize
, argp
->pgno
, PGNO_INVALID
,
553 argp
->old_pgno
, 0, argp
->old_type
);
555 } else if ((cmp_p
== 0 && redo
&& argp
->opcode
== DELPGNO
) ||
556 (cmp_n
== 0 && !redo
&& argp
->opcode
== ALLOCPGNO
)) {
557 /* Need to redo a deletion or undo an allocation. */
558 NEXT_PGNO(pagep
) = argp
->free_pgno
;
559 TYPE(pagep
) = P_INVALID
;
563 LSN(pagep
) = redo
? *lsnp
: argp
->pagelsn
;
565 if ((ret
= __ham_put_page(file_dbp
, pagep
, change
)) != 0)
568 *lsnp
= argp
->prev_lsn
;
571 RELEASE_META(file_dbp
, hashp
);
577 * __ham_splitmeta_recover --
578 * This is the meta-data part of the split. Records the new and old
579 * bucket numbers and the new/old mask information.
581 * PUBLIC: int __ham_splitmeta_recover
582 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
585 __ham_splitmeta_recover(logp
, dbtp
, lsnp
, redo
, info
)
592 __ham_splitmeta_args
*argp
;
596 int change
, cmp_n
, cmp_p
, getmeta
, ret
;
600 hashp
= NULL
; /* XXX: shut the compiler up. */
601 REC_PRINT(__ham_splitmeta_print
);
602 REC_INTRO(__ham_splitmeta_read
);
604 hashp
= (HTAB
*)file_dbp
->internal
;
605 GET_META(file_dbp
, hashp
);
609 * There are two phases to the recovery here. First we need
610 * to update the meta data; then we need to update the page.
611 * We'll do the meta-data first.
613 cmp_n
= log_compare(lsnp
, &hashp
->hdr
->lsn
);
614 cmp_p
= log_compare(&hashp
->hdr
->lsn
, &argp
->metalsn
);
617 if (cmp_p
== 0 && redo
) {
618 /* Need to redo the split information. */
619 hashp
->hdr
->max_bucket
= argp
->bucket
+ 1;
620 pow
= __db_log2(hashp
->hdr
->max_bucket
+ 1);
621 if (pow
> hashp
->hdr
->ovfl_point
) {
622 hashp
->hdr
->spares
[pow
] =
623 hashp
->hdr
->spares
[hashp
->hdr
->ovfl_point
];
624 hashp
->hdr
->ovfl_point
= pow
;
626 if (hashp
->hdr
->max_bucket
> hashp
->hdr
->high_mask
) {
627 hashp
->hdr
->low_mask
= hashp
->hdr
->high_mask
;
628 hashp
->hdr
->high_mask
=
629 hashp
->hdr
->max_bucket
| hashp
->hdr
->low_mask
;
632 } else if (cmp_n
== 0 && !redo
) {
633 /* Need to undo the split information. */
634 hashp
->hdr
->max_bucket
= argp
->bucket
;
635 hashp
->hdr
->ovfl_point
= argp
->ovflpoint
;
636 hashp
->hdr
->spares
[hashp
->hdr
->ovfl_point
] = argp
->spares
;
637 pow
= 1 << __db_log2(hashp
->hdr
->max_bucket
+ 1);
638 hashp
->hdr
->high_mask
= pow
- 1;
639 hashp
->hdr
->low_mask
= (pow
>> 1) - 1;
643 hashp
->hdr
->lsn
= redo
? *lsnp
: argp
->metalsn
;
644 F_SET(file_dbp
, DB_HS_DIRTYMETA
);
646 *lsnp
= argp
->prev_lsn
;
649 RELEASE_META(file_dbp
, hashp
);
654 * __ham_splitdata_recover --
656 * PUBLIC: int __ham_splitdata_recover
657 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
660 __ham_splitdata_recover(logp
, dbtp
, lsnp
, redo
, info
)
667 __ham_splitdata_args
*argp
;
672 int change
, cmp_n
, cmp_p
, getmeta
, ret
;
675 hashp
= NULL
; /* XXX: shut the compiler up. */
676 REC_PRINT(__ham_splitdata_print
);
677 REC_INTRO(__ham_splitdata_read
);
679 ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
);
683 * We are undoing and the page doesn't exist. That
684 * is equivalent to having a pagelsn of 0, so we
685 * would not have to undo anything. In this case,
686 * don't bother creating a page.
688 *lsnp
= argp
->prev_lsn
;
691 } else if ((ret
= memp_fget(mpf
, &argp
->pgno
,
692 DB_MPOOL_CREATE
, &pagep
)) != 0)
696 hashp
= (HTAB
*)file_dbp
->internal
;
697 GET_META(file_dbp
, hashp
);
700 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
701 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
704 * There are two types of log messages here, one for the old page
705 * and one for the new pages created. The original image in the
706 * SPLITOLD record is used for undo. The image in the SPLITNEW
707 * is used for redo. We should never have a case where there is
708 * a redo operation and the SPLITOLD record is on disk, but not
709 * the SPLITNEW record. Therefore, we only have work to do when
710 * redo NEW messages and undo OLD messages, but we have to update
711 * LSNs in both cases.
714 if (cmp_p
== 0 && redo
) {
715 if (argp
->opcode
== SPLITNEW
)
716 /* Need to redo the split described. */
717 memcpy(pagep
, argp
->pageimage
.data
,
718 argp
->pageimage
.size
);
721 } else if (cmp_n
== 0 && !redo
) {
722 if (argp
->opcode
== SPLITOLD
) {
723 /* Put back the old image. */
724 memcpy(pagep
, argp
->pageimage
.data
,
725 argp
->pageimage
.size
);
727 P_INIT(pagep
, file_dbp
->pgsize
, argp
->pgno
,
728 PGNO_INVALID
, PGNO_INVALID
, 0, P_HASH
);
729 LSN(pagep
) = argp
->pagelsn
;
732 if ((ret
= __ham_put_page(file_dbp
, pagep
, change
)) != 0)
735 *lsnp
= argp
->prev_lsn
;
738 RELEASE_META(file_dbp
, hashp
);
743 * __ham_ovfl_recover --
744 * This message is generated when we initialize a set of overflow pages.
746 * PUBLIC: int __ham_ovfl_recover
747 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
750 __ham_ovfl_recover(logp
, dbtp
, lsnp
, redo
, info
)
757 __ham_ovfl_args
*argp
;
762 db_pgno_t max_pgno
, pgno
;
763 int cmp_n
, cmp_p
, getmeta
, ret
;
766 hashp
= NULL
; /* XXX: shut the compiler up. */
767 REC_PRINT(__ham_ovfl_print
);
768 REC_INTRO(__ham_ovfl_read
);
770 hashp
= (HTAB
*)file_dbp
->internal
;
771 GET_META(file_dbp
, hashp
);
774 cmp_n
= log_compare(lsnp
, &hashp
->hdr
->lsn
);
775 cmp_p
= log_compare(&hashp
->hdr
->lsn
, &argp
->metalsn
);
777 if (cmp_p
== 0 && redo
) {
778 /* Redo the allocation. */
779 hashp
->hdr
->last_freed
= argp
->start_pgno
;
780 hashp
->hdr
->spares
[argp
->ovflpoint
] += argp
->npages
;
781 hashp
->hdr
->lsn
= *lsnp
;
782 F_SET(file_dbp
, DB_HS_DIRTYMETA
);
783 } else if (cmp_n
== 0 && !redo
) {
784 hashp
->hdr
->last_freed
= argp
->free_pgno
;
785 hashp
->hdr
->spares
[argp
->ovflpoint
] -= argp
->npages
;
786 hashp
->hdr
->lsn
= argp
->metalsn
;
787 F_SET(file_dbp
, DB_HS_DIRTYMETA
);
790 max_pgno
= argp
->start_pgno
+ argp
->npages
- 1;
792 for (pgno
= argp
->start_pgno
; pgno
<= max_pgno
; pgno
++) {
793 ret
= memp_fget(mpf
, &pgno
, 0, &pagep
);
795 if (redo
&& (ret
= memp_fget(mpf
, &pgno
,
796 DB_MPOOL_CREATE
, &pagep
)) != 0)
799 (void)__ham_put_page(file_dbp
, pagep
, 0);
803 if (redo
&& log_compare((const DB_LSN
*)lsnp
,
804 (const DB_LSN
*)&LSN(pagep
)) > 0) {
805 P_INIT(pagep
, file_dbp
->pgsize
, pgno
, PGNO_INVALID
,
806 pgno
== max_pgno
? argp
->free_pgno
: pgno
+ 1,
809 ret
= __ham_put_page(file_dbp
, pagep
, 1);
811 ZERO_LSN(pagep
->lsn
);
812 ret
= __ham_put_page(file_dbp
, pagep
, 1);
814 ret
= __ham_put_page(file_dbp
, pagep
, 0);
819 *lsnp
= argp
->prev_lsn
;
821 RELEASE_META(file_dbp
, hashp
);
826 * __ham_copypage_recover --
827 * Recovery function for copypage.
829 * PUBLIC: int __ham_copypage_recover
830 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
833 __ham_copypage_recover(logp
, dbtp
, lsnp
, redo
, info
)
840 __ham_copypage_args
*argp
;
845 int cmp_n
, cmp_p
, getmeta
, modified
, ret
;
848 hashp
= NULL
; /* XXX: shut the compiler up. */
849 REC_PRINT(__ham_copypage_print
);
850 REC_INTRO(__ham_copypage_read
);
852 hashp
= (HTAB
*)file_dbp
->internal
;
853 GET_META(file_dbp
, hashp
);
857 /* This is the bucket page. */
858 ret
= memp_fget(mpf
, &argp
->pgno
, 0, &pagep
);
862 * We are undoing and the page doesn't exist. That
863 * is equivalent to having a pagelsn of 0, so we
864 * would not have to undo anything. In this case,
865 * don't bother creating a page.
869 } else if ((ret
= memp_fget(mpf
, &argp
->pgno
,
870 DB_MPOOL_CREATE
, &pagep
)) != 0)
874 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
875 cmp_p
= log_compare(&LSN(pagep
), &argp
->pagelsn
);
877 if (cmp_p
== 0 && redo
) {
878 /* Need to redo update described. */
879 memcpy(pagep
, argp
->page
.data
, argp
->page
.size
);
882 } else if (cmp_n
== 0 && !redo
) {
883 /* Need to undo update described. */
884 P_INIT(pagep
, hashp
->hdr
->pagesize
, argp
->pgno
, PGNO_INVALID
,
885 argp
->next_pgno
, 0, P_HASH
);
886 LSN(pagep
) = argp
->pagelsn
;
889 if ((ret
= memp_fput(mpf
, pagep
, modified
? DB_MPOOL_DIRTY
: 0)) != 0)
892 /* Now fix up the "next" page. */
893 donext
: ret
= memp_fget(mpf
, &argp
->next_pgno
, 0, &pagep
);
897 * We are undoing and the page doesn't exist. That
898 * is equivalent to having a pagelsn of 0, so we
899 * would not have to undo anything. In this case,
900 * don't bother creating a page.
904 } else if ((ret
= memp_fget(mpf
, &argp
->next_pgno
,
905 DB_MPOOL_CREATE
, &pagep
)) != 0)
909 /* There is nothing to do in the REDO case; only UNDO. */
911 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
912 if (cmp_n
== 0 && !redo
) {
913 /* Need to undo update described. */
914 memcpy(pagep
, argp
->page
.data
, argp
->page
.size
);
917 if ((ret
= memp_fput(mpf
, pagep
, modified
? DB_MPOOL_DIRTY
: 0)) != 0)
920 /* Now fix up the next's next page. */
921 do_nn
: if (argp
->nnext_pgno
== PGNO_INVALID
) {
922 *lsnp
= argp
->prev_lsn
;
926 ret
= memp_fget(mpf
, &argp
->nnext_pgno
, 0, &pagep
);
930 * We are undoing and the page doesn't exist. That
931 * is equivalent to having a pagelsn of 0, so we
932 * would not have to undo anything. In this case,
933 * don't bother creating a page.
936 *lsnp
= argp
->prev_lsn
;
938 } else if ((ret
= memp_fget(mpf
, &argp
->nnext_pgno
,
939 DB_MPOOL_CREATE
, &pagep
)) != 0)
943 cmp_n
= log_compare(lsnp
, &LSN(pagep
));
944 cmp_p
= log_compare(&LSN(pagep
), &argp
->nnextlsn
);
946 if (cmp_p
== 0 && redo
) {
947 /* Need to redo update described. */
948 PREV_PGNO(pagep
) = argp
->pgno
;
951 } else if (cmp_n
== 0 && !redo
) {
952 /* Need to undo update described. */
953 PREV_PGNO(pagep
) = argp
->next_pgno
;
954 LSN(pagep
) = argp
->nnextlsn
;
957 if ((ret
= memp_fput(mpf
, pagep
, modified
? DB_MPOOL_DIRTY
: 0)) != 0)
960 *lsnp
= argp
->prev_lsn
;
963 RELEASE_META(file_dbp
, hashp
);