~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/btree/bt_rec.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

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-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
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 "dbinc/db_page.h"
22
 
#include "dbinc/db_shash.h"
23
 
#include "dbinc/btree.h"
24
 
#include "dbinc/lock.h"
25
 
#include "dbinc/log.h"
26
 
 
27
 
#define IS_BTREE_PAGE(pagep)                                            \
28
 
        (TYPE(pagep) == P_IBTREE ||                                     \
29
 
         TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP)
30
 
 
31
 
/*
32
 
 * __bam_split_recover --
33
 
 *      Recovery function for split.
34
 
 *
35
 
 * PUBLIC: int __bam_split_recover
36
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
37
 
 */
38
 
int
39
 
__bam_split_recover(dbenv, dbtp, lsnp, op, info)
40
 
        DB_ENV *dbenv;
41
 
        DBT *dbtp;
42
 
        DB_LSN *lsnp;
43
 
        db_recops op;
44
 
        void *info;
45
 
{
46
 
        __bam_split_args *argp;
47
 
        DB *file_dbp;
48
 
        DBC *dbc;
49
 
        DB_MPOOLFILE *mpf;
50
 
        PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
51
 
        db_pgno_t pgno, root_pgno;
52
 
        u_int32_t ptype;
53
 
        int cmp, l_update, p_update, r_update, rc, ret, ret_l, rootsplit, t_ret;
54
 
 
55
 
        COMPQUIET(info, NULL);
56
 
        REC_PRINT(__bam_split_print);
57
 
 
58
 
        mpf = NULL;
59
 
        _lp = lp = np = pp = _rp = rp = NULL;
60
 
        sp = NULL;
61
 
 
62
 
        REC_INTRO(__bam_split_read, 1);
63
 
 
64
 
        /*
65
 
         * There are two kinds of splits that we have to recover from.  The
66
 
         * first is a root-page split, where the root page is split from a
67
 
         * leaf page into an internal page and two new leaf pages are created.
68
 
         * The second is where a page is split into two pages, and a new key
69
 
         * is inserted into the parent page.
70
 
         *
71
 
         * DBTs are not aligned in log records, so we need to copy the page
72
 
         * so that we can access fields within it throughout this routine.
73
 
         * Although we could hardcode the unaligned copies in this routine,
74
 
         * we will be calling into regular btree functions with this page,
75
 
         * so it's got to be aligned.  Copying it into allocated memory is
76
 
         * the only way to guarantee this.
77
 
         */
78
 
        if ((ret = __os_malloc(dbenv, argp->pg.size, &sp)) != 0)
79
 
                goto out;
80
 
        memcpy(sp, argp->pg.data, argp->pg.size);
81
 
 
82
 
        pgno = PGNO(sp);
83
 
        root_pgno = argp->root_pgno;
84
 
        rootsplit = root_pgno != PGNO_INVALID;
85
 
        if ((ret_l = mpf->get(mpf, &argp->left, 0, &lp)) != 0)
86
 
                lp = NULL;
87
 
        if (mpf->get(mpf, &argp->right, 0, &rp) != 0)
88
 
                rp = NULL;
89
 
 
90
 
        if (DB_REDO(op)) {
91
 
                l_update = r_update = p_update = 0;
92
 
                /*
93
 
                 * Decide if we need to resplit the page.
94
 
                 *
95
 
                 * If this is a root split, then the root has to exist, it's
96
 
                 * the page we're splitting and it gets modified.  If this is
97
 
                 * not a root split, then the left page has to exist, for the
98
 
                 * same reason.
99
 
                 */
100
 
                if (rootsplit) {
101
 
                        if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
102
 
                                __db_pgerr(file_dbp, pgno, ret);
103
 
                                pp = NULL;
104
 
                                goto out;
105
 
                        }
106
 
                        cmp = log_compare(&LSN(pp), &LSN(argp->pg.data));
107
 
                        CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data));
108
 
                        p_update = cmp  == 0;
109
 
                } else if (lp == NULL) {
110
 
                        __db_pgerr(file_dbp, argp->left, ret_l);
111
 
                        goto out;
112
 
                }
113
 
 
114
 
                if (lp != NULL) {
115
 
                        cmp = log_compare(&LSN(lp), &argp->llsn);
116
 
                        CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn);
117
 
                        if (cmp == 0)
118
 
                                l_update = 1;
119
 
                } else
120
 
                        l_update = 1;
121
 
 
122
 
                if (rp != NULL) {
123
 
                        cmp = log_compare(&LSN(rp), &argp->rlsn);
124
 
                        CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn);
125
 
                        if (cmp == 0)
126
 
                                r_update = 1;
127
 
                } else
128
 
                        r_update = 1;
129
 
                if (!p_update && !l_update && !r_update)
130
 
                        goto check_next;
131
 
 
132
 
                /* Allocate and initialize new left/right child pages. */
133
 
                if ((ret = __os_malloc(dbenv, file_dbp->pgsize, &_lp)) != 0 ||
134
 
                    (ret = __os_malloc(dbenv, file_dbp->pgsize, &_rp)) != 0)
