~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to db/btree/bt_rec.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1996-2001
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
11
static const char revid[] = "$Id: bt_rec.c,v 11.43 2001/06/19 16:14:37 margo Exp $";
 
12
#endif /* not lint */
 
13
 
 
14
#ifndef NO_SYSTEM_INCLUDES
 
15
#include <sys/types.h>
 
16
 
 
17
#include <string.h>
 
18
#endif
 
19
 
 
20
#include "db_int.h"
 
21
#include "db_page.h"
 
22
#include "db_shash.h"
 
23
#include "hash.h"
 
24
#include "btree.h"
 
25
#include "lock.h"
 
26
#include "log.h"
 
27
 
 
28
#define IS_BTREE_PAGE(pagep)                                            \
 
29
        (TYPE(pagep) == P_IBTREE ||                                     \
 
30
         TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP)
 
31
 
 
32
/*
 
33
 * __bam_pg_alloc_recover --
 
34
 *      Recovery function for pg_alloc.
 
35
 *
 
36
 * PUBLIC: int __bam_pg_alloc_recover
 
37
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
38
 */
 
39
int
 
40
__bam_pg_alloc_recover(dbenv, dbtp, lsnp, op, info)
 
41
        DB_ENV *dbenv;
 
42
        DBT *dbtp;
 
43
        DB_LSN *lsnp;
 
44
        db_recops op;
 
45
        void *info;
 
46
{
 
47
        __bam_pg_alloc_args *argp;
 
48
        DB *file_dbp;
 
49
        DBC *dbc;
 
50
        DBMETA *meta;
 
51
        DB_MPOOLFILE *mpf;
 
52
        PAGE *pagep;
 
53
        db_pgno_t pgno;
 
54
        int cmp_n, cmp_p, created, level, modified, ret;
 
55
 
 
56
        REC_PRINT(__bam_pg_alloc_print);
 
57
        REC_INTRO(__bam_pg_alloc_read, 0);
 
58
 
 
59
        /*
 
60
         * Fix up the allocated page.  If we're redoing the operation, we have
 
61
         * to get the page (creating it if it doesn't exist), and update its
 
62
         * LSN.  If we're undoing the operation, we have to reset the page's
 
63
         * LSN and put it on the free list.
 
64
         *
 
65
         * Fix up the metadata page.  If we're redoing the operation, we have
 
66
         * to get the metadata page and update its LSN and its free pointer.
 
67
         * If we're undoing the operation and the page was ever created, we put
 
68
         * it on the freelist.
 
69
         */
 
70
        pgno = PGNO_BASE_MD;
 
71
        meta = NULL;
 
72
        if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) {
 
73
                /* The metadata page must always exist on redo. */
 
74
                if (DB_REDO(op)) {
 
75
                        (void)__db_pgerr(file_dbp, pgno);
 
76
                        goto out;
 
77
                } else
 
78
                        goto done;
 
79
        }
 
80
        created = modified = 0;
 
81
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
82
                /*
 
83
                 * We have to be able to identify if a page was newly
 
84
                 * created so we can recover it properly.  We cannot simply
 
85
                 * look for an empty header, because hash uses a pgin
 
86
                 * function that will set the header.  Instead, we explicitly
 
87
                 * try for the page without CREATE and if that fails, then
 
88
                 * create it.
 
89
                 */
 
90
                if ((ret = memp_fget(mpf,
 
91
                    &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
 
92
                        (void)__db_pgerr(file_dbp, argp->pgno);
 
93
                        goto err;
 
94
                }
 
95
                created = modified = 1;
 
96
        }
 
97
 
 
98
        /* Fix up the allocated page. */
 
99
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
100
        cmp_p = log_compare(&LSN(pagep), &argp->page_lsn);
 
101
 
 
102
        /*
 
103
         * If an inital allocation is aborted and then reallocated
 
104
         * during an archival restore the log record will have
 
105
         * an LSN for the page but the page will be empty.
 
106
         */
 
107
        if (IS_ZERO_LSN(LSN(pagep)))
 
108
                cmp_p = 0;
 
109
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->page_lsn);
 
110
        /*
 
111
         * If we we rolled back this allocation previously during an
 
112
         * archive restore, the page may have the LSN of the meta page
 
113
         * at the point of the roll back.  This will be no more
 
114
         * than the LSN of the metadata page at the time of this allocation.
 
115
         * Another special case we have to handle is if we ended up with a
 
116
         * page of all 0's which can happen if we abort between allocating a
 
117
         * page in mpool and initializing it.  In that case, even if we're
 
118
         * undoing, we need to re-initialize the page.
 
119
         */
 
