source: trunk/third/evolution-data-server/libdb/btree/bt_rec.c @ 21189

Revision 21189, 24.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21188, which included commits to RCS files with non-trunk default branches.
Line 
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
11static const char revid[] = "$Id: bt_rec.c,v 1.1.1.1 2004-12-17 17:26:43 ghudson 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 "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 */
38int
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
217check_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                 */
268lrundo:         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
310done:   *lsnp = argp->prev_lsn;
311        ret = 0;
312
313out:    /* 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 */
341int
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
401do_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
431done:   *lsnp = argp->prev_lsn;
432        ret = 0;
433
434out:    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 */
446int
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
499done:   *lsnp = argp->prev_lsn;
500        ret = 0;
501
502out:    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 */
515int
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
583done:   *lsnp = argp->prev_lsn;
584        ret = 0;
585
586out:    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 */
598int
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
652done:   *lsnp = argp->prev_lsn;
653        ret = 0;
654
655out:    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 */
667int
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
760done:   *lsnp = argp->prev_lsn;
761        ret = 0;
762
763out:    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 */
775int
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
823done:   *lsnp = argp->prev_lsn;
824        ret = 0;
825
826out:    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 */
839int
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
886done:   *lsnp = argp->prev_lsn;
887out:    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 */
898int
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
967done:   *lsnp = argp->prev_lsn;
968out:    if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0)
969                ret = t_ret;
970        REC_CLOSE;
971}
Note: See TracBrowser for help on using the repository browser.