135
 
                        goto out;
136
 
                if (rootsplit) {
137
 
                        P_INIT(_lp, file_dbp->pgsize, argp->left,
138
 
                            PGNO_INVALID,
139
 
                            ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
140
 
                            LEVEL(sp), TYPE(sp));
141
 
                        P_INIT(_rp, file_dbp->pgsize, argp->right,
142
 
                            ISINTERNAL(sp) ?  PGNO_INVALID : argp->left,
143
 
                            PGNO_INVALID, LEVEL(sp), TYPE(sp));
144
 
                } else {
145
 
                        P_INIT(_lp, file_dbp->pgsize, PGNO(sp),
146
 
                            ISINTERNAL(sp) ? PGNO_INVALID : PREV_PGNO(sp),
147
 
                            ISINTERNAL(sp) ? PGNO_INVALID : argp->right,
148
 
                            LEVEL(sp), TYPE(sp));
149
 
                        P_INIT(_rp, file_dbp->pgsize, argp->right,
150
 
                            ISINTERNAL(sp) ? PGNO_INVALID : sp->pgno,
151
 
                            ISINTERNAL(sp) ? PGNO_INVALID : NEXT_PGNO(sp),
152
 
                            LEVEL(sp), TYPE(sp));
153
 
                }
154
 
 
155
 
                /* Split the page. */
156
 
                if ((ret = __bam_copy(file_dbp, sp, _lp, 0, argp->indx)) != 0 ||
157
 
                    (ret = __bam_copy(file_dbp, sp, _rp, argp->indx,
158
 
                    NUM_ENT(sp))) != 0)
159
 
                        goto out;
160
 
 
161
 
                /* If the left child is wrong, update it. */
162
 
                if (lp == NULL && (ret = mpf->get(
163
 
                    mpf, &argp->left, DB_MPOOL_CREATE, &lp)) != 0) {
164
 
                        __db_pgerr(file_dbp, argp->left, ret);
165
 
                        lp = NULL;
166
 
                        goto out;
167
 
                }
