fe33825ec46546666d8c62b63c63fbb49109d1cd
[kopensolaris-gnu/glibc.git] / db2 / btree / bt_rec.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997, 1998
5  *      Sleepycat Software.  All rights reserved.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)bt_rec.c      10.21 (Sleepycat) 4/28/98";
12 #endif /* not lint */
13
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16
17 #include <errno.h>
18 #include <string.h>
19 #endif
20
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"
28
29 /*
30  * __bam_pg_alloc_recover --
31  *      Recovery function for pg_alloc.
32  *
33  * PUBLIC: int __bam_pg_alloc_recover
34  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
35  */
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;
43 {
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;
51
52         REC_PRINT(__bam_pg_alloc_print);
53         REC_INTRO(__bam_pg_alloc_read);
54
55         /*
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.
60          *
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.
65          */
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;
71         }
72         if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
73                 /*
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.
78                  */
79                 (void)__db_pgerr(file_dbp, argp->pgno);
80                 (void)memp_fput(mpf, meta, 0);
81                 goto out;
82         }
83
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);
92
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);
99
100                 pagep->lsn = argp->page_lsn;
101                 modified = 1;
102         }
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;
107         }
108
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;
123         }
124         if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
125                 (void)__db_panic(file_dbp);
126                 goto out;
127         }
128
129         *lsnp = argp->prev_lsn;
130         ret = 0;
131
132 out:    REC_CLOSE;
133 }
134
135 /*
136  * __bam_pg_free_recover --
137  *      Recovery function for pg_free.
138  *
139  * PUBLIC: int __bam_pg_free_recover
140  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
141  */
142 int
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;
149 {
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;
157
158         REC_PRINT(__bam_pg_free_print);
159         REC_INTRO(__bam_pg_free_read);
160
161         /*
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.
165          */
166         if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
167                 /*
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.
173                  */
174                 if (!redo)
175                         goto done;
176                 (void)__db_pgerr(file_dbp, argp->pgno);
177                 goto out;
178         }
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;
187
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);
192
193                 modified = 1;
194         }
195         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
196                 (void)__db_panic(file_dbp);
197                 goto out;
198         }
199
200         /*
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.
203          */
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;
209         }
210
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;
217
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;
223
224                 meta->lsn = argp->meta_lsn;
225                 modified = 1;
226         }
227         if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
228                 (void)__db_panic(file_dbp);
229                 goto out;
230         }
231
232 done:   *lsnp = argp->prev_lsn;
233         ret = 0;
234
235 out:    REC_CLOSE;
236 }
237
238 /*
239  * __bam_split_recover --
240  *      Recovery function for split.
241  *
242  * PUBLIC: int __bam_split_recover
243  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
244  */
245 int
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;
252 {
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;
259
260         REC_PRINT(__bam_split_print);
261
262         mpf = NULL;
263         _lp = lp = np = pp = _rp = rp = NULL;
264
265         REC_INTRO(__bam_split_read);
266
267         /*
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.
273          */
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;
281
282         if (redo) {
283                 l_update = r_update = p_update = 0;
284                 /*
285                  * Decide if we need to resplit the page.
286                  *
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.
291                  */
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;
297                         }
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;
304                         }
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;
311
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;
318                 }
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));
336                 }
337
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;
343
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;
350                 }
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;
357                 }
358
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;
365                 }
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;
372                 }
373
374                 /*
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.
379                  */
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;
397                 }
398
399                 /*
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.
405                  */
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;
411                         }
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;
419                         }
420                 }
421         } else {
422                 /*
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.
428                  */
429                 if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) {
430                         pp = NULL;
431                         goto lrundo;
432                 }
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;
438                 }
439
440                 /*
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.
447                  */
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;
456                         }
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;
464                         }
465                 }
466
467                 /*
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.
474                  */
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;
479                         }
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;
486                         }
487                 }
488         }
489
490 done:   *lsnp = argp->prev_lsn;
491         ret = 0;
492
493         if (0) {
494 fatal:          (void)__db_panic(file_dbp);
495         }
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;
505
506         /* Free any allocated space. */
507         if (_lp != NULL)
508                 __db_free(_lp);
509         if (_rp != NULL)
510                 __db_free(_rp);
511
512         REC_CLOSE;
513 }
514
515 /*
516  * __bam_rsplit_recover --
517  *      Recovery function for a reverse split.
518  *
519  * PUBLIC: int __bam_rsplit_recover
520  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
521  */
522 int
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;
529 {
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;
536
537         REC_PRINT(__bam_rsplit_print);
538         REC_INTRO(__bam_rsplit_read);
539
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;
546         }
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;
566         }
567         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
568                 (void)__db_panic(file_dbp);
569                 goto out;
570         }
571
572         /*
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.
576          */
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;
582         }
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;
594         }
595         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
596                 (void)__db_panic(file_dbp);
597                 goto out;
598         }
599
600 done:   *lsnp = argp->prev_lsn;
601         ret = 0;
602
603 out:    REC_CLOSE;
604 }
605
606 /*
607  * __bam_adj_recover --
608  *      Recovery function for adj.
609  *
610  * PUBLIC: int __bam_adj_recover
611  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
612  */
613 int
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;
620 {
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;
626
627         REC_PRINT(__bam_adj_print);
628         REC_INTRO(__bam_adj_read);
629
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;
636         }
637
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;
646
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;
654
655                 LSN(pagep) = argp->lsn;
656                 modified = 1;
657         }
658         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
659                 goto out;
660
661 done:   *lsnp = argp->prev_lsn;
662         ret = 0;
663
664         if (0) {
665 err:            (void)memp_fput(mpf, pagep, 0);
666         }
667 out:    REC_CLOSE;
668 }
669
670 /*
671  * __bam_cadjust_recover --
672  *      Recovery function for the adjust of a count change in an internal
673  *      page.
674  *
675  * PUBLIC: int __bam_cadjust_recover
676  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
677  */
678 int
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;
685 {
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;
691
692         REC_PRINT(__bam_cadjust_print);
693         REC_INTRO(__bam_cadjust_read);
694
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;
701         }
702
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);
713                 }
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);
718                 }
719
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);
729                 }
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));
734                 }
735                 LSN(pagep) = argp->lsn;
736                 modified = 1;
737         }
738         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
739                 goto out;
740
741 done:   *lsnp = argp->prev_lsn;
742         ret = 0;
743
744 out:    REC_CLOSE;
745 }
746
747 /*
748  * __bam_cdel_recover --
749  *      Recovery function for the intent-to-delete of a cursor record.
750  *
751  * PUBLIC: int __bam_cdel_recover
752  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
753  */
754 int
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;
761 {
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;
767
768         REC_PRINT(__bam_cdel_print);
769         REC_INTRO(__bam_cdel_read);
770
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;
777         }
778
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);
785
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);
791
792                 LSN(pagep) = argp->lsn;
793                 modified = 1;
794         }
795         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
796                 goto out;
797
798 done:   *lsnp = argp->prev_lsn;
799         ret = 0;
800
801 out:    REC_CLOSE;
802 }
803
804 /*
805  * __bam_repl_recover --
806  *      Recovery function for page item replacement.
807  *
808  * PUBLIC: int __bam_repl_recover
809  * PUBLIC:   __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
810  */
811 int
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;
818 {
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;
827
828         REC_PRINT(__bam_repl_print);
829         REC_INTRO(__bam_repl_read);
830
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;
837         }
838         bk = GET_BKEYDATA(pagep, argp->indx);
839
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) {
844                 /*
845                  * Need to redo update described.
846                  *
847                  * Re-build the replacement item.
848                  */
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;
854                 }
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);
861
862                 ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
863                 __db_free(dbt.data);
864                 if (ret != 0)
865                         goto err;
866
867                 LSN(pagep) = *lsnp;
868                 modified = 1;
869         } else if (cmp_n == 0 && !redo) {
870                 /*
871                  * Need to undo update described.
872                  *
873                  * Re-build the original item.
874                  */
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;
880                 }
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);
887
888                 ret = __bam_ritem(file_dbp, pagep, argp->indx, &dbt);
889                 __db_free(dbt.data);
890                 if (ret != 0)
891                         goto err;
892
893                 /* Reset the deleted flag, if necessary. */
894                 if (argp->isdeleted)
895                         B_DSET(GET_BKEYDATA(pagep, argp->indx)->type);
896
897                 LSN(pagep) = argp->lsn;
898                 modified = 1;
899         }
900         if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
901                 goto out;
902
903 done:   *lsnp = argp->prev_lsn;
904         ret = 0;
905
906         if (0) {
907 err:            (void)memp_fput(mpf, pagep, 0);
908         }
909 out:    REC_CLOSE;
910 }