Update.
[glibc.git] / db2 / btree / bt_rec.c
blobfe33825ec46546666d8c62b63c63fbb49109d1cd
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)bt_rec.c 10.21 (Sleepycat) 4/28/98";
12 #endif /* not lint */
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
17 #include <errno.h>
18 #include <string.h>
19 #endif
21 #include "db_int.h"
22 #include "db_page.h"
23 #include "shqueue.h"
24 #include "hash.h"
25 #include "btree.h"
26 #include "log.h"
27 #include "common_ext.h"
30 * __bam_pg_alloc_recover --
31 * Recovery function for pg_alloc.
33 * PUBLIC: int __bam_pg_alloc_recover
34 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
36 int
37 __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
38 DB_LOG *logp;
39 DBT *dbtp;
40 DB_LSN *lsnp;
41 int redo;
42 void *info;
44 __bam_pg_alloc_args *argp;
45 BTMETA *meta;
46 DB_MPOOLFILE *mpf;
47 PAGE *pagep;
48 DB *file_dbp, *mdbp;
49 db_pgno_t pgno;
50 int cmp_n, cmp_p, modified, ret;
52 REC_PRINT(__bam_pg_alloc_print);
53 REC_INTRO(__bam_pg_alloc_read);
56 * Fix up the allocated page. If we're redoing the operation, we have
57 * to get the page (creating it if it doesn't exist), and update its
58 * LSN. If we're undoing the operation, we have to reset the page's
59 * LSN and put it on the free list.
61 * Fix up the metadata page. If we're redoing the operation, we have
62 * to get the metadata page and update its LSN and its free pointer.
63 * If we're undoing the operation and the page was ever created, we put
64 * it on the freelist.
66 pgno = PGNO_METADATA;
67 if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) {
68 /* The metadata page must always exist. */
69 (void)__db_pgerr(file_dbp, pgno);
70 goto out;
72 if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
74 * We specify creation and check for it later, because this
75 * operation was supposed to create the page, and even in
76 * the undo case it's going to get linked onto the freelist
77 * which we're also fixing up.
79 (void)__db_pgerr(file_dbp, argp->pgno);
80 (void)memp_fput(mpf, meta, 0);
81 goto out;
84 /* Fix up the allocated page. */
85 modified = 0;
86 cmp_n = log_compare(lsnp, &LSN(pagep));
87 cmp_p = log_compare(&LSN(pagep), &argp->page_lsn);
88 if (cmp_p == 0 && redo) {
89 /* Need to redo update described. */
90 P_INIT(pagep, file_dbp->pgsize,
91 argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, argp->ptype);
93 pagep->lsn = *lsnp;
94 modified = 1;
95 } else if (cmp_n == 0 && !redo) {
96 /* Need to undo update described. */
97 P_INIT(pagep, file_dbp->pgsize,
98 argp->pgno, PGNO_INVALID, meta->free, 0, P_INVALID);
100 pagep->lsn = argp->page_lsn;
101 modified = 1;
103 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
104 (void)__db_panic(file_dbp);
105 (void)memp_fput(mpf, meta, 0);
106 goto out;
109 /* Fix up the metadata page. */
110 modified = 0;
111 cmp_n = log_compare(lsnp, &LSN(meta));
112 cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
113 if (cmp_p == 0 && redo) {
114 /* Need to redo update described. */
115 meta->lsn = *lsnp;
116 meta->free = argp->next;
117 modified = 1;
118 } else if (cmp_n == 0 && !redo) {
119 /* Need to undo update described. */
120 meta->lsn = argp->meta_lsn;
121 meta->free = argp->pgno;
122 modified = 1;
124 if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
125 (void)__db_panic(file_dbp);
126 goto out;
129 *lsnp = argp->prev_lsn;
130 ret = 0;
132 out: REC_CLOSE;
136 * __bam_pg_free_recover --
137 * Recovery function for pg_free.
139 * PUBLIC: int __bam_pg_free_recover
140 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
143 __bam_pg_free_recover(logp, dbtp, lsnp, redo, info)
144 DB_LOG *logp;
145 DBT *dbtp;
146 DB_LSN *lsnp;
147 int redo;
148 void *info;
150 __bam_pg_free_args *argp;
151 BTMETA *meta;
152 DB *file_dbp, *mdbp;
153 DB_MPOOLFILE *mpf;
154 PAGE *pagep;
155 db_pgno_t pgno;
156 int cmp_n, cmp_p, modified, ret;
158 REC_PRINT(__bam_pg_free_print);
159 REC_INTRO(__bam_pg_free_read);
162 * Fix up the freed page. If we're redoing the operation we get the
163 * page and explicitly discard its contents, then update its LSN. If
164 * we're undoing the operation, we get the page and restore its header.
166 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
168 * We don't automatically create the page. The only way the
169 * page might not exist is if the alloc never happened, and
170 * the only way the alloc might never have happened is if we
171 * are undoing, in which case there's no reason to create the
172 * page.
174 if (!redo)
175 goto done;
176 (void)__db_pgerr(file_dbp, argp->pgno);
177 goto out;
179 modified = 0;
180 cmp_n = log_compare(lsnp, &LSN(pagep));
181 cmp_p = log_compare(&LSN(pagep), &LSN(argp->header.data));
182 if (cmp_p == 0 && redo) {
183 /* Need to redo update described. */
184 P_INIT(pagep, file_dbp->pgsize,
185 pagep->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
186 pagep->lsn = *lsnp;
188 modified = 1;
189 } else if (cmp_n == 0 && !redo) {
190 /* Need to undo update described. */
191 memcpy(pagep, argp->header.data, argp->header.size);
193 modified = 1;
195 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
196 (void)__db_panic(file_dbp);
197 goto out;
201 * Fix up the metadata page. If we're redoing or undoing the operation
202 * we get the page and update its LSN and free pointer.
204 pgno = PGNO_METADATA;
205 if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) {
206 /* The metadata page must always exist. */
207 (void)__db_pgerr(file_dbp, pgno);
208 goto out;
211 modified = 0;
212 cmp_n = log_compare(lsnp, &LSN(meta));
213 cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
214 if (cmp_p == 0 && redo) {
215 /* Need to redo update described. */
216 meta->free = argp->pgno;
218 meta->lsn = *lsnp;
219 modified = 1;
220 } else if (cmp_n == 0 && !redo) {
221 /* Need to undo update described. */
222 meta->free = argp->next;
224 meta->lsn = argp->meta_lsn;
225 modified = 1;
227 if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
228 (void)__db_panic(file_dbp);
229 goto out;
232 done: *lsnp = argp->prev_lsn;
233 ret = 0;
235 out: REC_CLOSE;
239 * __bam_split_recover --
240 * Recovery function for split.
242 * PUBLIC: int __bam_split_recover
243 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
246 __bam_split_recover(logp, dbtp, lsnp, redo, info)
247 DB_LOG *logp;
248 DBT *dbtp;
249 DB_LSN *lsnp;
250 int redo;
251 void *info;
253 __bam_split_args *argp;
254 DB *file_dbp, *mdbp;
255 DB_MPOOLFILE *mpf;
256 PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
257 db_pgno_t pgno;
258 int l_update, p_update, r_update, ret, rootsplit, t_ret;
260 REC_PRINT(__bam_split_print);
262 mpf = NULL;
263 _lp = lp = np = pp = _rp = rp = NULL;
265 REC_INTRO(__bam_split_read);
268 * There are two kinds of splits that we have to recover from. The
269 * first is a root-page split, where the root page is split from a
270 * leaf page into an internal page and two new leaf pages are created.
271 * The second is where a page is split into two pages, and a new key
272 * is inserted into the parent page.
274 sp = argp->pg.data;
275 pgno = PGNO(sp);
276 rootsplit = pgno == PGNO_ROOT;
277 if (memp_fget(mpf, &argp->left, 0, &lp) != 0)
278 lp = NULL;
279 if (memp_fget(mpf, &argp->right, 0, &rp) != 0)
280 rp = NULL;
282 if (redo) {
283 l_update = r_update = p_update = 0;
285 * Decide if we need to resplit the page.
287 * If this is a root split, then the root has to exist, it's
288 * the page we're splitting and it gets modified. If this is
289 * not a root split, then the left page has to exist, for the
290 * same reason.
292 if (rootsplit) {
293 if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) {
294 (void)__db_pgerr(file_dbp, pgno);
295 pp = NULL;
296 goto out;
298 p_update =
299 log_compare(&LSN(pp), &LSN(argp->pg.data)) == 0;
300 } else
301 if (lp == NULL) {
302 (void)__db_pgerr(file_dbp, argp->left);
303 goto out;
305 if (lp == NULL || log_compare(&LSN(lp), &argp->llsn) == 0)
306 l_update = 1;
307 if (rp == NULL || log_compare(&LSN(rp), &argp->rlsn) == 0)
308 r_update = 1;
309 if (!p_update && !l_update && !r_update)
310 goto done;
312 /* Allocate and initialize new left/right child pages. */
313 if ((_lp = (PAGE *)__db_malloc(file_dbp->pgsize)) == NULL ||
314 (_rp = (PAGE *)__db_malloc(file_dbp->pgsize)) == NULL) {
315 ret = ENOMEM;
316 __db_err(file_dbp->dbenv, "%s", strerror(ret));
317 goto out;
319 if (rootsplit) {
320 P_INIT(_lp, file_dbp->pgsize, argp->left,
321 PGNO_INVALID,
322 ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
323 LEVEL(sp), TYPE(sp));
324 P_INIT(_rp, file_dbp->pgsize, argp->right,
325 ISINTERNAL(sp) ? PGNO_INVALID : argp->left,
326 PGNO_INVALID, LEVEL(sp), TYPE(sp));
327 } else {
328 P_INIT(_lp, file_dbp->pgsize, PGNO(sp),
329 ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp),
330 ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
331 LEVEL(sp), TYPE(sp));
332 P_INIT(_rp, file_dbp->pgsize, argp->right,
333 ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno,
334 ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp),
335 LEVEL(sp), TYPE(sp));
338 /* Split the page. */
339 if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 ||
340 (ret = __bam_copy(file_dbp, sp, _rp, argp->indx,
341 NUM_ENT(sp))) != 0)
342 goto out;
344 /* If the left child is wrong, update it. */
345 if (lp == NULL && (ret =
346 memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) {
347 (void)__db_pgerr(file_dbp, argp->left);
348 lp = NULL;
349 goto out;
351 if (l_update) {
352 memcpy(lp, _lp, file_dbp->pgsize);
353 lp->lsn = *lsnp;
354 if ((ret = memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
355 goto fatal;
356 lp = NULL;
359 /* If the right child is wrong, update it. */
360 if (rp == NULL && (ret = memp_fget(mpf,
361 &argp->right, DB_MPOOL_CREATE, &rp)) != 0) {
362 (void)__db_pgerr(file_dbp, argp->right);
363 rp = NULL;
364 goto out;
366 if (r_update) {
367 memcpy(rp, _rp, file_dbp->pgsize);
368 rp->lsn = *lsnp;
369 if ((ret = memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
370 goto fatal;
371 rp = NULL;
375 * If the parent page is wrong, update it. This is of interest
376 * only if it was a root split, since root splits create parent
377 * pages. All other splits modify a parent page, but those are
378 * separately logged and recovered.
380 if (rootsplit && p_update) {
381 if (file_dbp->type == DB_BTREE)
382 P_INIT(pp, file_dbp->pgsize,
383 PGNO_ROOT, PGNO_INVALID, PGNO_INVALID,
384 _lp->level + 1, P_IBTREE);
385 else
386 P_INIT(pp, file_dbp->pgsize,
387 PGNO_ROOT, PGNO_INVALID, PGNO_INVALID,
388 _lp->level + 1, P_IRECNO);
389 RE_NREC_SET(pp,
390 file_dbp->type == DB_RECNO ||
391 F_ISSET(file_dbp, DB_BT_RECNUM) ?
392 __bam_total(_lp) + __bam_total(_rp) : 0);
393 pp->lsn = *lsnp;
394 if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
395 goto fatal;
396 pp = NULL;
400 * Finally, redo the next-page link if necessary. This is of
401 * interest only if it wasn't a root split -- inserting a new
402 * page in the tree requires that any following page have its
403 * previous-page pointer updated to our new page. The next
404 * page must exist because we're redoing the operation.
406 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
407 if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
408 (void)__db_pgerr(file_dbp, argp->npgno);
409 np = NULL;
410 goto out;
412 if (log_compare(&LSN(np), &argp->nlsn) == 0) {
413 PREV_PGNO(np) = argp->right;
414 np->lsn = *lsnp;
415 if ((ret = memp_fput(mpf,
416 np, DB_MPOOL_DIRTY)) != 0)
417 goto fatal;
418 np = NULL;
421 } else {
423 * If the split page is wrong, replace its contents with the
424 * logged page contents. If the page doesn't exist, it means
425 * that the create of the page never happened, nor did any of
426 * the adds onto the page that caused the split, and there's
427 * really no undo-ing to be done.
429 if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) {
430 pp = NULL;
431 goto lrundo;
433 if (log_compare(lsnp, &LSN(pp)) == 0) {
434 memcpy(pp, argp->pg.data, argp->pg.size);
435 if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
436 goto fatal;
437 pp = NULL;
441 * If it's a root split and the left child ever existed, update
442 * its LSN. (If it's not a root split, we've updated the left
443 * page already -- it's the same as the split page.) If the
444 * right child ever existed, root split or not, update its LSN.
445 * The undo of the page allocation(s) will restore them to the
446 * free list.
448 lrundo: if ((rootsplit && lp != NULL) || rp != NULL) {
449 if (rootsplit && lp != NULL &&
450 log_compare(lsnp, &LSN(lp)) == 0) {
451 lp->lsn = argp->llsn;
452 if ((ret =
453 memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
454 goto fatal;
455 lp = NULL;
457 if (rp != NULL &&
458 log_compare(lsnp, &LSN(rp)) == 0) {
459 rp->lsn = argp->rlsn;
460 if ((ret =
461 memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
462 goto fatal;
463 rp = NULL;
468 * Finally, undo the next-page link if necessary. This is of
469 * interest only if it wasn't a root split -- inserting a new
470 * page in the tree requires that any following page have its
471 * previous-page pointer updated to our new page. Since it's
472 * possible that the next-page never existed, we ignore it as
473 * if there's nothing to undo.
475 if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
476 if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
477 np = NULL;
478 goto done;
480 if (log_compare(lsnp, &LSN(np)) == 0) {
481 PREV_PGNO(np) = argp->left;
482 np->lsn = argp->nlsn;
483 if (memp_fput(mpf, np, DB_MPOOL_DIRTY))
484 goto fatal;
485 np = NULL;
490 done: *lsnp = argp->prev_lsn;
491 ret = 0;
493 if (0) {
494 fatal: (void)__db_panic(file_dbp);
496 out: /* Free any pages that weren't dirtied. */
497 if (pp != NULL && (t_ret = memp_fput(mpf, pp, 0)) != 0 && ret == 0)
498 ret = t_ret;
499 if (lp != NULL && (t_ret = memp_fput(mpf, lp, 0)) != 0 && ret == 0)
500 ret = t_ret;
501 if (np != NULL && (t_ret = memp_fput(mpf, np, 0)) != 0 && ret == 0)
502 ret = t_ret;
503 if (rp != NULL && (t_ret = memp_fput(mpf, rp, 0)) != 0 && ret == 0)
504 ret = t_ret;
506 /* Free any allocated space. */
507 if (_lp != NULL)
508 __db_free(_lp);
509 if (_rp != NULL)
510 __db_free(_rp);
512 REC_CLOSE;
516 * __bam_rsplit_recover --
517 * Recovery function for a reverse split.
519 * PUBLIC: int __bam_rsplit_recover
520 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
523 __bam_rsplit_recover(logp, dbtp, lsnp, redo, info)
524 DB_LOG *logp;
525 DBT *dbtp;
526 DB_LSN *lsnp;
527 int redo;
528 void *info;
530 __bam_rsplit_args *argp;
531 DB *file_dbp, *mdbp;
532 DB_MPOOLFILE *mpf;
533 PAGE *pagep;
534 db_pgno_t pgno;
535 int cmp_n, cmp_p, modified, ret;
537 REC_PRINT(__bam_rsplit_print);
538 REC_INTRO(__bam_rsplit_read);
540 /* Fix the root page. */
541 pgno = PGNO_ROOT;
542 if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
543 /* The root page must always exist. */
544 __db_pgerr(file_dbp, pgno);
545 goto out;
547 modified = 0;
548 cmp_n = log_compare(lsnp, &LSN(pagep));
549 cmp_p = log_compare(&LSN(pagep), &argp->rootlsn);
550 if (cmp_p == 0 && redo) {
551 /* Need to redo update described. */
552 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
553 pagep->pgno = PGNO_ROOT;
554 pagep->lsn = *lsnp;
555 modified = 1;
556 } else if (cmp_n == 0 && !redo) {
557 /* Need to undo update described. */
558 P_INIT(pagep, file_dbp->pgsize, PGNO_ROOT,
559 argp->nrec, PGNO_INVALID, pagep->level + 1,
560 file_dbp->type == DB_BTREE ? P_IBTREE : P_IRECNO);
561 if ((ret = __db_pitem(file_dbp, pagep, 0,
562 argp->rootent.size, &argp->rootent, NULL)) != 0)
563 goto out;
564 pagep->lsn = argp->rootlsn;
565 modified = 1;
567 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
568 (void)__db_panic(file_dbp);
569 goto out;
573 * Fix the page copied over the root page. It's possible that the
574 * page never made it to disk, so if we're undo-ing and the page
575 * doesn't exist, it's okay and there's nothing further to do.
577 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
578 if (!redo)
579 goto done;
580 (void)__db_pgerr(file_dbp, argp->pgno);
581 goto out;
583 modified = 0;
584 cmp_n = log_compare(lsnp, &LSN(pagep));
585 cmp_p = log_compare(&LSN(pagep), &LSN(argp->pgdbt.data));
586 if (cmp_p == 0 && redo) {
587 /* Need to redo update described. */
588 pagep->lsn = *lsnp;
589 modified = 1;
590 } else if (cmp_n == 0 && !redo) {
591 /* Need to undo update described. */
592 memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
593 modified = 1;
595 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
596 (void)__db_panic(file_dbp);
597 goto out;
600 done: *lsnp = argp->prev_lsn;
601 ret = 0;
603 out: REC_CLOSE;
607 * __bam_adj_recover --
608 * Recovery function for adj.
610 * PUBLIC: int __bam_adj_recover
611 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
614 __bam_adj_recover(logp, dbtp, lsnp, redo, info)
615 DB_LOG *logp;
616 DBT *dbtp;
617 DB_LSN *lsnp;
618 int redo;
619 void *info;
621 __bam_adj_args *argp;
622 DB *file_dbp, *mdbp;
623 DB_MPOOLFILE *mpf;
624 PAGE *pagep;
625 int cmp_n, cmp_p, modified, ret;
627 REC_PRINT(__bam_adj_print);
628 REC_INTRO(__bam_adj_read);
630 /* Get the page; if it never existed and we're undoing, we're done. */
631 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
632 if (!redo)
633 goto done;
634 (void)__db_pgerr(file_dbp, argp->pgno);
635 goto out;
638 modified = 0;
639 cmp_n = log_compare(lsnp, &LSN(pagep));
640 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
641 if (cmp_p == 0 && redo) {
642 /* Need to redo update described. */
643 if ((ret = __bam_adjindx(file_dbp,
644 pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
645 goto err;
647 LSN(pagep) = *lsnp;
648 modified = 1;
649 } else if (cmp_n == 0 && !redo) {
650 /* Need to undo update described. */
651 if ((ret = __bam_adjindx(file_dbp,
652 pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
653 goto err;
655 LSN(pagep) = argp->lsn;
656 modified = 1;
658 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
659 goto out;
661 done: *lsnp = argp->prev_lsn;
662 ret = 0;
664 if (0) {
665 err: (void)memp_fput(mpf, pagep, 0);
667 out: REC_CLOSE;
671 * __bam_cadjust_recover --
672 * Recovery function for the adjust of a count change in an internal
673 * page.
675 * PUBLIC: int __bam_cadjust_recover
676 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
679 __bam_cadjust_recover(logp, dbtp, lsnp, redo, info)
680 DB_LOG *logp;
681 DBT *dbtp;
682 DB_LSN *lsnp;
683 int redo;
684 void *info;
686 __bam_cadjust_args *argp;
687 DB *file_dbp, *mdbp;
688 DB_MPOOLFILE *mpf;
689 PAGE *pagep;
690 int cmp_n, cmp_p, modified, ret;
692 REC_PRINT(__bam_cadjust_print);
693 REC_INTRO(__bam_cadjust_read);
695 /* Get the page; if it never existed and we're undoing, we're done. */
696 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
697 if (!redo)
698 goto done;
699 (void)__db_pgerr(file_dbp, argp->pgno);
700 goto out;
703 modified = 0;
704 cmp_n = log_compare(lsnp, &LSN(pagep));
705 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
706 if (cmp_p == 0 && redo) {
707 /* Need to redo update described. */
708 if (file_dbp->type == DB_BTREE &&
709 F_ISSET(file_dbp, DB_BT_RECNUM)) {
710 GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
711 if (argp->total && PGNO(pagep) == PGNO_ROOT)
712 RE_NREC_ADJ(pagep, argp->adjust);
714 if (file_dbp->type == DB_RECNO) {
715 GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
716 if (argp->total && PGNO(pagep) == PGNO_ROOT)
717 RE_NREC_ADJ(pagep, argp->adjust);
720 LSN(pagep) = *lsnp;
721 modified = 1;
722 } else if (cmp_n == 0 && !redo) {
723 /* Need to undo update described. */
724 if (file_dbp->type == DB_BTREE &&
725 F_ISSET(file_dbp, DB_BT_RECNUM)) {
726 GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
727 if (argp->total && PGNO(pagep) == PGNO_ROOT)
728 RE_NREC_ADJ(pagep, argp->adjust);
730 if (file_dbp->type == DB_RECNO) {
731 GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
732 if (argp->total && PGNO(pagep) == PGNO_ROOT)
733 RE_NREC_ADJ(pagep, -(argp->adjust));
735 LSN(pagep) = argp->lsn;
736 modified = 1;
738 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
739 goto out;
741 done: *lsnp = argp->prev_lsn;
742 ret = 0;
744 out: REC_CLOSE;
748 * __bam_cdel_recover --
749 * Recovery function for the intent-to-delete of a cursor record.
751 * PUBLIC: int __bam_cdel_recover
752 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
755 __bam_cdel_recover(logp, dbtp, lsnp, redo, info)
756 DB_LOG *logp;
757 DBT *dbtp;
758 DB_LSN *lsnp;
759 int redo;
760 void *info;
762 __bam_cdel_args *argp;
763 DB *file_dbp, *mdbp;
764 DB_MPOOLFILE *mpf;
765 PAGE *pagep;
766 int cmp_n, cmp_p, modified, ret;
768 REC_PRINT(__bam_cdel_print);
769 REC_INTRO(__bam_cdel_read);
771 /* Get the page; if it never existed and we're undoing, we're done. */
772 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
773 if (!redo)
774 goto done;
775 (void)__db_pgerr(file_dbp, argp->pgno);
776 goto out;
779 modified = 0;
780 cmp_n = log_compare(lsnp, &LSN(pagep));
781 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
782 if (cmp_p == 0 && redo) {
783 /* Need to redo update described. */
784 B_DSET(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
786 LSN(pagep) = *lsnp;
787 modified = 1;
788 } else if (cmp_n == 0 && !redo) {
789 /* Need to undo update described. */
790 B_DCLR(GET_BKEYDATA(pagep, argp->indx + O_INDX)->type);
792 LSN(pagep) = argp->lsn;
793 modified = 1;
795 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
796 goto out;
798 done: *lsnp = argp->prev_lsn;
799 ret = 0;
801 out: REC_CLOSE;
805 * __bam_repl_recover --
806 * Recovery function for page item replacement.
808 * PUBLIC: int __bam_repl_recover
809 * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
812 __bam_repl_recover(logp, dbtp, lsnp, redo, info)
813 DB_LOG *logp;
814 DBT *dbtp;
815 DB_LSN *lsnp;
816 int redo;
817 void *info;
819 __bam_repl_args *argp;
820 BKEYDATA *bk;
821 DB *file_dbp, *mdbp;
822 DBT dbt;
823 DB_MPOOLFILE *mpf;
824 PAGE *pagep;
825 int cmp_n, cmp_p, modified, ret;
826 u_int8_t *p;
828 REC_PRINT(__bam_repl_print);
829 REC_INTRO(__bam_repl_read);
831 /* Get the page; if it never existed and we're undoing, we're done. */
832 if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
833 if (!redo)
834 goto done;
835 (void)__db_pgerr(file_dbp, argp->pgno);
836 goto out;
838 bk = GET_BKEYDATA(pagep, argp->indx);
840 modified = 0;
841 cmp_n = log_compare(lsnp, &LSN(pagep));
842 cmp_p = log_compare(&LSN(pagep), &argp->lsn);
843 if (cmp_p == 0 && redo) {
845 * Need to redo update described.
847 * Re-build the replacement item.
849 memset(&dbt, 0, sizeof(dbt));
850 dbt.size = argp->prefix + argp->suffix + argp->repl.size;
851 if ((dbt.data = __db_malloc(dbt.size)) == NULL) {
852 ret = ENOMEM;
853 goto err;
855 p = dbt.data;
856 memcpy(p, bk->data, argp->prefix);
857 p += argp->prefix;
858 memcpy(p, argp->repl.data, argp->repl.size);
859 p += argp->repl.size;
860 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
862 ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
863 __db_free(dbt.data);
864 if (ret != 0)
865 goto err;
867 LSN(pagep) = *lsnp;
868 modified = 1;
869 } else if (cmp_n == 0 && !redo) {
871 * Need to undo update described.
873 * Re-build the original item.
875 memset(&dbt, 0, sizeof(dbt));
876 dbt.size = argp->prefix + argp->suffix + argp->orig.size;
877 if ((dbt.data = __db_malloc(dbt.size)) == NULL) {
878 ret = ENOMEM;
879 goto err;
881 p = dbt.data;
882 memcpy(p, bk->data, argp->prefix);
883 p += argp->prefix;
884 memcpy(p, argp->orig.data, argp->orig.size);
885 p += argp->orig.size;
886 memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
888 ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
889 __db_free(dbt.data);
890 if (ret != 0)
891 goto err;
893 /* Reset the deleted flag, if necessary. */
894 if (argp->isdeleted)
895 B_DSET(GET_BKEYDATA(pagep, argp->indx)->type);
897 LSN(pagep) = argp->lsn;
898 modified = 1;
900 if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
901 goto out;
903 done: *lsnp = argp->prev_lsn;
904 ret = 0;
906 if (0) {
907 err: (void)memp_fput(mpf, pagep, 0);
909 out: REC_CLOSE;