168
 
                if (l_update) {
169
 
                        memcpy(lp, _lp, file_dbp->pgsize);
170
 
                        lp->lsn = *lsnp;
171
 
                        if ((ret = mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
172
 
                                goto out;
173
 
                        lp = NULL;
174
 
                }
175
 
 
176
 
                /* If the right child is wrong, update it. */
177
 
                if (rp == NULL && (ret = mpf->get(
178
 
                    mpf, &argp->right, DB_MPOOL_CREATE, &rp)) != 0) {
179
 
                        __db_pgerr(file_dbp, argp->right, ret);
180
 
                        rp = NULL;
181
 
                        goto out;
182
 
                }
183
 
                if (r_update) {
184
 
                        memcpy(rp, _rp, file_dbp->pgsize);
185
 
                        rp->lsn = *lsnp;
186
 
                        if ((ret = mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
187
 
                                goto out;
188
 
                        rp = NULL;
189
 
                }
190
 
 
191
 
                /*
192
 
                 * If the parent page is wrong, update it.  This is of interest
193
 
                 * only if it was a root split, since root splits create parent
194
 
                 * pages.  All other splits modify a parent page, but those are
195
 
                 * separately logged and recovered.
196
 
                 */
197
 
                if (rootsplit && p_update) {
198
 
                        if (IS_BTREE_PAGE(sp)) {
199
 
                                ptype = P_IBTREE;
200
 
                                rc = argp->opflags & SPL_NRECS ? 1 : 0;
201
 
                        } else {
202
 
                                ptype = P_IRECNO;
203
 
                                rc = 1;
204
 
                        }
205
 
 
206
 
                        P_INIT(pp, file_dbp->pgsize, root_pgno,
207
 
                            PGNO_INVALID, PGNO_INVALID, _lp->level + 1, ptype);
208
 
                        RE_NREC_SET(pp, rc ?  __bam_total(file_dbp, _lp) +
209
 
                            __bam_total(file_dbp, _rp) : 0);
210
 
 
211
 
                        pp->lsn = *lsnp;
212
 
                        if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
213
 
                                goto out;
214
 
                        pp = NULL;
215
 
                }
216
 
 
217
 
check_next:     /*
218
 
                 * Finally, redo the next-page link if necessary.  This is of
219
 
                 * interest only if it wasn't a root split -- inserting a new
220
 
                 * page in the tree requires that any following page have its
221
 
                 * previous-page pointer updated to our new page.  The next
222
 
                 * page must exist because we're redoing the operation.
223
 
                 */
224
 
                if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
225
 
                        if ((ret = mpf->get(mpf, &argp->npgno, 0, &np)) != 0) {
226
 
                                __db_pgerr(file_dbp, argp->npgno, ret);
227
 
                                np = NULL;
228
 
                                goto out;
229
 
                        }
230
 
                        cmp = log_compare(&LSN(np), &argp->nlsn);
231
 
                        CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn);
232
 
                        if (cmp == 0) {
233
 
                                PREV_PGNO(np) = argp->right;
234
 
                                np->lsn = *lsnp;
235
 
                                if ((ret =
236
 
                                    mpf->put(mpf, np, DB_MPOOL_DIRTY)) != 0)
237
 
                                        goto out;
238
 
                                np = NULL;
239
 
                        }
240
 
                }
241
 
        } else {
242
 
                /*
243
 
                 * If the split page is wrong, replace its contents with the
244
 
                 * logged page contents.  If the page doesn't exist, it means
245
 
                 * that the create of the page never happened, nor did any of
246
 
                 * the adds onto the page that caused the split, and there's
247
 
                 * really no undo-ing to be done.
248
 
                 */
249
 
                if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
250
 
                        pp = NULL;
251
 
                        goto lrundo;
252
 
                }
253
 
                if (log_compare(lsnp, &LSN(pp)) == 0) {
254
 
                        memcpy(pp, argp->pg.data, argp->pg.size);
255
 
                        if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
256
 
                                goto out;
257
 
                        pp = NULL;
258
 
                }
259
 
 
260
 
                /*
261
 
                 * If it's a root split and the left child ever existed, update
262
 
                 * its LSN.  (If it's not a root split, we've updated the left
263
 
                 * page already -- it's the same as the split page.) If the
264
 
                 * right child ever existed, root split or not, update its LSN.
265
 
                 * The undo of the page allocation(s) will restore them to the
266
 
                 * free list.
267
 
                 */
268
 
lrundo:         if ((rootsplit && lp != NULL) || rp != NULL) {
269
 
                        if (rootsplit && lp != NULL &&
270
 
                            log_compare(lsnp, &LSN(lp)) == 0) {
271
 
                                lp->lsn = argp->llsn;
272
 
                                if ((ret =
273
 
                                    mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
274
 
                                        goto out;
275
 
                                lp = NULL;
276
 
                        }
277
 
                        if (rp != NULL &&
278
 
                            log_compare(lsnp, &LSN(rp)) == 0) {
279
 
                                rp->lsn = argp->rlsn;
280
 
                                if ((ret =
281
 
                                    mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
282
 
                                        goto out;
283
 
                                rp = NULL;
284
 
                        }
285
 
                }
286
 
 
287
 
                /*
288
 
                 * Finally, undo the next-page link if necessary.  This is of
289
 
                 * interest only if it wasn't a root split -- inserting a new
290
 
                 * page in the tree requires that any following page have its
291
 
                 * previous-page pointer updated to our new page.  Since it's
292
 
                 * possible that the next-page never existed, we ignore it as
293
 
                 * if there's nothing to undo.
294
 
                 */
295
 
                if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
296
 
                        if ((ret = mpf->get(mpf, &argp->npgno, 0, &np)) != 0) {
297
 
                                np = NULL;
298
 
                                goto done;
299
 
                        }
300
 
                        if (log_compare(lsnp, &LSN(np)) == 0) {
301
 
                                PREV_PGNO(np) = argp->left;
302
 
                                np->lsn = argp->nlsn;
303
 
                                if (mpf->put(mpf, np, DB_MPOOL_DIRTY))
304
 
                                        goto out;
305
 
                                np = NULL;
306
 
                        }
307
 
                }
308
 
        }
309
 
 
310
 
done:   *lsnp = argp->prev_lsn;
311
 
        ret = 0;
312
 
 
313
 
out:    /* Free any pages that weren't dirtied. */
314
 
        if (pp != NULL && (t_ret = mpf->put(mpf, pp, 0)) != 0 && ret == 0)
315
 
                ret = t_ret;
316
 
        if (lp != NULL && (t_ret = mpf->put(mpf, lp, 0)) != 0 && ret == 0)
317
 
                ret = t_ret;
318
 
        if (np != NULL && (t_ret = mpf->put(mpf, np, 0)) != 0 && ret == 0)
319
 
                ret = t_ret;
320
 
        if (rp != NULL && (t_ret = mpf->put(mpf, rp, 0)) != 0 && ret == 0)
321
 
                ret = t_ret;
322
 
 
323
 
        /* Free any allocated space. */
324
 
        if (_lp != NULL)
325
 
                __os_free(dbenv, _lp);
326
 
        if (_rp != NULL)
327
 
                __os_free(dbenv, _rp);
328
 
        if (sp != NULL)
329
 
                __os_free(dbenv, sp);
330
 
 
331
 
        REC_CLOSE;
332
 
}
333
 
 
334
 
/*
335
 
 * __bam_rsplit_recover --
336
 
 *      Recovery function for a reverse split.
337
 
 *
338
 
 * PUBLIC: int __bam_rsplit_recover
339
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
340
 
 */
341
 
int
342
 
__bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
343
 
        DB_ENV *dbenv;
344
 
        DBT *dbtp;
345
 
        DB_LSN *lsnp;
346
 
        db_recops op;
347
 
        void *info;
348
 
{
349
 
        __bam_rsplit_args *argp;
350
 
        DB *file_dbp;
351
 
        DBC *dbc;
352
 
        DB_LSN copy_lsn;
353
 
        DB_MPOOLFILE *mpf;
354
 
        PAGE *pagep;
355
 
        db_pgno_t pgno, root_pgno;
356
 
        int cmp_n, cmp_p, modified, ret;
357
 
 
358
 
        pagep = NULL;
359
 
        COMPQUIET(info, NULL);
360
 
        REC_PRINT(__bam_rsplit_print);
361
 
        REC_INTRO(__bam_rsplit_read, 1);
362
 
 
363
 
        /* Fix the root page. */
364
 
        pgno = root_pgno = argp->root_pgno;
365
 
        if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) != 0) {
366
 
                /* The root page must always exist if we are going forward. */
367
 
                if (DB_REDO(op)) {
368
 
                        __db_pgerr(file_dbp, pgno, ret);
369
 
                        goto out;
370
 
                }
371
 
                /* This must be the root of an OPD tree. */
372
 
                DB_ASSERT(root_pgno !=
373
 
                    ((BTREE *)file_dbp->bt_internal)->bt_root);
374
 
                ret = 0;
375
 
                goto do_page;
376
 
        }
377
 
        modified = 0;
378
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
379
 
        cmp_p = log_compare(&LSN(pagep), &argp->rootlsn);
380
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->rootlsn);
381
 
        if (cmp_p == 0 && DB_REDO(op)) {
382
 
                /* Need to redo update described. */
383
 
                memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
384
 
                pagep->pgno = root_pgno;
385
 
                pagep->lsn = *lsnp;
386
 
                modified = 1;
387
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
388
 
                /* Need to undo update described. */
389
 
                P_INIT(pagep, file_dbp->pgsize, root_pgno,
390
 
                    argp->nrec, PGNO_INVALID, pagep->level + 1,
391
 
                    IS_BTREE_PAGE(pagep) ? P_IBTREE : P_IRECNO);
392
 
                if ((ret = __db_pitem(dbc, pagep, 0,
393
 
                    argp->rootent.size, &argp->rootent, NULL)) != 0)
394
 
                        goto out;
395
 
                pagep->lsn = argp->rootlsn;
396
 
                modified = 1;
397
 
        }
