bt_rec.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

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