Update.
[glibc.git] / db2 / hash / hash_rec.c
blob727f615828ab26db6b43fbcb4c03d2f37c3779a0
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
7 /*
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
16 * Margo Seltzer.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
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
44 * SUCH DAMAGE.
47 #include "config.h"
49 #ifndef lint
50 static const char sccsid[] = "@(#)hash_rec.c 10.19 (Sleepycat) 5/23/98";
51 #endif /* not lint */
53 #ifndef NO_SYSTEM_INCLUDES
54 #include <sys/types.h>
56 #include <errno.h>
57 #include <string.h>
58 #endif
60 #include "db_int.h"
61 #include "shqueue.h"
62 #include "db_page.h"
63 #include "hash.h"
64 #include "btree.h"
65 #include "log.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 *));
74 int
75 __ham_insdel_recover(logp, dbtp, lsnp, redo, info)
76 DB_LOG *logp;
77 DBT *dbtp;
78 DB_LSN *lsnp;
79 int redo;
80 void *info;
82 __ham_insdel_args *argp;
83 DB *mdbp, *file_dbp;
84 DB_MPOOLFILE *mpf;
85 HTAB *hashp;
86 PAGE *pagep;
87 u_int32_t op;
88 int cmp_n, cmp_p, getmeta, ret;
90 getmeta = 0;
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);
96 if (ret != 0) {
97 if (!redo) {
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;
105 ret = 0;
106 goto out;
107 } else if ((ret = memp_fget(mpf, &argp->pgno,
108 DB_MPOOL_CREATE, &pagep)) != 0)
109 goto out;
112 hashp = (HTAB *)file_dbp->internal;
113 GET_META(file_dbp, hashp);
114 getmeta = 1;
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
126 * of H_KEYDATA.
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.
138 if (op != DELPAIR ||
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);
146 } else
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)
152 goto out;
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)
160 goto out;
161 } else
162 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
163 goto out;
165 /* Return the previous LSN. */
166 *lsnp = argp->prev_lsn;
168 out: if (getmeta)
169 RELEASE_META(file_dbp, hashp);
170 REC_CLOSE;
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)
183 DB_LOG *logp;
184 DBT *dbtp;
185 DB_LSN *lsnp;
186 int redo;
187 void *info;
189 __ham_newpage_args *argp;
190 DB *mdbp, *file_dbp;
191 DB_MPOOLFILE *mpf;
192 HTAB *hashp;
193 PAGE *pagep;
194 int cmp_n, cmp_p, change, getmeta, ret;
196 getmeta = 0;
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);
202 if (ret != 0) {
203 if (!redo) {
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.
210 ret = 0;
211 goto ppage;
212 } else if ((ret = memp_fget(mpf, &argp->new_pgno,
213 DB_MPOOL_CREATE, &pagep)) != 0)
214 goto out;
217 hashp = (HTAB *)file_dbp->internal;
218 GET_META(file_dbp, hashp);
219 getmeta = 1;
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
224 * it.
227 cmp_n = log_compare(lsnp, &LSN(pagep));
228 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
229 change = 0;
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);
236 change = 1;
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.
243 change = 1;
246 if (!change) {
247 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
248 goto out;
249 } else {
250 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
251 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
252 goto out;
255 /* Now do the prev page. */
256 ppage: if (argp->prev_pgno != PGNO_INVALID) {
257 ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep);
259 if (ret != 0) {
260 if (!redo) {
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.
267 ret = 0;
268 goto npage;
269 } else if ((ret =
270 memp_fget(mpf, &argp->prev_pgno,
271 DB_MPOOL_CREATE, &pagep)) != 0)
272 goto out;
275 cmp_n = log_compare(lsnp, &LSN(pagep));
276 cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
277 change = 0;
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;
283 change = 1;
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;
288 change = 1;
291 if (!change) {
292 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
293 goto out;
294 } else {
295 LSN(pagep) = redo ? *lsnp : argp->prevlsn;
296 if ((ret = __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
297 goto out;
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);
305 if (ret != 0) {
306 if (!redo) {
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;
314 ret = 0;
315 goto out;
316 } else if ((ret =
317 memp_fget(mpf, &argp->next_pgno,
318 DB_MPOOL_CREATE, &pagep)) != 0)
319 goto out;
322 cmp_n = log_compare(lsnp, &LSN(pagep));
323 cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
324 change = 0;
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;
330 change = 1;
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;
335 change = 1;
338 if (!change) {
339 if ((ret =
340 __ham_put_page(file_dbp, (PAGE *)pagep, 0)) != 0)
341 goto out;
342 } else {
343 LSN(pagep) = redo ? *lsnp : argp->nextlsn;
344 if ((ret =
345 __ham_put_page(file_dbp, (PAGE *)pagep, 1)) != 0)
346 goto out;
349 *lsnp = argp->prev_lsn;
351 out: if (getmeta)
352 RELEASE_META(file_dbp, hashp);
353 REC_CLOSE;
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)
368 DB_LOG *logp;
369 DBT *dbtp;
370 DB_LSN *lsnp;
371 int redo;
372 void *info;
374 __ham_replace_args *argp;
375 DB *mdbp, *file_dbp;
376 DB_MPOOLFILE *mpf;
377 DBT dbt;
378 HTAB *hashp;
379 PAGE *pagep;
380 int32_t grow;
381 int change, cmp_n, cmp_p, getmeta, ret;
382 u_int8_t *hk;
384 getmeta = 0;
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);
390 if (ret != 0) {
391 if (!redo) {
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;
399 ret = 0;
400 goto out;
401 } else if ((ret = memp_fget(mpf, &argp->pgno,
402 DB_MPOOL_CREATE, &pagep)) != 0)
403 goto out;
406 hashp = (HTAB *)file_dbp->internal;
407 GET_META(file_dbp, hashp);
408 getmeta = 1;
410 cmp_n = log_compare(lsnp, &LSN(pagep));
411 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
413 if (cmp_p == 0 && redo) {
414 change = 1;
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;
419 LSN(pagep) = *lsnp;
420 } else if (cmp_n == 0 && !redo) {
421 change = 1;
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;
427 } else {
428 change = 0;
429 grow = 0;
432 if (change) {
433 __ham_onpage_replace(pagep,
434 file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
435 if (argp->makedup) {
436 hk = P_ENTRY(pagep, argp->ndx);
437 if (redo)
438 HPAGE_PTYPE(hk) = H_DUPLICATE;
439 else
440 HPAGE_PTYPE(hk) = H_KEYDATA;
444 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
445 goto out;
447 *lsnp = argp->prev_lsn;
449 out: if (getmeta)
450 RELEASE_META(file_dbp, hashp);
451 REC_CLOSE;
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)
464 DB_LOG *logp;
465 DBT *dbtp;
466 DB_LSN *lsnp;
467 int redo;
468 void *info;
470 __ham_newpgno_args *argp;
471 DB *mdbp, *file_dbp;
472 DB_MPOOLFILE *mpf;
473 HTAB *hashp;
474 PAGE *pagep;
475 int change, cmp_n, cmp_p, getmeta, ret;
477 getmeta = 0;
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);
484 getmeta = 1;
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);
494 change = 0;
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]++;
501 change = 1;
502 } else if (cmp_p == 0 && redo && argp->opcode == DELPGNO) {
503 /* Need to redo a deletion */
504 hashp->hdr->last_freed = argp->pgno;
505 change = 1;
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;
510 else {
511 hashp->hdr->spares[hashp->hdr->ovfl_point]--;
512 hashp->hdr->last_freed = 0;
514 change = 1;
516 if (change) {
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);
525 if (ret != 0) {
526 if (!redo) {
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;
534 ret = 0;
535 goto out;
536 } else if ((ret = memp_fget(mpf, &argp->pgno,
537 DB_MPOOL_CREATE, &pagep)) != 0)
538 goto out;
541 cmp_n = log_compare(lsnp, &LSN(pagep));
542 cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
544 change = 0;
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);
549 change = 1;
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);
554 change = 1;
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;
560 change = 1;
562 if (change)
563 LSN(pagep) = redo ? *lsnp : argp->pagelsn;
565 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
566 goto out;
568 *lsnp = argp->prev_lsn;
570 out: if (getmeta)
571 RELEASE_META(file_dbp, hashp);
572 REC_CLOSE;
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)
586 DB_LOG *logp;
587 DBT *dbtp;
588 DB_LSN *lsnp;
589 int redo;
590 void *info;
592 __ham_splitmeta_args *argp;
593 DB *mdbp, *file_dbp;
594 DB_MPOOLFILE *mpf;
595 HTAB *hashp;
596 int change, cmp_n, cmp_p, getmeta, ret;
597 u_int32_t pow;
599 getmeta = 0;
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);
606 getmeta = 1;
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);
616 change = 0;
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;
631 change = 1;
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;
640 change = 1;
642 if (change) {
643 hashp->hdr->lsn = redo ? *lsnp : argp->metalsn;
644 F_SET(file_dbp, DB_HS_DIRTYMETA);
646 *lsnp = argp->prev_lsn;
648 out: if (getmeta)
649 RELEASE_META(file_dbp, hashp);
650 REC_CLOSE;
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)
661 DB_LOG *logp;
662 DBT *dbtp;
663 DB_LSN *lsnp;
664 int redo;
665 void *info;
667 __ham_splitdata_args *argp;
668 DB *mdbp, *file_dbp;
669 DB_MPOOLFILE *mpf;
670 HTAB *hashp;
671 PAGE *pagep;
672 int change, cmp_n, cmp_p, getmeta, ret;
674 getmeta = 0;
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);
680 if (ret != 0) {
681 if (!redo) {
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;
689 ret = 0;
690 goto out;
691 } else if ((ret = memp_fget(mpf, &argp->pgno,
692 DB_MPOOL_CREATE, &pagep)) != 0)
693 goto out;
696 hashp = (HTAB *)file_dbp->internal;
697 GET_META(file_dbp, hashp);
698 getmeta = 1;
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.
713 change = 0;
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);
719 LSN(pagep) = *lsnp;
720 change = 1;
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);
726 } else
727 P_INIT(pagep, file_dbp->pgsize, argp->pgno,
728 PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
729 LSN(pagep) = argp->pagelsn;
730 change = 1;
732 if ((ret = __ham_put_page(file_dbp, pagep, change)) != 0)
733 goto out;
735 *lsnp = argp->prev_lsn;
737 out: if (getmeta)
738 RELEASE_META(file_dbp, hashp);
739 REC_CLOSE;
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)
751 DB_LOG *logp;
752 DBT *dbtp;
753 DB_LSN *lsnp;
754 int redo;
755 void *info;
757 __ham_ovfl_args *argp;
758 DB *mdbp, *file_dbp;
759 DB_MPOOLFILE *mpf;
760 HTAB *hashp;
761 PAGE *pagep;
762 db_pgno_t max_pgno, pgno;
763 int cmp_n, cmp_p, getmeta, ret;
765 getmeta = 0;
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);
772 getmeta = 1;
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;
791 ret = 0;
792 for (pgno = argp->start_pgno; pgno <= max_pgno; pgno++) {
793 ret = memp_fget(mpf, &pgno, 0, &pagep);
794 if (ret != 0) {
795 if (redo && (ret = memp_fget(mpf, &pgno,
796 DB_MPOOL_CREATE, &pagep)) != 0)
797 goto out;
798 else if (!redo) {
799 (void)__ham_put_page(file_dbp, pagep, 0);
800 continue;
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,
807 0, P_HASH);
808 LSN(pagep) = *lsnp;
809 ret = __ham_put_page(file_dbp, pagep, 1);
810 } else if (!redo) {
811 ZERO_LSN(pagep->lsn);
812 ret = __ham_put_page(file_dbp, pagep, 1);
813 } else
814 ret = __ham_put_page(file_dbp, pagep, 0);
815 if (ret)
816 goto out;
819 *lsnp = argp->prev_lsn;
820 out: if (getmeta)
821 RELEASE_META(file_dbp, hashp);
822 REC_CLOSE;
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)
834 DB_LOG *logp;
835 DBT *dbtp;
836 DB_LSN *lsnp;
837 int redo;
838 void *info;
840 __ham_copypage_args *argp;
841 DB *file_dbp, *mdbp;
842 DB_MPOOLFILE *mpf;
843 HTAB *hashp;
844 PAGE *pagep;
845 int cmp_n, cmp_p, getmeta, modified, ret;
847 getmeta = 0;
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);
854 getmeta = 1;
855 modified = 0;
857 /* This is the bucket page. */
858 ret = memp_fget(mpf, &argp->pgno, 0, &pagep);
859 if (ret != 0) {
860 if (!redo) {
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.
867 ret = 0;
868 goto donext;
869 } else if ((ret = memp_fget(mpf, &argp->pgno,
870 DB_MPOOL_CREATE, &pagep)) != 0)
871 goto out;
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);
880 LSN(pagep) = *lsnp;
881 modified = 1;
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;
887 modified = 1;
889 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
890 goto out;
892 /* Now fix up the "next" page. */
893 donext: ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep);
894 if (ret != 0) {
895 if (!redo) {
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.
902 ret = 0;
903 goto do_nn;
904 } else if ((ret = memp_fget(mpf, &argp->next_pgno,
905 DB_MPOOL_CREATE, &pagep)) != 0)
906 goto out;
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);
915 modified = 1;
917 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
918 goto out;
920 /* Now fix up the next's next page. */
921 do_nn: if (argp->nnext_pgno == PGNO_INVALID) {
922 *lsnp = argp->prev_lsn;
923 goto out;
926 ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep);
927 if (ret != 0) {
928 if (!redo) {
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.
935 ret = 0;
936 *lsnp = argp->prev_lsn;
937 goto out;
938 } else if ((ret = memp_fget(mpf, &argp->nnext_pgno,
939 DB_MPOOL_CREATE, &pagep)) != 0)
940 goto out;
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;
949 LSN(pagep) = *lsnp;
950 modified = 1;
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;
955 modified = 1;
957 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
958 goto out;
960 *lsnp = argp->prev_lsn;
962 out: if (getmeta)
963 RELEASE_META(file_dbp, hashp);
964 REC_CLOSE;