398
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
399
 
                goto out;
400
 
 
401
 
do_page:
402
 
        /*
403
 
         * Fix the page copied over the root page.  It's possible that the
404
 
         * page never made it to disk, so if we're undo-ing and the page
405
 
         * doesn't exist, it's okay and there's nothing further to do.
406
 
         */
407
 
        if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
408
 
                if (DB_UNDO(op))
409
 
                        goto done;
410
 
                __db_pgerr(file_dbp, argp->pgno, ret);
411
 
                goto out;
412
 
        }
413
 
        modified = 0;
414
 
        (void)__ua_memcpy(&copy_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
415
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
416
 
        cmp_p = log_compare(&LSN(pagep), &copy_lsn);
417
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
418
 
        if (cmp_p == 0 && DB_REDO(op)) {
419
 
                /* Need to redo update described. */
420
 
                pagep->lsn = *lsnp;
421
 
                modified = 1;
422
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
423
 
                /* Need to undo update described. */
424
 
                memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
425
 
                modified = 1;
426
 
        }
427
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
428
 
                goto out;
429
 
        pagep = NULL;
430
 
 
431
 
done:   *lsnp = argp->prev_lsn;
432
 
        ret = 0;
433
 
 
434
 
out:    if (pagep != NULL)
435
 
                (void)mpf->put(mpf, pagep, 0);
436
 
        REC_CLOSE;
437
 
}
438
 
 
439
 
/*
440
 
 * __bam_adj_recover --
441
 
 *      Recovery function for adj.
442
 
 *
443
 
 * PUBLIC: int __bam_adj_recover
444
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
445
 
 */
446
 
int
447
 
__bam_adj_recover(dbenv, dbtp, lsnp, op, info)
448
 
        DB_ENV *dbenv;
449
 
        DBT *dbtp;
450
 
        DB_LSN *lsnp;
451
 
        db_recops op;
452
 
        void *info;
453
 
{
454
 
        __bam_adj_args *argp;
455
 
        DB *file_dbp;
456
 
        DBC *dbc;
457
 
        DB_MPOOLFILE *mpf;
458
 
        PAGE *pagep;
459
 
        int cmp_n, cmp_p, modified, ret;
460
 
 
461
 
        pagep = NULL;
462
 
        COMPQUIET(info, NULL);
463
 
        REC_PRINT(__bam_adj_print);
464
 
        REC_INTRO(__bam_adj_read, 1);
465
 
 
466
 
        /* Get the page; if it never existed and we're undoing, we're done. */
467
 
        if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
468
 
                if (DB_UNDO(op))
469
 
                        goto done;
470
 
                __db_pgerr(file_dbp, argp->pgno, ret);
471
 
                goto out;
472
 
        }