120
        if (DB_REDO(op) &&
 
121
            (cmp_p == 0 ||
 
122
            (IS_ZERO_LSN(argp->page_lsn) &&
 
123
            log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) {
 
124
                /* Need to redo update described. */
 
125
                switch (argp->ptype) {
 
126
                case P_LBTREE:
 
127
                case P_LRECNO:
 
128
                case P_LDUP:
 
129
                        level = LEAFLEVEL;
 
130
                        break;
 
131
                default:
 
132
                        level = 0;
 
133
                        break;
 
134
                }
 
135
                P_INIT(pagep, file_dbp->pgsize,
 
136
                    argp->pgno, PGNO_INVALID, PGNO_INVALID, level, argp->ptype);
 
137
 
 
138
                pagep->lsn = *lsnp;
 
139
                modified = 1;
 
140
        } else if (DB_UNDO(op) && (cmp_n == 0 || created)) {
 
141
                /*
 
142
                 * This is where we handle the case of a 0'd page (pagep->pgno
 
143
                 * is equal to PGNO_INVALID).
 
144
                 * Undo the allocation, reinitialize the page and
 
145
                 * link its next pointer to the free list.
 
146
                 */
 
147
                P_INIT(pagep, file_dbp->pgsize,
 
148
                    argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
 
149
 
 
150
                pagep->lsn = argp->page_lsn;
 
151
                modified = 1;
 
152
        }
 
153
 
 
154
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
 
155
                goto err;
 
156
        }
 
157
 
 
158
        /*
 
159
         * If the page was newly created, put it on the limbo list.
 
160
         */
 
161
        if (IS_ZERO_LSN(LSN(pagep)) &&
 
162
             IS_ZERO_LSN(argp->page_lsn) && DB_UNDO(op)) {
 
163
                /* Put the page in limbo.*/
 
164
                if ((ret = __db_add_limbo(dbenv,
 
165
                    info, argp->fileid, argp->pgno, 1)) != 0)
 
166
                        goto err;
 
167
        }
 
168
 
 
169
        /* Fix up the metadata page. */
 
170
        modified = 0;
 
171
        cmp_n = log_compare(lsnp, &LSN(meta));
 
172
        cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
 
173
        CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
 
174
        if (cmp_p == 0 && DB_REDO(op)) {
 
175
                /* Need to redo update described. */
 
176
                LSN(meta) = *lsnp;
 
177
                meta->free = argp->next;
 
178
                modified = 1;
 
179
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
180
                /* Need to undo update described. */
 
181
                LSN(meta) = argp->meta_lsn;
 
182
 
 
183
                /*
 
184
                 * If the page has a zero LSN then its newly created
 
185
                 * and will go into limbo rather than directly on the
 
186
                 * free list.
 
187
                 */
 
188
                if (!IS_ZERO_LSN(argp->page_lsn))
 
189
                        meta->free = argp->pgno;
 
190
                modified = 1;
 
191
        }
 
192
        if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
193
                goto out;
 
194
        /*
 
195
         * This could be the metapage from a subdb which is read from disk
 
196
         * to recover its creation.
 
197
         */
 
198
        if (F_ISSET(file_dbp, DB_AM_SUBDB))
 
199
                switch (argp->type) {
 
200
                case P_BTREEMETA:
 
201
                case P_HASHMETA:
 
202
                case P_QAMMETA:
 
203
                        file_dbp->sync(file_dbp, 0);
 
204
                        break;
 
205
                }
 
206
 
 
207
done:   *lsnp = argp->prev_lsn;
 
208
        ret = 0;
 
209
 
 
210
        if (0) {
 
211
err:
 
212
                if (meta != NULL)
 
213
                        (void)memp_fput(mpf, meta, 0);
 
214
        }
 
215
out:    REC_CLOSE;
 
216
}
 
217
 
 
218
/*
 
219
 * __bam_pg_free_recover --
 
220
 *      Recovery function for pg_free.
 
221
 *
 
222
 * PUBLIC: int __bam_pg_free_recover
 
223
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
224
 */
 
225
int
 
226
__bam_pg_free_recover(dbenv, dbtp, lsnp, op, info)
 
227
        DB_ENV *dbenv;
 
228
        DBT *dbtp;
 
229
        DB_LSN *lsnp;
 
230
        db_recops op;
 
231
        void *info;
 
232
{
 
233
        __bam_pg_free_args *argp;
 
234
        DB *file_dbp;
 
235
        DBC *dbc;
 
236
        DBMETA *meta;
 
237
        DB_LSN copy_lsn;
 
238
        DB_MPOOLFILE *mpf;
 
239
        PAGE *pagep;
 
240
        db_pgno_t pgno;
 
241
        int cmp_n, cmp_p, modified, ret;
 
242
 
 
243
        COMPQUIET(info, NULL);
 
244
        REC_PRINT(__bam_pg_free_print);
 
245
        REC_INTRO(__bam_pg_free_read, 1);
 
246
 
 
247
        /*
 
248
         * Fix up the freed page.  If we're redoing the operation we get the
 
249
         * page and explicitly discard its contents, then update its LSN.  If
 
250
         * we're undoing the operation, we get the page and restore its header.
 
251
         * Create the page if necessary, we may be freeing an aborted
 
252
         * create.
 
253
         */
 
254
        if ((ret = memp_fget(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
 
255
                goto out;
 
256
        modified = 0;
 
257
        (void)__ua_memcpy(&copy_lsn, &LSN(argp->header.data), sizeof(DB_LSN));
 
258
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
259
        cmp_p = log_compare(&LSN(pagep), &copy_lsn);
 
260
        CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
 
261
        if (DB_REDO(op) &&
 
262
            (cmp_p == 0 ||
 
263
            (IS_ZERO_LSN(copy_lsn) &&
 
264
            log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) {
 
265
                /* Need to redo update described. */
 
266
                P_INIT(pagep, file_dbp->pgsize,
 
267
                    argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
 
268
                pagep->lsn = *lsnp;
 
269
 
 
270
                modified = 1;
 
271
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
272
                /* Need to undo update described. */
 
273
                memcpy(pagep, argp->header.data, argp->header.size);
 
274
 
 
275
                modified = 1;
 
276
        }
 
277
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
278
                goto out;
 
279
 
 
280
        /*
 
281
         * Fix up the metadata page.  If we're redoing or undoing the operation
 
282
         * we get the page and update its LSN and free pointer.
 
283
         */
 
284
        pgno = PGNO_BASE_MD;
 
285
        if ((ret = memp_fget(mpf, &pgno, 0, &meta)) != 0) {
 
286
                /* The metadata page must always exist. */
 
287
                (void)__db_pgerr(file_dbp, pgno);
 
288
                goto out;
 
289
        }
 
290
 
 
291
        modified = 0;
 
292
        cmp_n = log_compare(lsnp, &LSN(meta));
 
293
        cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
 
294
        CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
 
295
        if (cmp_p == 0 && DB_REDO(op)) {
 
296
                /* Need to redo the deallocation. */
 
297
                meta->free = argp->pgno;
 
298
                LSN(meta) = *lsnp;
 
299
                modified = 1;
 
300
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
301
                /* Need to undo the deallocation. */
 
302
                meta->free = argp->next;
 
303
                LSN(meta) = argp->meta_lsn;
 
304
                modified = 1;
 
305
        }
 
306
        if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
307
                goto out;
 
308
 
 
309
done:   *lsnp = argp->prev_lsn;
 
310
        ret = 0;
 
311
 
 
312
out:    REC_CLOSE;
 
313
}
 
314
 
 
315
/*
 
316
 * __bam_split_recover --
 
317
 *      Recovery function for split.
 
318
 *
 
319
 * PUBLIC: int __bam_split_recover
 
320
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
321
 */
 
322
int
 
323
__bam_split_recover(dbenv, dbtp, lsnp, op, info)
 
324
        DB_ENV *dbenv;
 
325
        DBT *dbtp;
 
326
        DB_LSN *lsnp;
 
327
        db_recops op;
 
328
        void *info;
 
329
{
 
330
        __bam_split_args *argp;
 
331
        DB *file_dbp;
 
332
        DBC *dbc;
 
333
        DB_MPOOLFILE *mpf;
 
334
        PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
 
335
        db_pgno_t pgno, root_pgno;
 
336
        u_int32_t ptype;
 
337
        int cmp, l_update, p_update, r_update, rc, ret, rootsplit, t_ret;
 
338
 
 
339
        COMPQUIET(info, NULL);
 
340
        REC_PRINT(__bam_split_print);
 
341
 
 
342
        mpf = NULL;
 
343
        _lp = lp = np = pp = _rp = rp = NULL;
 
344
        sp = NULL;
 
345
 
 
346
        REC_INTRO(__bam_split_read, 1);
 
347
 
 
348
        /*
 
349
         * There are two kinds of splits that we have to recover from.  The
 
350
         * first is a root-page split, where the root page is split from a
 
351
         * leaf page into an internal page and two new leaf pages are created.
 
352
         * The second is where a page is split into two pages, and a new key
 
353
         * is inserted into the parent page.
 
354
         *
 
355
         * DBTs are not aligned in log records, so we need to copy the page
 
356
         * so that we can access fields within it throughout this routine.
 
357
         * Although we could hardcode the unaligned copies in this routine,
 
358
         * we will be calling into regular btree functions with this page,
 
359
         * so it's got to be aligned.  Copying it into allocated memory is
 
360
         * the only way to guarantee this.
 
361
         */
 
362
        if ((ret = __os_malloc(dbenv, argp->pg.size, &sp)) != 0)
 
363
                goto out;
 
364
        memcpy(sp, argp->pg.data, argp->pg.size);
 
365
 
 
366
        pgno = PGNO(sp);
 
367
        root_pgno = argp->root_pgno;
 
368
        rootsplit = pgno == root_pgno;
 
369
        if (memp_fget(mpf, &argp->left, 0, &lp) != 0)
 
370
                lp = NULL;
 
371
        if (memp_fget(mpf, &argp->right, 0, &rp) != 0)
 
372
                rp = NULL;
 
373
 
 
374
        if (DB_REDO(op)) {
 
375
                l_update = r_update = p_update = 0;
 
376
                /*
 
377
                 * Decide if we need to resplit the page.
 
378
                 *
 
379
                 * If this is a root split, then the root has to exist, it's
 
380
                 * the page we're splitting and it gets modified.  If this is
 
381
                 * not a root split, then the left page has to exist, for the
 
382
                 * same reason.
 
383
                 */
 
384
                if (rootsplit) {
 
385
                        if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) {
 
386
                                (void)__db_pgerr(file_dbp, pgno);
 
387
                                pp = NULL;
 
388
                                goto out;
 
389
                        }
 
390
                        cmp = log_compare(&LSN(pp), &LSN(argp->pg.data));
 
391
                        CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data));
 
392
                        p_update = cmp  == 0;
 
393
                } else if (lp == NULL) {
 
394
                        (void)__db_pgerr(file_dbp, argp->left);
 
395
                        goto out;
 
396
                }
 
397
 
 
398
                if (lp != NULL) {
 
399
                        cmp = log_compare(&LSN(lp), &argp->llsn);
 
400
                        CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn);
 
401
                        if (cmp == 0)
 
402
                                l_update = 1;
 
403
                } else
 
404
                        l_update = 1;
 
405
 
 
406
                if (rp != NULL) {
 
407
                        cmp = log_compare(&LSN(rp), &argp->rlsn);
 
408
                        CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn);
 
409
                        if (cmp == 0)
 
410
                                r_update = 1;
 
411
                } else
 
412
                        r_update = 1;
 
413
                if (!p_update && !l_update && !r_update)
 
414
                        goto check_next;
 
415
 
 
416
                /* Allocate and initialize new left/right child pages. */
 
417
                if ((ret = __os_malloc(dbenv, file_dbp->pgsize, &_lp)) != 0 ||
 
418
                    (ret = __os_malloc(dbenv, file_dbp->pgsize, &_rp)) != 0)
 
419
                        goto out;
 
420
                if (rootsplit) {
 
421
                        P_INIT(_lp, file_dbp->pgsize, argp->left,
 
422
                            PGNO_INVALID,
 
423
                            ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
 
424
                            LEVEL(sp), TYPE(sp));
 
425
                        P_INIT(_rp, file_dbp->pgsize, argp->right,
 
426
                            ISINTERNAL(sp) ?  PGNO_INVALID : argp->left,
 
427
                            PGNO_INVALID, LEVEL(sp), TYPE(sp));
 
428
                } else {
 
429
                        P_INIT(_lp, file_dbp->pgsize, PGNO(sp),
 
430
                            ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp),
 
431
                            ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
 
432
                            LEVEL(sp), TYPE(sp));
 
433
                        P_INIT(_rp, file_dbp->pgsize, argp->right,
 
434
                            ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno,
 
435
                            ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp),
 
436
                            LEVEL(sp), TYPE(sp));
 
437
                }
 
438
 
 
439
                /* Split the page. */
 
440
                if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 ||
 
441
                    (ret = __bam_copy(file_dbp, sp, _rp, argp->indx,
 
442
                    NUM_ENT(sp))) != 0)
 
443
                        goto out;
 
444
 
 
445
                /* If the left child is wrong, update it. */
 
446
                if (lp == NULL && (ret =
 
447
                    memp_fget(mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) {
 
448
                        (void)__db_pgerr(file_dbp, argp->left);
 
449
                        lp = NULL;
 
450
                        goto out;
 
451
                }
 
452
                if (l_update) {
 
453
                        memcpy(lp, _lp, file_dbp->pgsize);
 
454
                        lp->lsn = *lsnp;
 
455
                        if ((ret = memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
 
456
                                goto out;
 
457
                        lp = NULL;
 
458
                }
 
459
 
 
460
                /* If the right child is wrong, update it. */
 
461
                if (rp == NULL && (ret = memp_fget(mpf,
 
462
                    &argp->right, DB_MPOOL_CREATE, &rp)) != 0) {
 
463
                        (void)__db_pgerr(file_dbp, argp->right);
 
464
                        rp = NULL;
 
465
                        goto out;
 
466
                }
 
467
                if (r_update) {
 
468
                        memcpy(rp, _rp, file_dbp->pgsize);
 
469
                        rp->lsn = *lsnp;
 
470
                        if ((ret = memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
 
471
                                goto out;
 
472
                        rp = NULL;
 
473
                }
 
474
 
 
475
                /*
 
476
                 * If the parent page is wrong, update it.  This is of interest
 
477
                 * only if it was a root split, since root splits create parent
 
478
                 * pages.  All other splits modify a parent page, but those are
 
479
                 * separately logged and recovered.
 
480
                 */
 
481
                if (rootsplit && p_update) {
 
482
                        if (IS_BTREE_PAGE(sp)) {
 
483
                                ptype = P_IBTREE;
 
484
                                rc = argp->opflags & SPL_NRECS ? 1 : 0;
 
485
                        } else {
 
486
                                ptype = P_IRECNO;
 
487
                                rc = 1;
 
488
                        }
 
489
 
 
490
                        P_INIT(pp, file_dbp->pgsize, root_pgno,
 
491
                            PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype);
 
492
                        RE_NREC_SET(pp,
 
493
                            rc ? __bam_total(_lp) + __bam_total(_rp) : 0);
 
494
 
 
495
                        pp->lsn = *lsnp;
 
496
                        if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
 
497
                                goto out;
 
498
                        pp = NULL;
 
499
                }
 
500
 
 
501
check_next:     /*
 
502
                 * Finally, redo the next-page link if necessary.  This is of
 
503
                 * interest only if it wasn't a root split -- inserting a new
 
504
                 * page in the tree requires that any following page have its
 
505
                 * previous-page pointer updated to our new page.  The next
 
506
                 * page must exist because we're redoing the operation.
 
507
                 */
 
508
                if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
 
509
                        if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
 
510
                                (void)__db_pgerr(file_dbp, argp->npgno);
 
511
                                np = NULL;
 
512
                                goto out;
 
513
                        }
 
514
                        cmp = log_compare(&LSN(np), &argp->nlsn);
 
515
                        CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn);
 
516
                        if (cmp == 0) {
 
517
                                PREV_PGNO(np) = argp->right;
 
518
                                np->lsn = *lsnp;
 
519
                                if ((ret =
 
520
                                    memp_fput(mpf, np, DB_MPOOL_DIRTY)) != 0)
 
521
                                        goto out;
 
522
                                np = NULL;
 
523
                        }
 
524
                }
 
525
        } else {
 
526
                /*
 
527
                 * If the split page is wrong, replace its contents with the
 
528
                 * logged page contents.  If the page doesn't exist, it means
 
529
                 * that the create of the page never happened, nor did any of
 
530
                 * the adds onto the page that caused the split, and there's
 
531
                 * really no undo-ing to be done.
 
532
                 */
 
533
                if ((ret = memp_fget(mpf, &pgno, 0, &pp)) != 0) {
 
534
                        pp = NULL;
 
535
                        goto lrundo;
 
536
                }
 
537
                if (log_compare(lsnp, &LSN(pp)) == 0) {
 
538
                        memcpy(pp, argp->pg.data, argp->pg.size);
 
539
                        if ((ret = memp_fput(mpf, pp, DB_MPOOL_DIRTY)) != 0)
 
540
                                goto out;
 
541
                        pp = NULL;
 
542
                }
 
543
 
 
544
                /*
 
545
                 * If it's a root split and the left child ever existed, update
 
546
                 * its LSN.  (If it's not a root split, we've updated the left
 
547
                 * page already -- it's the same as the split page.) If the
 
548
                 * right child ever existed, root split or not, update its LSN.
 
549
                 * The undo of the page allocation(s) will restore them to the
 
550
                 * free list.
 
551
                 */
 
552
lrundo:         if ((rootsplit && lp != NULL) || rp != NULL) {
 
553
                        if (rootsplit && lp != NULL &&
 
554
                            log_compare(lsnp, &LSN(lp)) == 0) {
 
555
                                lp->lsn = argp->llsn;
 
556
                                if ((ret =
 
557
                                    memp_fput(mpf, lp, DB_MPOOL_DIRTY)) != 0)
 
558
                                        goto out;
 
559
                                lp = NULL;
 
560
                        }
 
561
                        if (rp != NULL &&
 
562
                            log_compare(lsnp, &LSN(rp)) == 0) {
 
563
                                rp->lsn = argp->rlsn;
 
564
                                if ((ret =
 
565
                                    memp_fput(mpf, rp, DB_MPOOL_DIRTY)) != 0)
 
566
                                        goto out;
 
567
                                rp = NULL;
 
568
                        }
 
569
                }
 
570
 
 
571
                /*
 
572
                 * Finally, undo the next-page link if necessary.  This is of
 
573
                 * interest only if it wasn't a root split -- inserting a new
 
574
                 * page in the tree requires that any following page have its
 
575
                 * previous-page pointer updated to our new page.  Since it's
 
576
                 * possible that the next-page never existed, we ignore it as
 
577
                 * if there's nothing to undo.
 
578
                 */
 
579
                if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
 
580
                        if ((ret = memp_fget(mpf, &argp->npgno, 0, &np)) != 0) {
 
581
                                np = NULL;
 
582
                                goto done;
 
583
                        }
 
584
                        if (log_compare(lsnp, &LSN(np)) == 0) {
 
585
                                PREV_PGNO(np) = argp->left;
 
586
                                np->lsn = argp->nlsn;
 
587
                                if (memp_fput(mpf, np, DB_MPOOL_DIRTY))
 
588
                                        goto out;
 
589
                                np = NULL;
 
590
                        }
 
591
                }
 
592
        }
 
593
 
 
594
done:   *lsnp = argp->prev_lsn;
 
595
        ret = 0;
 
596
 
 
597
out:    /* Free any pages that weren't dirtied. */
 
598
        if (pp != NULL && (t_ret = memp_fput(mpf, pp, 0)) != 0 && ret == 0)
 
599
                ret = t_ret;
 
600
        if (lp != NULL && (t_ret = memp_fput(mpf, lp, 0)) != 0 && ret == 0)
 
601
                ret = t_ret;
 
602
        if (np != NULL && (t_ret = memp_fput(mpf, np, 0)) != 0 && ret == 0)
 
603
                ret = t_ret;
 
604
        if (rp != NULL && (t_ret = memp_fput(mpf, rp, 0)) != 0 && ret == 0)
 
605
                ret = t_ret;
 
606
 
 
607
        /* Free any allocated space. */
 
608
        if (_lp != NULL)
 
609
                __os_free(dbenv, _lp, file_dbp->pgsize);
 
610
        if (_rp != NULL)
 
611
                __os_free(dbenv, _rp, file_dbp->pgsize);
 
612
        if (sp != NULL)
 
613
                __os_free(dbenv, sp, argp->pg.size);
 
614
 
 
615
        REC_CLOSE;
 
616
}
 
617
 
 
618
/*
 
619
 * __bam_rsplit_recover --
 
620
 *      Recovery function for a reverse split.
 
621
 *
 
622
 * PUBLIC: int __bam_rsplit_recover
 
623
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
624
 */
 
625
int
 
626
__bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
 
627
        DB_ENV *dbenv;
 
628
        DBT *dbtp;
 
629
        DB_LSN *lsnp;
 
630
        db_recops op;
 
631
        void *info;
 
632
{
 
633
        __bam_rsplit_args *argp;
 
634
        DB *file_dbp;
 
635
        DBC *dbc;
 
636
        DB_LSN copy_lsn;
 
637
        DB_MPOOLFILE *mpf;
 
638
        PAGE *pagep;
 
639
        db_pgno_t pgno, root_pgno;
 
640
        int cmp_n, cmp_p, modified, ret;
 
641
 
 
642
        COMPQUIET(info, NULL);
 
643
        REC_PRINT(__bam_rsplit_print);
 
644
        REC_INTRO(__bam_rsplit_read, 1);
 
645
 
 
646
        /* Fix the root page. */
 
647
        pgno = root_pgno = argp->root_pgno;
 
648
        if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) != 0) {
 
649
                /* The root page must always exist if we are going forward. */
 
650
                if (DB_REDO(op)) {
 
651
                        (void)__db_pgerr(file_dbp, pgno);
 
652
                        goto out;
 
653
                }
 
654
                /* This must be the root of an OPD tree. */
 
655
                DB_ASSERT(root_pgno !=
 
656
                    ((BTREE *)file_dbp->bt_internal)->bt_root);
 
657
                ret = 0;
 
658
                goto done;
 
659
        }
 
