2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1996-2002
5
* Sleepycat Software. All rights reserved.
11
static const char revid[] = "$Id$";
14
#ifndef NO_SYSTEM_INCLUDES
15
#include <sys/types.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"
27
#define IS_BTREE_PAGE(pagep) \
28
(TYPE(pagep) == P_IBTREE || \
29
TYPE(pagep) == P_LBTREE || TYPE(pagep) == P_LDUP)
32
* __bam_split_recover --
33
* Recovery function for split.
35
* PUBLIC: int __bam_split_recover
36
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
39
__bam_split_recover(dbenv, dbtp, lsnp, op, info)
46
__bam_split_args *argp;
50
PAGE *_lp, *lp, *np, *pp, *_rp, *rp, *sp;
51
db_pgno_t pgno, root_pgno;
53
int cmp, l_update, p_update, r_update, rc, ret, ret_l, rootsplit, t_ret;
55
COMPQUIET(info, NULL);
56
REC_PRINT(__bam_split_print);
59
_lp = lp = np = pp = _rp = rp = NULL;
62
REC_INTRO(__bam_split_read, 1);
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.
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.
78
if ((ret = __os_malloc(dbenv, argp->pg.size, &sp)) != 0)
80
memcpy(sp, argp->pg.data, argp->pg.size);
83
root_pgno = argp->root_pgno;
84
rootsplit = root_pgno != PGNO_INVALID;
85
if ((ret_l = mpf->get(mpf, &argp->left, 0, &lp)) != 0)
87
if (mpf->get(mpf, &argp->right, 0, &rp) != 0)
91
l_update = r_update = p_update = 0;
93
* Decide if we need to resplit the page.
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
101
if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
102
__db_pgerr(file_dbp, pgno, ret);
106
cmp = log_compare(&LSN(pp), &LSN(argp->pg.data));
107
CHECK_LSN(op, cmp, &LSN(pp), &LSN(argp->pg.data));
109
} else if (lp == NULL) {
110
__db_pgerr(file_dbp, argp->left, ret_l);
115
cmp = log_compare(&LSN(lp), &argp->llsn);
116
CHECK_LSN(op, cmp, &LSN(lp), &argp->llsn);
123
cmp = log_compare(&LSN(rp), &argp->rlsn);
124
CHECK_LSN(op, cmp, &LSN(rp), &argp->rlsn);
129
if (!p_update && !l_update && !r_update)
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)
137
P_INIT(_lp, file_dbp->pgsize, argp->left,
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));
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));
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,
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);
169
memcpy(lp, _lp, file_dbp->pgsize);
171
if ((ret = mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
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);
184
memcpy(rp, _rp, file_dbp->pgsize);
186
if ((ret = mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
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.
197
if (rootsplit && p_update) {
198
if (IS_BTREE_PAGE(sp)) {
200
rc = argp->opflags & SPL_NRECS ? 1 : 0;
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);
212
if ((ret = mpf->put(mpf, pp, DB_MPOOL_DIRTY)) != 0)
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.
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);
230
cmp = log_compare(&LSN(np), &argp->nlsn);
231
CHECK_LSN(op, cmp, &LSN(np), &argp->nlsn);
233
PREV_PGNO(np) = argp->right;
236
mpf->put(mpf, np, DB_MPOOL_DIRTY)) != 0)
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.
249
if ((ret = mpf->get(mpf, &pgno, 0, &pp)) != 0) {
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)
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
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;
273
mpf->put(mpf, lp, DB_MPOOL_DIRTY)) != 0)
278
log_compare(lsnp, &LSN(rp)) == 0) {
279
rp->lsn = argp->rlsn;
281
mpf->put(mpf, rp, DB_MPOOL_DIRTY)) != 0)
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.
295
if (!rootsplit && !IS_ZERO_LSN(argp->nlsn)) {
296
if ((ret = mpf->get(mpf, &argp->npgno, 0, &np)) != 0) {
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))
310
done: *lsnp = argp->prev_lsn;
313
out: /* Free any pages that weren't dirtied. */
314
if (pp != NULL && (t_ret = mpf->put(mpf, pp, 0)) != 0 && ret == 0)
316
if (lp != NULL && (t_ret = mpf->put(mpf, lp, 0)) != 0 && ret == 0)
318
if (np != NULL && (t_ret = mpf->put(mpf, np, 0)) != 0 && ret == 0)
320
if (rp != NULL && (t_ret = mpf->put(mpf, rp, 0)) != 0 && ret == 0)
323
/* Free any allocated space. */
325
__os_free(dbenv, _lp);
327
__os_free(dbenv, _rp);
329
__os_free(dbenv, sp);
335
* __bam_rsplit_recover --
336
* Recovery function for a reverse split.
338
* PUBLIC: int __bam_rsplit_recover
339
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
342
__bam_rsplit_recover(dbenv, dbtp, lsnp, op, info)
349
__bam_rsplit_args *argp;
355
db_pgno_t pgno, root_pgno;
356
int cmp_n, cmp_p, modified, ret;
359
COMPQUIET(info, NULL);
360
REC_PRINT(__bam_rsplit_print);
361
REC_INTRO(__bam_rsplit_read, 1);
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. */
368
__db_pgerr(file_dbp, pgno, ret);
371
/* This must be the root of an OPD tree. */
372
DB_ASSERT(root_pgno !=
373
((BTREE *)file_dbp->bt_internal)->bt_root);
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;
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)
395
pagep->lsn = argp->rootlsn;
398
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
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.
407
if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
410
__db_pgerr(file_dbp, argp->pgno, ret);
414
(void)__ua_memcpy(©_lsn, &LSN(argp->pgdbt.data), sizeof(DB_LSN));
415
cmp_n = log_compare(lsnp, &LSN(pagep));
416
cmp_p = log_compare(&LSN(pagep), ©_lsn);
417
CHECK_LSN(op, cmp_p, &LSN(pagep), ©_lsn);
418
if (cmp_p == 0 && DB_REDO(op)) {
419
/* Need to redo update described. */
422
} else if (cmp_n == 0 && DB_UNDO(op)) {
423
/* Need to undo update described. */
424
memcpy(pagep, argp->pgdbt.data, argp->pgdbt.size);
427
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
431
done: *lsnp = argp->prev_lsn;
434
out: if (pagep != NULL)
435
(void)mpf->put(mpf, pagep, 0);
440
* __bam_adj_recover --
441
* Recovery function for adj.
443
* PUBLIC: int __bam_adj_recover
444
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
447
__bam_adj_recover(dbenv, dbtp, lsnp, op, info)
454
__bam_adj_args *argp;
459
int cmp_n, cmp_p, modified, ret;
462
COMPQUIET(info, NULL);
463
REC_PRINT(__bam_adj_print);
464
REC_INTRO(__bam_adj_read, 1);
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) {
470
__db_pgerr(file_dbp, argp->pgno, ret);
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)
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)
492
LSN(pagep) = argp->lsn;
495
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
499
done: *lsnp = argp->prev_lsn;
502
out: if (pagep != NULL)
503
(void)mpf->put(mpf, pagep, 0);
508
* __bam_cadjust_recover --
509
* Recovery function for the adjust of a count change in an internal
512
* PUBLIC: int __bam_cadjust_recover
513
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
516
__bam_cadjust_recover(dbenv, dbtp, lsnp, op, info)
523
__bam_cadjust_args *argp;
528
int cmp_n, cmp_p, modified, ret;
531
COMPQUIET(info, NULL);
532
REC_PRINT(__bam_cadjust_print);
533
REC_INTRO(__bam_cadjust_read, 1);
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) {
539
__db_pgerr(file_dbp, argp->pgno, ret);
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 +=
552
if (argp->opflags & CAD_UPDATEROOT)
553
RE_NREC_ADJ(pagep, argp->adjust);
555
GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs +=
557
if (argp->opflags & CAD_UPDATEROOT)
558
RE_NREC_ADJ(pagep, argp->adjust);
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 -=
568
if (argp->opflags & CAD_UPDATEROOT)
569
RE_NREC_ADJ(pagep, -(argp->adjust));
571
GET_RINTERNAL(file_dbp, pagep, argp->indx)->nrecs -=
573
if (argp->opflags & CAD_UPDATEROOT)
574
RE_NREC_ADJ(pagep, -(argp->adjust));
576
LSN(pagep) = argp->lsn;
579
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
583
done: *lsnp = argp->prev_lsn;
586
out: if (pagep != NULL)
587
(void)mpf->put(mpf, pagep, 0);
592
* __bam_cdel_recover --
593
* Recovery function for the intent-to-delete of a cursor record.
595
* PUBLIC: int __bam_cdel_recover
596
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
599
__bam_cdel_recover(dbenv, dbtp, lsnp, op, info)
606
__bam_cdel_args *argp;
612
int cmp_n, cmp_p, modified, ret;
615
COMPQUIET(info, NULL);
616
REC_PRINT(__bam_cdel_print);
617
REC_INTRO(__bam_cdel_read, 1);
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) {
623
__db_pgerr(file_dbp, argp->pgno, ret);
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);
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);
643
(void)__bam_ca_delete(file_dbp, argp->pgno, argp->indx, 0);
645
LSN(pagep) = argp->lsn;
648
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
652
done: *lsnp = argp->prev_lsn;
655
out: if (pagep != NULL)
656
(void)mpf->put(mpf, pagep, 0);
661
* __bam_repl_recover --
662
* Recovery function for page item replacement.
664
* PUBLIC: int __bam_repl_recover
665
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
668
__bam_repl_recover(dbenv, dbtp, lsnp, op, info)
675
__bam_repl_args *argp;
682
int cmp_n, cmp_p, modified, ret;
686
COMPQUIET(info, NULL);
687
REC_PRINT(__bam_repl_print);
688
REC_INTRO(__bam_repl_read, 1);
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) {
694
__db_pgerr(file_dbp, argp->pgno, ret);
697
bk = GET_BKEYDATA(file_dbp, pagep, argp->indx);
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)) {
705
* Need to redo update described.
707
* Re-build the replacement item.
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)
714
memcpy(p, bk->data, 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);
720
ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
721
__os_free(dbenv, dbt.data);
727
} else if (cmp_n == 0 && DB_UNDO(op)) {
729
* Need to undo update described.
731
* Re-build the original item.
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)
738
memcpy(p, bk->data, 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);
744
ret = __bam_ritem(dbc, pagep, argp->indx, &dbt);
745
__os_free(dbenv, dbt.data);
749
/* Reset the deleted flag, if necessary. */
751
B_DSET(GET_BKEYDATA(file_dbp, pagep, argp->indx)->type);
753
LSN(pagep) = argp->lsn;
756
if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
760
done: *lsnp = argp->prev_lsn;
763
out: if (pagep != NULL)
764
(void)mpf->put(mpf, pagep, 0);
769
* __bam_root_recover --
770
* Recovery function for setting the root page on the meta-data page.
772
* PUBLIC: int __bam_root_recover
773
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
776
__bam_root_recover(dbenv, dbtp, lsnp, op, info)
783
__bam_root_args *argp;
788
int cmp_n, cmp_p, modified, ret;
791
COMPQUIET(info, NULL);
792
REC_PRINT(__bam_root_print);
793
REC_INTRO(__bam_root_read, 0);
795
if ((ret = mpf->get(mpf, &argp->meta_pgno, 0, &meta)) != 0) {
796
/* The metadata page must always exist on redo. */
798
__db_pgerr(file_dbp, argp->meta_pgno, ret);
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;
814
} else if (cmp_n == 0 && DB_UNDO(op)) {
815
/* Nothing to undo except lsn. */
816
meta->dbmeta.lsn = argp->meta_lsn;
819
if ((ret = mpf->put(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
823
done: *lsnp = argp->prev_lsn;
826
out: if (meta != NULL)
827
(void)mpf->put(mpf, meta, 0);
832
* __bam_curadj_recover --
833
* Transaction abort function to undo cursor adjustments.
834
* This should only be triggered by subtransaction aborts.
836
* PUBLIC: int __bam_curadj_recover
837
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
840
__bam_curadj_recover(dbenv, dbtp, lsnp, op, info)
847
__bam_curadj_args *argp;
853
COMPQUIET(info, NULL);
855
REC_PRINT(__bam_curadj_print);
856
REC_INTRO(__bam_curadj_read, 0);
859
if (op != DB_TXN_ABORT)
864
if ((ret = __bam_ca_di(dbc, argp->from_pgno,
865
argp->from_indx, -(int)argp->first_indx)) != 0)
869
if ((ret = __bam_ca_undodup(file_dbp, argp->first_indx,
870
argp->from_pgno, argp->from_indx, argp->to_indx)) != 0)
876
__bam_ca_rsplit(dbc, argp->to_pgno, argp->from_pgno)) != 0)
881
__bam_ca_undosplit(file_dbp, argp->from_pgno,
882
argp->to_pgno, argp->left_pgno, argp->from_indx);
886
done: *lsnp = argp->prev_lsn;
891
* __bam_rcuradj_recover --
892
* Transaction abort function to undo cursor adjustments in rrecno.
893
* This should only be triggered by subtransaction aborts.
895
* PUBLIC: int __bam_rcuradj_recover
896
* PUBLIC: __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
899
__bam_rcuradj_recover(dbenv, dbtp, lsnp, op, info)
906
__bam_rcuradj_args *argp;
913
COMPQUIET(info, NULL);
916
REC_PRINT(__bam_rcuradj_print);
917
REC_INTRO(__bam_rcuradj_read, 0);
921
if (op != DB_TXN_ABORT)
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.
935
__db_icursor(file_dbp,
936
NULL, DB_RECNO, argp->root, 0, DB_LOCK_INVALIDID, &rdbc)) != 0)
939
cp = (BTREE_CURSOR *)rdbc->internal;
940
F_SET(cp, C_RENUMBER);
941
cp->recno = argp->recno;
946
* The way to undo a delete is with an insert. Since
947
* we're undoing it, the delete flag must be set.
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);
958
* The way to undo an insert is with a delete. The delete
959
* flag is unset to start with.
961
F_CLR(cp, C_DELETED);
962
cp->order = INVALID_ORDER;
963
__ram_ca(rdbc, CA_DELETE);
967
done: *lsnp = argp->prev_lsn;
968
out: if (rdbc != NULL && (t_ret = rdbc->c_close(rdbc)) != 0 && ret == 0)