473
 
 
474
 
        modified = 0;
475
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
476
 
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
477
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
478
 
        if (cmp_p == 0 && DB_REDO(op)) {
479
 
                /* Need to redo update described. */
480
 
                if ((ret = __bam_adjindx(dbc,
481
 
                    pagep, argp->indx, argp->indx_copy, argp->is_insert)) != 0)
482
 
                        goto out;
483
 
 
484
 
                LSN(pagep) = *lsnp;
485
 
                modified = 1;
486
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
487
 
                /* Need to undo update described. */
488
 
                if ((ret = __bam_adjindx(dbc,
489
 
                    pagep, argp->indx, argp->indx_copy, !argp->is_insert)) != 0)
490
 
                        goto out;
491
 
 
492
 
                LSN(pagep) = argp->lsn;
493
 
                modified = 1;
494
 
        }
495
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
496
 
                goto out;
497
 
        pagep = NULL;
498
 
 
499
 
done:   *lsnp = argp->prev_lsn;
500
 
        ret = 0;
501
 
 
502
 
out:    if (pagep != NULL)
503
 
                (void)mpf->put(mpf, pagep, 0);
504
 
        REC_CLOSE;
505
 
}
506
 
 
507
 
/*
508
 
 * __bam_cadjust_recover --
509
 
 *      Recovery function for the adjust of a count change in an internal
510
 
 *      page.
511
 
 *
512
 
 * PUBLIC: int __bam_cadjust_recover
513
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
514
 
 */
515
 
int
516
 
__bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
517
 
        DB_ENV *dbenv;
518
 
        DBT *dbtp;
519
 
        DB_LSN *lsnp;
520
 
        db_recops op;
521
 
        void *info;
522
 
{
523
 
        __bam_cadjust_args *argp;
524
 
        DB *file_dbp;
525
 
        DBC *dbc;
526
 
        DB_MPOOLFILE *mpf;
527
 
        PAGE *pagep;
528
 
        int cmp_n, cmp_p, modified, ret;
529
 
 
530
 
        pagep = NULL;
531
 
        COMPQUIET(info, NULL);
532
 
        REC_PRINT(__bam_cadjust_print);
533
 
        REC_INTRO(__bam_cadjust_read, 1);
534
 
 
535
 
        /* Get the page; if it never existed and we're undoing, we're done. */
536
 
        if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
537
 
                if (DB_UNDO(op))
538
 
                        goto done;
539
 
                __db_pgerr(file_dbp, argp->pgno, ret);
540
 
                goto out;
541
 
        }
542
 
 
543
 
        modified = 0;
544
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
545
 
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
546
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
547
 
        if (cmp_p == 0 && DB_REDO(op)) {
548
 
                /* Need to redo update described. */
549
 
                if (IS_BTREE_PAGE(pagep)) {
550
 
                        GET_BINTERNAL(file_dbp, pagep, argp->indx)->nrecs +=
551
 
                            argp->adjust;
552
 
                        if (argp->opflags & CAD_UPDATEROOT)
553
 
                                RE_NREC_ADJ(pagep, argp->adjust);
554
 
                } else {
555
 
                        GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs +=
556
 
                            argp->adjust;
557
 
                        if (argp->opflags & CAD_UPDATEROOT)
558
 
                                RE_NREC_ADJ(pagep, argp->adjust);
559
 
                }
560
 
 
561
 
                LSN(pagep) = *lsnp;
562
 
                modified = 1;
563
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
564
 
                /* Need to undo update described. */
565
 
                if (IS_BTREE_PAGE(pagep)) {
566
 
                        GET_BINTERNAL(file_dbp, pagep, argp->indx)->nrecs -=
567
 
                            argp->adjust;
568
 
                        if (argp->opflags & CAD_UPDATEROOT)
569
 
                                RE_NREC_ADJ(pagep, -(argp->adjust));
570
 
                } else {
571
 
                        GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs -=
572
 
                            argp->adjust;
573
 
                        if (argp->opflags & CAD_UPDATEROOT)
574
 
                                RE_NREC_ADJ(pagep, -(argp->adjust));
575
 
                }
576
 
                LSN(pagep) = argp->lsn;
577
 
                modified = 1;
578
 
        }
579
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
580
 
                goto out;
581
 
        pagep = NULL;
582
 
 
583
 
done:   *lsnp = argp->prev_lsn;
584
 
        ret = 0;
585
 
 
586
 
out:    if (pagep != NULL)
587
 
                (void)mpf->put(mpf, pagep, 0);
588
 
        REC_CLOSE;
589
 
}
590
 
 
591
 
/*
592
 
 * __bam_cdel_recover --
593
 
 *      Recovery function for the intent-to-delete of a cursor record.
594
 
 *
595
 
 * PUBLIC: int __bam_cdel_recover
596
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
597
 
 */
598
 
int
599
 
__bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
600
 
        DB_ENV *dbenv;