660
        modified = 0;
 
661
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
662
        cmp_p = log_compare(&LSN(pagep), &argp->rootlsn);
 
663
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->rootlsn);
 
664
        if (cmp_p == 0 && DB_REDO(op)) {
 
665
                /* Need to redo update described. */
 
666
                memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
 
667
                pagep->pgno = root_pgno;
 
668
                pagep->lsn = *lsnp;
 
669
                modified = 1;
 
670
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
671
                /* Need to undo update described. */
 
672
                P_INIT(pagep, file_dbp->pgsize, root_pgno,
 
673
                    argp->nrec, PGNO_INVALID, pagep->level + 1,
 
674
                    IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO);
 
675
                if ((ret = __db_pitem(dbc, pagep, 0,
 
676
                    argp->rootent.size, &argp->rootent, NULL)) != 0)
 
677
                        goto out;
 
678
                pagep->lsn = argp->rootlsn;
 
679
                modified = 1;
 
680
        }
 
681
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
682
                goto out;
 
683
 
 
684
        /*
 
685
         * Fix the page copied over the root page.  It's possible that the
 
686
         * page never made it to disk, so if we're undo-ing and the page
 
687
         * doesn't exist, it's okay and there's nothing further to do.
 
688
         */
 
689
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
690
                if (DB_UNDO(op))
 