601
 
        DBT *dbtp;
602
 
        DB_LSN *lsnp;
603
 
        db_recops op;
604
 
        void *info;
605
 
{
606
 
        __bam_cdel_args *argp;
607
 
        DB *file_dbp;
608
 
        DBC *dbc;
609
 
        DB_MPOOLFILE *mpf;
610
 
        PAGE *pagep;
611
 
        u_int32_t indx;
612
 
        int cmp_n, cmp_p, modified, ret;
613
 
 
614
 
        pagep = NULL;
615
 
        COMPQUIET(info, NULL);
616
 
        REC_PRINT(__bam_cdel_print);
617
 
        REC_INTRO(__bam_cdel_read, 1);
618
 
 
619
 
        /* Get the page; if it never existed and we're undoing, we're done. */
620
 
        if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
621
 
                if (DB_UNDO(op))
622
 
                        goto done;
623
 
                __db_pgerr(file_dbp, argp->pgno, ret);
624
 
                goto out;
625
 
        }
626
 
 
627
 
        modified = 0;
628
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
629
 
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
630
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
631
 
        if (cmp_p == 0 && DB_REDO(op)) {
632
 
                /* Need to redo update described. */
633
 
                indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
634
 
                B_DSET(GET_BKEYDATA(file_dbp, pagep, indx)->type);
635
 
 
636
 
                LSN(pagep) = *lsnp;
637
 
                modified = 1;
638
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
639
 
                /* Need to undo update described. */
640
 
                indx = argp->indx + (TYPE(pagep) == P_LBTREE ? O_INDX : 0);
641
 
                B_DCLR(GET_BKEYDATA(file_dbp, pagep, indx)->type);
642
 
 
643
 
                (void)__bam_ca_delete(file_dbp, argp->pgno, argp->indx, 0);
644
 
 
645
 
                LSN(pagep) = argp->lsn;
646
 
                modified = 1;
647
 
        }
648
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
649
 
                goto out;
650
 
        pagep = NULL;
651
 
 
652
 
done:   *lsnp = argp->prev_lsn;
653
 
        ret = 0;
654
 
 
655
 
out:    if (pagep != NULL)
656
 
                (void)mpf->put(mpf, pagep, 0);
657
 
        REC_CLOSE;
658
 
}
659
 
 
660
 
/*
661
 
 * __bam_repl_recover --
662
 
 *      Recovery function for page item replacement.
663
 
 *
664
 
 * PUBLIC: int __bam_repl_recover
665
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
666
 
 */
667
 
int
668
 
__bam_repl_recover(dbenv, dbtp, lsnp, op, info)
669
 
        DB_ENV *dbenv;
670
 
        DBT *dbtp;
671
 
        DB_LSN *lsnp;
672
 
        db_recops op;
673
 
        void *info;
674
 
{
675
 
        __bam_repl_args *argp;
676
 
        BKEYDATA *bk;
677
 
        DB *file_dbp;
678
 
        DBC *dbc;
679
 
        DBT dbt;
680
 
        DB_MPOOLFILE *mpf;
681
 
        PAGE *pagep;
682
 
        int cmp_n, cmp_p, modified, ret;
683
 
        u_int8_t *p;
684
 
 
685
 
        pagep = NULL;
686
 
        COMPQUIET(info, NULL);
687
 
        REC_PRINT(__bam_repl_print);
688
 
        REC_INTRO(__bam_repl_read, 1);
689
 
 
690
 
        /* Get the page; if it never existed and we're undoing, we're done. */
691
 
        if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
692
 
                if (DB_UNDO(op))
693
 
                        goto done;
694
 
                __db_pgerr(file_dbp, argp->pgno, ret);
695
 
                goto out;
696
 
        }
697
 
        bk = GET_BKEYDATA(file_dbp, pagep, argp->indx);
698
 
 
699
 
        modified = 0;
700
 
        cmp_n = log_compare(lsnp, &LSN(pagep));
701
 
        cmp_p = log_compare(&LSN(pagep), &argp->lsn);
702
 
        CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
703
 
        if (cmp_p == 0 && DB_REDO(op)) {
704
 
                /*
705
 
                 * Need to redo update described.
706
 
                 *
707
 
                 * Re-build the replacement item.
708
 
                 */
709
 
                memset(&dbt, 0, sizeof(dbt));
710
 
                dbt.size = argp->prefix + argp->suffix + argp->repl.size;
711
 
                if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
712
 
                        goto out;
713
 
                p = dbt.data;
714
 
                memcpy(p, bk->data, argp->prefix);
715
 
                p += argp->prefix;
716
 
                memcpy(p, argp->repl.data, argp->repl.size);
717
 
                p += argp->repl.size;
718
 
                memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
719
 
 
720
 
                ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
721
 
                __os_free(dbenv, dbt.data);
722
 
                if (ret != 0)
723
 
                        goto out;
724
 
 
725
 
                LSN(pagep) = *lsnp;
726
 
                modified = 1;
727
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
728
 
                /*
729
 
                 * Need to undo update described.
730
 
                 *
731
 
                 * Re-build the original item.
732
 
                 */
733
 
                memset(&dbt, 0, sizeof(dbt));
734
 
                dbt.size = argp->prefix + argp->suffix + argp->orig.size;
735
 
                if ((ret = __os_malloc(dbenv, dbt.size, &dbt.data)) != 0)
736
 
                        goto out;
737
 
                p = dbt.data;
738
 
                memcpy(p, bk->data, argp->prefix);
739
 
                p += argp->prefix;
740
 
                memcpy(p, argp->orig.data, argp->orig.size);
741
 
                p += argp->orig.size;
742
 
                memcpy(p, bk->data + (bk->len - argp->suffix), argp->suffix);
743
 
 
744
 
                ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
745
 
                __os_free(dbenv, dbt.data);
746
 
                if (ret != 0)
747
 
                        goto out;
748
 
 
749
 
                /* Reset the deleted flag, if necessary. */
750
 
                if (argp->isdeleted)
751
 
                        B_DSET(GET_BKEYDATA(file_dbp, pagep, argp->indx)->type);
752
 
 
753
 
                LSN(pagep) = argp->lsn;
754
 
                modified = 1;
755
 
        }
756
 
        if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
757
 
                goto out;
758
 
        pagep = NULL;
759
 
 
760
 
done:   *lsnp = argp->prev_lsn;
761
 
        ret = 0;
762
 
 
763
 
out:    if (pagep != NULL)
764
 
                (void)mpf->put(mpf, pagep, 0);
765
 
        REC_CLOSE;
766
 
}
767
 
 
768
 
/*
769
 
 * __bam_root_recover --
770
 
 *      Recovery function for setting the root page on the meta-data page.
771
 
 *
772
 
 * PUBLIC: int __bam_root_recover
773
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
774
 
 */
775
 
int
776
 
__bam_root_recover(dbenv, dbtp, lsnp, op, info)
777
 
        DB_ENV *dbenv;
778
 
        DBT *dbtp;
779
 
        DB_LSN *lsnp;
780
 
        db_recops op;
781
 
        void *info;
782
 