691
                        goto done;
 
692
                (void)__db_pgerr(file_dbp, argp->pgno);
 
693
                goto out;
 
694
        }
 
695
        modified = 0;
 
696
        (void)__ua_memcpy(&copy_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
 
697
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
698
        cmp_p = log_compare(&LSN(pagep), &copy_lsn);
 
699
        CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
 
700
        if (cmp_p == 0 && DB_REDO(op)) {
 
701
                /* Need to redo update described. */
 
702
                pagep->lsn = *lsnp;
 
703
                modified = 1;
 
704
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
705
                /* Need to undo update described. */
 
706
                memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
 
707
                modified = 1;
 
708
        }
 
709
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
710
                goto out;
 
711
 
 
712
done:   *lsnp = argp->prev_lsn;
 
713
        ret = 0;
 
714
 
 
715
out:    REC_CLOSE;
 
716
}
 
717
 
 
718
/*
 
719
 * __bam_adj_recover --
 
720
 *      Recovery function for adj.
 
721
 *
 
722
 * PUBLIC: int __bam_adj_recover
 
723
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
724
 */
 
725
int
 
726
__bam_adj_recover(dbenv, dbtp, lsnp, op, info)
 
727
        DB_ENV *dbenv;
 
728
        DBT *dbtp;
 