{
783
 
        __bam_root_args *argp;
784
 
        BTMETA *meta;
785
 
        DB *file_dbp;
786
 
        DBC *dbc;
787
 
        DB_MPOOLFILE *mpf;
788
 
        int cmp_n, cmp_p, modified, ret;
789
 
 
790
 
        meta = NULL;
791
 
        COMPQUIET(info, NULL);
792
 
        REC_PRINT(__bam_root_print);
793
 
        REC_INTRO(__bam_root_read, 0);
794
 
 
795
 
        if ((ret = mpf->get(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
796
 
                /* The metadata page must always exist on redo. */
797
 
                if (DB_REDO(op)) {
798
 
                        __db_pgerr(file_dbp, argp->meta_pgno, ret);
799
 
                        goto out;
800
 
                } else
801
 
                        goto done;
802
 
        }
803
 
 
804
 
        modified = 0;
805
 
        cmp_n = log_compare(lsnp, &LSN(meta));
806
 
        cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
807
 
        CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
808
 
        if (cmp_p == 0 && DB_REDO(op)) {
809
 
                /* Need to redo update described. */
810
 
                meta->root = argp->root_pgno;
811
 
                meta->dbmeta.lsn = *lsnp;
812
 
                ((BTREE *)file_dbp->bt_internal)->bt_root = meta->root;
813
 
                modified = 1;
814
 
        } else if (cmp_n == 0 && DB_UNDO(op)) {
815
 
                /* Nothing to undo except lsn. */
816
 
                meta->dbmeta.lsn = argp->meta_lsn;
817
 
                modified = 1;
818
 
        }
819
 
        if ((ret = mpf->put(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
820
 
                goto out;
821
 
        meta = NULL;
822
 
 
823
 
done:   *lsnp = argp->prev_lsn;
824
 
        ret = 0;
825
 
 
826
 
out:    if (meta != NULL)
827
 
                (void)mpf->put(mpf, meta, 0);
828
 
        REC_CLOSE;
829
 
}
830
 
 
831
 
/*
832
 
 * __bam_curadj_recover --
833
 
 *      Transaction abort function to undo cursor adjustments.
834
 
 *      This should only be triggered by subtransaction aborts.
835
 
 *
836
 
 * PUBLIC: int __bam_curadj_recover
837
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
838
 
 */
839
 
int
840
 
__bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
841
 
        DB_ENV *dbenv;
842
 
        DBT *dbtp;
843
 
        DB_LSN *lsnp;
844
 
        db_recops op;
845
 
        void *info;
846
 
{
847
 
        __bam_curadj_args *argp;
848
 
        DB *file_dbp;
849
 
        DBC *dbc;
850
 
        DB_MPOOLFILE *mpf;
851
 
        int ret;
852
 
 
853
 
        COMPQUIET(info, NULL);
854
 
 
855
 
        REC_PRINT(__bam_curadj_print);
856
 
        REC_INTRO(__bam_curadj_read, 0);
857
 
 
858
 
        ret = 0;
859
 
        if (op != DB_TXN_ABORT)
860
 
                goto done;
861
 
 
862
 
        switch(argp->mode) {
863
 
        case DB_CA_DI:
864
 
                if ((ret = __bam_ca_di(dbc, argp->from_pgno,
865
 
                    argp->from_indx, -(int)argp->first_indx)) != 0)
866
 
                        goto out;
867
 
                break;
868
 
        case DB_CA_DUP:
869
 
                if ((ret = __bam_ca_undodup(file_dbp, argp->first_indx,
870
 
                    argp->from_pgno, argp->from_indx, argp->to_indx)) != 0)
871
 
                        goto out;
872
 
                break;
873
 
 
874
 
        case DB_CA_RSPLIT:
875
 
                if ((ret =
876
 
                    __bam_ca_rsplit(dbc, argp->to_pgno, argp->from_pgno)) != 0)
877
 
                        goto out;
878
 
                break;
879
 
 
880
 
        case DB_CA_SPLIT:
881
 
                __bam_ca_undosplit(file_dbp, argp->from_pgno,
882
 
                    argp->to_pgno, argp->left_pgno, argp->from_indx);
883
 
                break;
884
 
        }
885
 
 
886
 
done:   *lsnp = argp->prev_lsn;
887
 
out:    REC_CLOSE;
888
 
}
889
 
 
890
 
/*
891
 
 * __bam_rcuradj_recover --
892
 
 *      Transaction abort function to undo cursor adjustments in rrecno.
893
 
 *      This should only be triggered by subtransaction aborts.
894
 
 *
895
 
 * PUBLIC: int __bam_rcuradj_recover
896
 
 * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
897
 
 */
898
 
int
899
 
__bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
900
 
        DB_ENV *dbenv;
901
 
        DBT *dbtp;
902
 
        DB_LSN *lsnp;
903
 
        db_recops op;
904
 
        void *info;
905
 
{
906
 
        __bam_rcuradj_args *argp;
907
 
        BTREE_CURSOR *cp;
908
 
        DB *file_dbp;
909
 
        DBC *dbc, *rdbc;
910
 
        DB_MPOOLFILE *mpf;
911
 
        int ret, t_ret;
912
 
 
913
 
        COMPQUIET(info, NULL);
914
 
        rdbc = NULL;
915
 
 
916
 
        REC_PRINT(__bam_rcuradj_print);
917
 
        REC_INTRO(__bam_rcuradj_read, 0);
918
 
 
919
 
        ret = t_ret = 0;
920
 
 
921
 
        if (op != DB_TXN_ABORT)
922
 
                goto done;
923
 
 
924
 
        /*
925
 
         * We don't know whether we're in an offpage dup set, and
926
 
         * thus don't know whether the dbc REC_INTRO has handed us is
927
 
         * of a reasonable type.  It's certainly unset, so if this is
928
 
         * an offpage dup set, we don't have an OPD cursor.  The
929
 
         * simplest solution is just to allocate a whole new cursor
930
 
         * for our use;  we're only really using it to hold pass some
931
 
         * state into __ram_ca, and this way we don't need to make
932
 
         * this function know anything about how offpage dups work.
933
 
         */
934
 
        if ((ret =
935
 
            __db_icursor(file_dbp,
936
 
                NULL, DB_RECNO, argp->root, 0, DB_LOCK_INVALIDID, &rdbc)) != 0)
937
 
                goto out;
938
 
 
939
 
        cp = (BTREE_CURSOR *)rdbc->internal;
940
 
        F_SET(cp, C_RENUMBER);
941
 
        cp->recno = argp->recno;
942
 
 
943
 
        switch(argp->mode) {
944
 
        case CA_DELETE:
945
 
                /*
946
 
                 * The way to undo a delete is with an insert.  Since
947
 
                 * we're undoing it, the delete flag must be set.
948
 
                 */
949
 
                F_SET(cp, C_DELETED);
950
 
                F_SET(cp, C_RENUMBER);  /* Just in case. */
951
 
                cp->order = argp->order;
952
 
                __ram_ca(rdbc, CA_ICURRENT);
953
 
                break;
954
 
        case CA_IAFTER:
955
 
        case CA_IBEFORE:
956
 
        case CA_ICURRENT:
957
 
                /*
958
 
                 * The way to undo an insert is with a delete.  The delete
959
 
                 * flag is unset to start with.
960
 
                 */
961
 
                F_CLR(cp, C_DELETED);
962
 
                cp->order = INVALID_ORDER;
963
 
                __ram_ca(rdbc, CA_DELETE);
964
 
                break;
965
 
        }
966
 
 
967
 
done:   *lsnp = argp->prev_lsn;
968
 
out:    if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0)
969
 
                ret = t_ret;
970
 
        REC_CLOSE;
971
 
}