729
        DB_LSN *lsnp;
 
730
        db_recops op;
 
731
        void *info;
 
732
{
 
733
        __bam_adj_args *argp;
 
734
        DB *file_dbp;
 
735
        DBC *dbc;
 
736
        DB_MPOOLFILE *mpf;
 
737
        PAGE *pagep;
 
738
        int cmp_n, cmp_p, modified, ret;
 
739
 
 
740
        COMPQUIET(info, NULL);
 
741
        REC_PRINT(__bam_adj_print);
 
742
        REC_INTRO(__bam_adj_read, 1);
 
743
 
 
744
        /* Get the page; if it never existed and we're undoing, we're done. */
 
745
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
746
                if (DB_UNDO(op))
 
747
                        goto done;
 
748
                (void)__db_pgerr(file_dbp, argp->pgno);
 
749
                goto out;
 
750
        }
 
751
 
 
752
        modified = 0;
 
753
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
754
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
 
755
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
 
756
        if (cmp_p == 0 && DB_REDO(op)) {
 
757
                /* Need to redo update described. */
 
758
                if ((ret = __bam_adjindx(dbc,
 
759
                    pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
 
760
                        goto err;
 
761
 
 
762
                LSN(pagep) = *lsnp;
 
763
                modified = 1;
 
764
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
765
                /* Need to undo update described. */
 
766
                if ((ret = __bam_adjindx(dbc,
 
767
                    pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
 
768
                        goto err;
 
769
 
 
770
                LSN(pagep) = argp->lsn;
 
771
                modified = 1;
 
772
        }
 
773
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
774
                goto out;
 
775
 
 
776
done:   *lsnp = argp->prev_lsn;
 
777
        ret = 0;
 
778
 
 
779
        if (0) {
 
780
err:            (void)memp_fput(mpf, pagep, 0);
 
781
        }
 
782
out:    REC_CLOSE;
 
783
}
 
784
 
 
785
/*
 
786
 * __bam_cadjust_recover --
 
787
 *      Recovery function for the adjust of a count change in an internal
 
788
 *      page.
 
789
 *
 
790
 * PUBLIC: int __bam_cadjust_recover
 
791
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
792
 */
 
793
int
 
794
__bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
 
795
        DB_ENV *dbenv;
 
796
        DBT *dbtp;
 
797
        DB_LSN *lsnp;
 
798
        db_recops op;
 
799
        void *info;
 
800
{
 
801
        __bam_cadjust_args *argp;
 
802
        DB *file_dbp;
 
803
        DBC *dbc;
 
804
        DB_MPOOLFILE *mpf;
 
805
        PAGE *pagep;
 
806
        int cmp_n, cmp_p, modified, ret;
 
807
 
 
808
        COMPQUIET(info, NULL);
 
809
        REC_PRINT(__bam_cadjust_print);
 
810
        REC_INTRO(__bam_cadjust_read, 1);
 
811
 
 
812
        /* Get the page; if it never existed and we're undoing, we're done. */
 
813
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
814
                if (DB_UNDO(op))
 
815
                        goto done;
 
816
                (void)__db_pgerr(file_dbp, argp->pgno);
 
817
                goto out;
 
818
        }
 
819
 
 
820
        modified = 0;
 
821
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
822
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
 
823
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
 
824
        if (cmp_p == 0 && DB_REDO(op)) {
 
825
                /* Need to redo update described. */
 
826
                if (IS_BTREE_PAGE(pagep)) {
 
827
                        GET_BINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
 
828
                        if (argp->opflags & CAD_UPDATEROOT)
 
829
                                RE_NREC_ADJ(pagep, argp->adjust);
 
830
                } else {
 
831
                        GET_RINTERNAL(pagep, argp->indx)->nrecs += argp->adjust;
 
832
                        if (argp->opflags & CAD_UPDATEROOT)
 
833
                                RE_NREC_ADJ(pagep, argp->adjust);
 
834
                }
 
835
 
 
836
                LSN(pagep) = *lsnp;
 
837
                modified = 1;
 
838
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
839
                /* Need to undo update described. */
 
840
                if (IS_BTREE_PAGE(pagep)) {
 
841
                        GET_BINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
 
842
                        if (argp->opflags & CAD_UPDATEROOT)
 
843
                                RE_NREC_ADJ(pagep, -(argp->adjust));
 
844
                } else {
 
845
                        GET_RINTERNAL(pagep, argp->indx)->nrecs -= argp->adjust;
 
846
                        if (argp->opflags & CAD_UPDATEROOT)
 
847
                                RE_NREC_ADJ(pagep, -(argp->adjust));
 
848
                }
 
849
                LSN(pagep) = argp->lsn;
 
850
                modified = 1;
 
851
        }
 
852
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
853
                goto out;
 
854
 
 
855
done:   *lsnp = argp->prev_lsn;
 
856
        ret = 0;
 
857
 
 
858
out:    REC_CLOSE;
 
859
}
 
860
 
 
861
/*
 
862
 * __bam_cdel_recover --
 
863
 *      Recovery function for the intent-to-delete of a cursor record.
 
864
 *
 
865
 * PUBLIC: int __bam_cdel_recover
 
866
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
867
 */
 
868
int
 
869
__bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
 
870
        DB_ENV *dbenv;
 
871
        DBT *dbtp;
 
872
        DB_LSN *lsnp;
 
873
        db_recops op;
 
874
        void *info;
 
875
{
 
876
        __bam_cdel_args *argp;
 
877
        DB *file_dbp;
 
878
        DBC *dbc;
 
879
        DB_MPOOLFILE *mpf;
 
880
        PAGE *pagep;
 
881
        u_int32_t indx;
 
882
        int cmp_n, cmp_p, modified, ret;
 
883
 
 
884
        COMPQUIET(info, NULL);
 
885
        REC_PRINT(__bam_cdel_print);
 
886
        REC_INTRO(__bam_cdel_read, 1);
 
887
 
 
888
        /* Get the page; if it never existed and we're undoing, we're done. */
 
889
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
890
                if (DB_UNDO(op))
 
891
                        goto done;
 
892
                (void)__db_pgerr(file_dbp, argp->pgno);
 
893
                goto out;
 
894
        }
 
895
 
 
896
        modified = 0;
 
897
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
898
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
 
899
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
 
900
        if (cmp_p == 0 && DB_REDO(op)) {
 
901
                /* Need to redo update described. */
 
902
                indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
 
903
                B_DSET(GET_BKEYDATA(pagep, indx)->type);
 
904
 
 
905
                LSN(pagep) = *lsnp;
 
906
                modified = 1;
 
907
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
908
                /* Need to undo update described. */
 
909
                indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
 
910
                B_DCLR(GET_BKEYDATA(pagep, indx)->type);
 
911
 
 
912
                (void)__bam_ca_delete(file_dbp, argp->pgno, argp->indx, 0);
 
913
 
 
914
                LSN(pagep) = argp->lsn;
 
915
                modified = 1;
 
916
        }
 
917
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
918
                goto out;
 
919
 
 
920
done:   *lsnp = argp->prev_lsn;
 
921
        ret = 0;
 
922
 
 
923
out:    REC_CLOSE;
 
924
}
 
925
 
 
926
/*
 
927
 * __bam_repl_recover --
 
928
 *      Recovery function for page item replacement.
 
929
 *
 
930
 * PUBLIC: int __bam_repl_recover
 
931
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
932
 */
 
933
int
 
934
__bam_repl_recover(dbenv, dbtp, lsnp, op, info)
 
935
        DB_ENV *dbenv;
 
936
        DBT *dbtp;
 
937
        DB_LSN *lsnp;
 
938
        db_recops op;
 
939
        void *info;
 
940
{
 
941
        __bam_repl_args *argp;
 
942
        BKEYDATA *bk;
 
943
        DB *file_dbp;
 
944
        DBC *dbc;
 
945
        DBT dbt;
 
946
        DB_MPOOLFILE *mpf;
 
947
        PAGE *pagep;
 
948
        int cmp_n, cmp_p, modified, ret;
 
949
        u_int8_t *p;
 
950
 
 
951
        COMPQUIET(info, NULL);
 
952
        REC_PRINT(__bam_repl_print);
 
953
        REC_INTRO(__bam_repl_read, 1);
 
954
 
 
955
        /* Get the page; if it never existed and we're undoing, we're done. */
 
956
        if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
 
957
                if (DB_UNDO(op))
 
958
                        goto done;
 
959
                (void)__db_pgerr(file_dbp, argp->pgno);
 
960
                goto out;
 
961
        }
 
962
        bk = GET_BKEYDATA(pagep, argp->indx);
 
963
 
 
964
        modified = 0;
 
965
        cmp_n = log_compare(lsnp, &LSN(pagep));
 
966
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
 
967
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
 
968
        if (cmp_p == 0 && DB_REDO(op)) {
 
969
                /*
 
970
                 * Need to redo update described.
 
971
                 *
 
972
                 * Re-build the replacement item.
 
973
                 */
 
974
                memset(&dbt, 0, sizeof(dbt));
 
975
                dbt.size = argp->prefix + argp->suffix + argp->repl.size;
 
976
                if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
 
977
                        goto err;
 
978
                p = dbt.data;
 
979
                memcpy(p, bk->data, argp->prefix);
 
980
                p += argp->prefix;
 
981
                memcpy(p, argp->repl.data, argp->repl.size);
 
982
                p += argp->repl.size;
 
983
                memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
 
984
 
 
985
                ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
 
986
                __os_free(dbenv, dbt.data, dbt.size);
 
987
                if (ret != 0)
 
988
                        goto err;
 
989
 
 
990
                LSN(pagep) = *lsnp;
 
991
                modified = 1;
 
992
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
993
                /*
 
994
                 * Need to undo update described.
 
995
                 *
 
996
                 * Re-build the original item.
 
997
                 */
 
998
                memset(&dbt, 0, sizeof(dbt));
 
999
                dbt.size = argp->prefix + argp->suffix + argp->orig.size;
 
1000
                if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
 
1001
                        goto err;
 
1002
                p = dbt.data;
 
1003
                memcpy(p, bk->data, argp->prefix);
 
1004
                p += argp->prefix;
 
1005
                memcpy(p, argp->orig.data, argp->orig.size);
 
1006
                p += argp->orig.size;
 
1007
                memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
 
1008
 
 
1009
                ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
 
1010
                __os_free(dbenv, dbt.data, dbt.size);
 
1011
                if (ret != 0)
 
1012
                        goto err;
 
1013
 
 
1014
                /* Reset the deleted flag, if necessary. */
 
1015
                if (argp->isdeleted)
 
1016
                        B_DSET(GET_BKEYDATA(pagep, argp->indx)->type);
 
1017
 
 
1018
                LSN(pagep) = argp->lsn;
 
1019
                modified = 1;
 
1020
        }
 
1021
        if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
1022
                goto out;
 
1023
 
 
1024
done:   *lsnp = argp->prev_lsn;
 
1025
        ret = 0;
 
1026
 
 
1027
        if (0) {
 
1028
err:            (void)memp_fput(mpf, pagep, 0);
 
1029
        }
 
1030
out:    REC_CLOSE;
 
1031
}
 
1032
 
 
1033
/*
 
1034
 * __bam_root_recover --
 
1035
 *      Recovery function for setting the root page on the meta-data page.
 
1036
 *
 
1037
 * PUBLIC: int __bam_root_recover
 
1038
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
1039
 */
 
1040
int
 
1041
__bam_root_recover(dbenv, dbtp, lsnp, op, info)
 
1042
        DB_ENV *dbenv;
 
1043
        DBT *dbtp;
 
1044
        DB_LSN *lsnp;
 
1045
        db_recops op;
 
1046
        void *info;
 
1047
{
 
1048
        __bam_root_args *argp;
 
1049
        BTMETA *meta;
 
1050
        DB *file_dbp;
 
1051
        DBC *dbc;
 
1052
        DB_MPOOLFILE *mpf;
 
1053
        int cmp_n, cmp_p, modified, ret;
 
1054
 
 
1055
        COMPQUIET(info, NULL);
 
1056
        REC_PRINT(__bam_root_print);
 
1057
        REC_INTRO(__bam_root_read, 0);
 
1058
 
 
1059
        if ((ret = memp_fget(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
 
1060
                /* The metadata page must always exist on redo. */
 
1061
                if (DB_REDO(op)) {
 
1062
                        (void)__db_pgerr(file_dbp, argp->meta_pgno);
 
1063
                        goto out;
 
1064
                } else
 
1065
                        goto done;
 
1066
        }
 
1067
 
 
1068
        modified = 0;
 
1069
        cmp_n = log_compare(lsnp, &LSN(meta));
 
1070
        cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
 
1071
        CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
 
1072
        if (cmp_p == 0 && DB_REDO(op)) {
 
1073
                /* Need to redo update described. */
 
1074
                meta->root = argp->root_pgno;
 
1075
                meta->dbmeta.lsn = *lsnp;
 
1076
                ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root;
 
1077
                modified = 1;
 
1078
        } else if (cmp_n == 0 && DB_UNDO(op)) {
 
1079
                /* Nothing to undo except lsn. */
 
1080
                meta->dbmeta.lsn = argp->meta_lsn;
 
1081
                modified = 1;
 
1082
        }
 
1083
        if ((ret = memp_fput(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
 
1084
                goto out;
 
1085
 
 
1086
done:   *lsnp = argp->prev_lsn;
 
1087
        ret = 0;
 
1088
 
 
1089
out:    REC_CLOSE;
 
1090
}
 
1091
 
 
1092
/*
 
1093
 * __bam_curadj_recover --
 
1094
 *      Transaction abort function to undo cursor adjustments.
 
1095
 *      This should only be triggered by subtransaction aborts.
 
1096
 *
 
1097
 * PUBLIC: int __bam_curadj_recover
 
1098
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
1099
 */
 
1100
int
 
1101
__bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
 
1102
        DB_ENV *dbenv;
 
1103
        DBT *dbtp;
 
1104
        DB_LSN *lsnp;
 
1105
        db_recops op;
 
1106
        void *info;
 
1107
{
 
1108
        __bam_curadj_args *argp;
 
1109
        DB *file_dbp;
 
1110
        DBC *dbc;
 
1111
        DB_MPOOLFILE *mpf;
 
1112
        int ret;
 
1113
 
 
1114
        COMPQUIET(info, NULL);
 
1115
 
 
1116
        REC_PRINT(__bam_curadj_print);
 
1117
        REC_INTRO(__bam_curadj_read, 0);
 
1118
 
 
1119
        ret = 0;
 
1120
        if (op != DB_TXN_ABORT)
 
1121
                goto done;
 
1122
 
 
1123
        switch(argp->mode) {
 
1124
        case DB_CA_DI:
 
1125
                if ((ret = __bam_ca_di(dbc, argp->from_pgno,
 
1126
                    argp->from_indx, -(int)argp->first_indx)) != 0)
 
1127
                        goto out;
 
1128
                break;
 
1129
        case DB_CA_DUP:
 
1130
                if ((ret = __bam_ca_undodup(file_dbp, argp->first_indx,
 
1131
                     argp->from_pgno, argp->from_indx, argp->to_indx)) != 0)
 
1132
                        goto out;
 
1133
                break;
 
1134
 
 
1135
        case DB_CA_RSPLIT:
 
1136
                if ((ret =
 
1137
                    __bam_ca_rsplit(dbc, argp->to_pgno, argp->from_pgno)) != 0)
 
1138
                        goto out;
 
1139
                break;
 
1140
 
 
1141
        case DB_CA_SPLIT:
 
1142
                __bam_ca_undosplit(file_dbp, argp->from_pgno,
 
1143
                    argp->to_pgno, argp->left_pgno, argp->from_indx);
 
1144
                break;
 
1145
        }
 
1146
 
 
1147
done:   *lsnp = argp->prev_lsn;
 
1148
out:    REC_CLOSE;
 
1149
}
 
1150
 
 
1151
/*
 
1152
 * __bam_rcuradj_recover --
 
1153
 *      Transaction abort function to undo cursor adjustments in rrecno.
 
1154
 *      This should only be triggered by subtransaction aborts.
 
1155
 *
 
1156
 * PUBLIC: int __bam_rcuradj_recover
 
1157
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
 
1158
 */
 
1159
int
 
1160
__bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
 
1161
        DB_ENV *dbenv;
 
1162
        DBT *dbtp;
 
1163
        DB_LSN *lsnp;
 
1164
        db_recops op;
 
1165
        void *info;
 
1166
{
 
1167
        __bam_rcuradj_args *argp;
 
1168
        BTREE_CURSOR *cp;
 
1169
        DB *file_dbp;
 
1170
        DBC *dbc, *rdbc;
 
1171
        DB_MPOOLFILE *mpf;
 
1172
        int ret, t_ret;
 
1173
 
 
1174
        COMPQUIET(info, NULL);
 
1175
        rdbc = NULL;
 
1176
 
 
1177
        REC_PRINT(__bam_rcuradj_print);
 
1178
        REC_INTRO(__bam_rcuradj_read, 0);
 
1179
 
 
1180
        ret = t_ret = 0;
 
1181
 
 
1182
        if (op != DB_TXN_ABORT)
 
1183
                goto done;
 
1184
 
 
1185
        /*
 
1186
         * We don't know whether we're in an offpage dup set, and
 
1187
         * thus don't know whether the dbc REC_INTRO has handed us is
 
1188
         * of a reasonable type.  It's certainly unset, so if this is
 
1189
         * an offpage dup set, we don't have an OPD cursor.  The
 
1190
         * simplest solution is just to allocate a whole new cursor
 
1191
         * for our use;  we're only really using it to hold pass some
 
1192
         * state into __ram_ca, and this way we don't need to make
 
1193
         * this function know anything about how offpage dups work.
 
1194
         */
 
1195
        if ((ret =
 
1196
            __db_icursor(file_dbp,
 
1197
                NULL, DB_RECNO, argp->root, 0, DB_LOCK_INVALIDID, &rdbc)) != 0)
 
1198
                goto out;
 
1199
 
 
1200
        cp = (BTREE_CURSOR *)rdbc->internal;
 
1201
        F_SET(cp, C_RENUMBER);
 
1202
        cp->recno = argp->recno;
 
1203
 
 
1204
        switch(argp->mode) {
 
1205
        case CA_DELETE:
 
1206
                /*
 
1207
                 * The way to undo a delete is with an insert.  Since
 
1208
                 * we're undoing it, the delete flag must be set.
 
1209
                 */
 
1210
                F_SET(cp, C_DELETED);
 
1211
                F_SET(cp, C_RENUMBER);  /* Just in case. */
 
1212
                cp->order = argp->order;
 
1213
                __ram_ca(rdbc, CA_ICURRENT);
 
1214
                break;
 
1215
        case CA_IAFTER:
 
1216
        case CA_IBEFORE:
 
1217
        case CA_ICURRENT:
 
1218
                /*
 
1219
                 * The way to undo an insert is with a delete.  The delete
 
1220
                 * flag is unset to start with.
 
1221
                 */
 
1222
                F_CLR(cp, C_DELETED);
 
1223
                cp->order = INVALID_ORDER;
 
1224
                __ram_ca(rdbc, CA_DELETE);
 
1225
                break;
 
1226
        }
 
1227
 
 
1228
done:   *lsnp = argp->prev_lsn;
 
1229
out:    if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0)
 
1230
                ret = t_ret;
 
1231
        REC_CLOSE;
 
1232
}