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

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: db_rec.c,v 11.35 2002/08/08 03:57:49 bostic 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/log.h"
  18. #include "dbinc/hash.h"
  19. /*
  20.  * PUBLIC: int __db_addrem_recover
  21.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  22.  *
  23.  * This log message is generated whenever we add or remove a duplicate
  24.  * to/from a duplicate page.  On recover, we just do the opposite.
  25.  */
  26. int
  27. __db_addrem_recover(dbenv, dbtp, lsnp, op, info)
  28. DB_ENV *dbenv;
  29. DBT *dbtp;
  30. DB_LSN *lsnp;
  31. db_recops op;
  32. void *info;
  33. {
  34. __db_addrem_args *argp;
  35. DB *file_dbp;
  36. DBC *dbc;
  37. DB_MPOOLFILE *mpf;
  38. PAGE *pagep;
  39. u_int32_t change;
  40. int cmp_n, cmp_p, ret;
  41. pagep = NULL;
  42. COMPQUIET(info, NULL);
  43. REC_PRINT(__db_addrem_print);
  44. REC_INTRO(__db_addrem_read, 1);
  45. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  46. if (DB_UNDO(op)) {
  47. /*
  48.  * We are undoing and the page doesn't exist.  That
  49.  * is equivalent to having a pagelsn of 0, so we
  50.  * would not have to undo anything.  In this case,
  51.  * don't bother creating a page.
  52.  */
  53. goto done;
  54. } else
  55. if ((ret = mpf->get(mpf,
  56.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  57. goto out;
  58. }
  59. cmp_n = log_compare(lsnp, &LSN(pagep));
  60. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  61. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  62. change = 0;
  63. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_DUP) ||
  64.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_DUP)) {
  65. /* Need to redo an add, or undo a delete. */
  66. if ((ret = __db_pitem(dbc, pagep, argp->indx, argp->nbytes,
  67.     argp->hdr.size == 0 ? NULL : &argp->hdr,
  68.     argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
  69. goto out;
  70. change = DB_MPOOL_DIRTY;
  71. } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_DUP) ||
  72.     (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_DUP)) {
  73. /* Need to undo an add, or redo a delete. */
  74. if ((ret = __db_ditem(dbc,
  75.     pagep, argp->indx, argp->nbytes)) != 0)
  76. goto out;
  77. change = DB_MPOOL_DIRTY;
  78. }
  79. if (change) {
  80. if (DB_REDO(op))
  81. LSN(pagep) = *lsnp;
  82. else
  83. LSN(pagep) = argp->pagelsn;
  84. }
  85. if ((ret = mpf->put(mpf, pagep, change)) != 0)
  86. goto out;
  87. pagep = NULL;
  88. done: *lsnp = argp->prev_lsn;
  89. ret = 0;
  90. out: if (pagep != NULL)
  91. (void)mpf->put(mpf, pagep, 0);
  92. REC_CLOSE;
  93. }
  94. /*
  95.  * PUBLIC: int __db_big_recover
  96.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  97.  */
  98. int
  99. __db_big_recover(dbenv, dbtp, lsnp, op, info)
  100. DB_ENV *dbenv;
  101. DBT *dbtp;
  102. DB_LSN *lsnp;
  103. db_recops op;
  104. void *info;
  105. {
  106. __db_big_args *argp;
  107. DB *file_dbp;
  108. DBC *dbc;
  109. DB_MPOOLFILE *mpf;
  110. PAGE *pagep;
  111. u_int32_t change;
  112. int cmp_n, cmp_p, ret;
  113. pagep = NULL;
  114. COMPQUIET(info, NULL);
  115. REC_PRINT(__db_big_print);
  116. REC_INTRO(__db_big_read, 1);
  117. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  118. if (DB_UNDO(op)) {
  119. /*
  120.  * We are undoing and the page doesn't exist.  That
  121.  * is equivalent to having a pagelsn of 0, so we
  122.  * would not have to undo anything.  In this case,
  123.  * don't bother creating a page.
  124.  */
  125. ret = 0;
  126. goto ppage;
  127. } else
  128. if ((ret = mpf->get(mpf,
  129.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  130. goto out;
  131. }
  132. /*
  133.  * There are three pages we need to check.  The one on which we are
  134.  * adding data, the previous one whose next_pointer may have
  135.  * been updated, and the next one whose prev_pointer may have
  136.  * been updated.
  137.  */
  138. cmp_n = log_compare(lsnp, &LSN(pagep));
  139. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  140. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  141. change = 0;
  142. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) ||
  143.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_REM_BIG)) {
  144. /* We are either redo-ing an add, or undoing a delete. */
  145. P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
  146. argp->next_pgno, 0, P_OVERFLOW);
  147. OV_LEN(pagep) = argp->dbt.size;
  148. OV_REF(pagep) = 1;
  149. memcpy((u_int8_t *)pagep + P_OVERHEAD(file_dbp), argp->dbt.data,
  150.     argp->dbt.size);
  151. PREV_PGNO(pagep) = argp->prev_pgno;
  152. change = DB_MPOOL_DIRTY;
  153. } else if ((cmp_n == 0 && DB_UNDO(op) && argp->opcode == DB_ADD_BIG) ||
  154.     (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_REM_BIG)) {
  155. /*
  156.  * We are either undo-ing an add or redo-ing a delete.
  157.  * The page is about to be reclaimed in either case, so
  158.  * there really isn't anything to do here.
  159.  */
  160. change = DB_MPOOL_DIRTY;
  161. }
  162. if (change)
  163. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  164. if ((ret = mpf->put(mpf, pagep, change)) != 0)
  165. goto out;
  166. pagep = NULL;
  167. /*
  168.  * We only delete a whole chain of overflow.
  169.  * Each page is handled individually
  170.  */
  171. if (argp->opcode == DB_REM_BIG)
  172. goto done;
  173. /* Now check the previous page. */
  174. ppage: if (argp->prev_pgno != PGNO_INVALID) {
  175. change = 0;
  176. if ((ret = mpf->get(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
  177. if (DB_UNDO(op)) {
  178. /*
  179.  * We are undoing and the page doesn't exist.
  180.  * That is equivalent to having a pagelsn of 0,
  181.  * so we would not have to undo anything.  In
  182.  * this case, don't bother creating a page.
  183.  */
  184. *lsnp = argp->prev_lsn;
  185. ret = 0;
  186. goto npage;
  187. } else
  188. if ((ret = mpf->get(mpf, &argp->prev_pgno,
  189.     DB_MPOOL_CREATE, &pagep)) != 0)
  190. goto out;
  191. }
  192. cmp_n = log_compare(lsnp, &LSN(pagep));
  193. cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
  194. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
  195. if (cmp_p == 0 && DB_REDO(op) && argp->opcode == DB_ADD_BIG) {
  196. /* Redo add, undo delete. */
  197. NEXT_PGNO(pagep) = argp->pgno;
  198. change = DB_MPOOL_DIRTY;
  199. } else if (cmp_n == 0 &&
  200.     DB_UNDO(op) && argp->opcode == DB_ADD_BIG) {
  201. /* Redo delete, undo add. */
  202. NEXT_PGNO(pagep) = argp->next_pgno;
  203. change = DB_MPOOL_DIRTY;
  204. }
  205. if (change)
  206. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
  207. if ((ret = mpf->put(mpf, pagep, change)) != 0)
  208. goto out;
  209. }
  210. pagep = NULL;
  211. /* Now check the next page.  Can only be set on a delete. */
  212. npage: if (argp->next_pgno != PGNO_INVALID) {
  213. change = 0;
  214. if ((ret = mpf->get(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
  215. if (DB_UNDO(op)) {
  216. /*
  217.  * We are undoing and the page doesn't exist.
  218.  * That is equivalent to having a pagelsn of 0,
  219.  * so we would not have to undo anything.  In
  220.  * this case, don't bother creating a page.
  221.  */
  222. goto done;
  223. } else
  224. if ((ret = mpf->get(mpf, &argp->next_pgno,
  225.     DB_MPOOL_CREATE, &pagep)) != 0)
  226. goto out;
  227. }
  228. cmp_n = log_compare(lsnp, &LSN(pagep));
  229. cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
  230. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
  231. if (cmp_p == 0 && DB_REDO(op)) {
  232. PREV_PGNO(pagep) = PGNO_INVALID;
  233. change = DB_MPOOL_DIRTY;
  234. } else if (cmp_n == 0 && DB_UNDO(op)) {
  235. PREV_PGNO(pagep) = argp->pgno;
  236. change = DB_MPOOL_DIRTY;
  237. }
  238. if (change)
  239. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
  240. if ((ret = mpf->put(mpf, pagep, change)) != 0)
  241. goto out;
  242. }
  243. pagep = NULL;
  244. done: *lsnp = argp->prev_lsn;
  245. ret = 0;
  246. out: if (pagep != NULL)
  247. (void)mpf->put(mpf, pagep, 0);
  248. REC_CLOSE;
  249. }
  250. /*
  251.  * __db_ovref_recover --
  252.  * Recovery function for __db_ovref().
  253.  *
  254.  * PUBLIC: int __db_ovref_recover
  255.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  256.  */
  257. int
  258. __db_ovref_recover(dbenv, dbtp, lsnp, op, info)
  259. DB_ENV *dbenv;
  260. DBT *dbtp;
  261. DB_LSN *lsnp;
  262. db_recops op;
  263. void *info;
  264. {
  265. __db_ovref_args *argp;
  266. DB *file_dbp;
  267. DBC *dbc;
  268. DB_MPOOLFILE *mpf;
  269. PAGE *pagep;
  270. int cmp, modified, ret;
  271. pagep = NULL;
  272. COMPQUIET(info, NULL);
  273. REC_PRINT(__db_ovref_print);
  274. REC_INTRO(__db_ovref_read, 1);
  275. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  276. if (DB_UNDO(op))
  277. goto done;
  278. __db_pgerr(file_dbp, argp->pgno, ret);
  279. goto out;
  280. }
  281. modified = 0;
  282. cmp = log_compare(&LSN(pagep), &argp->lsn);
  283. CHECK_LSN(op, cmp, &LSN(pagep), &argp->lsn);
  284. if (cmp == 0 && DB_REDO(op)) {
  285. /* Need to redo update described. */
  286. OV_REF(pagep) += argp->adjust;
  287. pagep->lsn = *lsnp;
  288. modified = 1;
  289. } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
  290. /* Need to undo update described. */
  291. OV_REF(pagep) -= argp->adjust;
  292. pagep->lsn = argp->lsn;
  293. modified = 1;
  294. }
  295. if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  296. goto out;
  297. pagep = NULL;
  298. done: *lsnp = argp->prev_lsn;
  299. ret = 0;
  300. out: if (pagep != NULL)
  301. (void)mpf->put(mpf, pagep, 0);
  302. REC_CLOSE;
  303. }
  304. /*
  305.  * __db_relink_recover --
  306.  * Recovery function for relink.
  307.  *
  308.  * PUBLIC: int __db_relink_recover
  309.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  310.  */
  311. int
  312. __db_relink_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. __db_relink_args *argp;
  320. DB *file_dbp;
  321. DBC *dbc;
  322. DB_MPOOLFILE *mpf;
  323. PAGE *pagep;
  324. int cmp_n, cmp_p, modified, ret;
  325. pagep = NULL;
  326. COMPQUIET(info, NULL);
  327. REC_PRINT(__db_relink_print);
  328. REC_INTRO(__db_relink_read, 1);
  329. /*
  330.  * There are up to three pages we need to check -- the page, and the
  331.  * previous and next pages, if they existed.  For a page add operation,
  332.  * the current page is the result of a split and is being recovered
  333.  * elsewhere, so all we need do is recover the next page.
  334.  */
  335. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  336. if (DB_REDO(op)) {
  337. __db_pgerr(file_dbp, argp->pgno, ret);
  338. goto out;
  339. }
  340. goto next2;
  341. }
  342. modified = 0;
  343. if (argp->opcode == DB_ADD_PAGE)
  344. goto next1;
  345. cmp_p = log_compare(&LSN(pagep), &argp->lsn);
  346. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn);
  347. if (cmp_p == 0 && DB_REDO(op)) {
  348. /* Redo the relink. */
  349. pagep->lsn = *lsnp;
  350. modified = 1;
  351. } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
  352. /* Undo the relink. */
  353. pagep->next_pgno = argp->next;
  354. pagep->prev_pgno = argp->prev;
  355. pagep->lsn = argp->lsn;
  356. modified = 1;
  357. }
  358. next1: if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  359. goto out;
  360. pagep = NULL;
  361. next2: if ((ret = mpf->get(mpf, &argp->next, 0, &pagep)) != 0) {
  362. if (DB_REDO(op)) {
  363. __db_pgerr(file_dbp, argp->next, ret);
  364. goto out;
  365. }
  366. goto prev;
  367. }
  368. modified = 0;
  369. cmp_n = log_compare(lsnp, &LSN(pagep));
  370. cmp_p = log_compare(&LSN(pagep), &argp->lsn_next);
  371. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_next);
  372. if ((argp->opcode == DB_REM_PAGE && cmp_p == 0 && DB_REDO(op)) ||
  373.     (argp->opcode == DB_ADD_PAGE && cmp_n == 0 && DB_UNDO(op))) {
  374. /* Redo the remove or undo the add. */
  375. pagep->prev_pgno = argp->prev;
  376. modified = 1;
  377. } else if ((argp->opcode == DB_REM_PAGE && cmp_n == 0 && DB_UNDO(op)) ||
  378.     (argp->opcode == DB_ADD_PAGE && cmp_p == 0 && DB_REDO(op))) {
  379. /* Undo the remove or redo the add. */
  380. pagep->prev_pgno = argp->pgno;
  381. modified = 1;
  382. }
  383. if (modified == 1) {
  384. if (DB_UNDO(op))
  385. pagep->lsn = argp->lsn_next;
  386. else
  387. pagep->lsn = *lsnp;
  388. }
  389. if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  390. goto out;
  391. pagep = NULL;
  392. if (argp->opcode == DB_ADD_PAGE)
  393. goto done;
  394. prev: if ((ret = mpf->get(mpf, &argp->prev, 0, &pagep)) != 0) {
  395. if (DB_REDO(op)) {
  396. __db_pgerr(file_dbp, argp->prev, ret);
  397. goto out;
  398. }
  399. goto done;
  400. }
  401. modified = 0;
  402. cmp_p = log_compare(&LSN(pagep), &argp->lsn_prev);
  403. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->lsn_prev);
  404. if (cmp_p == 0 && DB_REDO(op)) {
  405. /* Redo the relink. */
  406. pagep->next_pgno = argp->next;
  407. modified = 1;
  408. } else if (log_compare(lsnp, &LSN(pagep)) == 0 && DB_UNDO(op)) {
  409. /* Undo the relink. */
  410. pagep->next_pgno = argp->pgno;
  411. modified = 1;
  412. }
  413. if (modified == 1) {
  414. if (DB_UNDO(op))
  415. pagep->lsn = argp->lsn_prev;
  416. else
  417. pagep->lsn = *lsnp;
  418. }
  419. if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  420. goto out;
  421. pagep = NULL;
  422. done: *lsnp = argp->prev_lsn;
  423. ret = 0;
  424. out: if (pagep != NULL)
  425. (void)mpf->put(mpf, pagep, 0);
  426. REC_CLOSE;
  427. }
  428. /*
  429.  * __db_debug_recover --
  430.  * Recovery function for debug.
  431.  *
  432.  * PUBLIC: int __db_debug_recover __P((DB_ENV *,
  433.  * PUBLIC:     DBT *, DB_LSN *, db_recops, void *));
  434.  */
  435. int
  436. __db_debug_recover(dbenv, dbtp, lsnp, op, info)
  437. DB_ENV *dbenv;
  438. DBT *dbtp;
  439. DB_LSN *lsnp;
  440. db_recops op;
  441. void *info;
  442. {
  443. __db_debug_args *argp;
  444. int ret;
  445. COMPQUIET(dbenv, NULL);
  446. COMPQUIET(op, DB_TXN_ABORT);
  447. COMPQUIET(info, NULL);
  448. REC_PRINT(__db_debug_print);
  449. REC_NOOP_INTRO(__db_debug_read);
  450. *lsnp = argp->prev_lsn;
  451. ret = 0;
  452. REC_NOOP_CLOSE;
  453. }
  454. /*
  455.  * __db_noop_recover --
  456.  * Recovery function for noop.
  457.  *
  458.  * PUBLIC: int __db_noop_recover __P((DB_ENV *,
  459.  * PUBLIC:      DBT *, DB_LSN *, db_recops, void *));
  460.  */
  461. int
  462. __db_noop_recover(dbenv, dbtp, lsnp, op, info)
  463. DB_ENV *dbenv;
  464. DBT *dbtp;
  465. DB_LSN *lsnp;
  466. db_recops op;
  467. void *info;
  468. {
  469. __db_noop_args *argp;
  470. DB *file_dbp;
  471. DBC *dbc;
  472. DB_MPOOLFILE *mpf;
  473. PAGE *pagep;
  474. u_int32_t change;
  475. int cmp_n, cmp_p, ret;
  476. pagep = NULL;
  477. COMPQUIET(info, NULL);
  478. REC_PRINT(__db_noop_print);
  479. REC_INTRO(__db_noop_read, 0);
  480. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0)
  481. goto out;
  482. cmp_n = log_compare(lsnp, &LSN(pagep));
  483. cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
  484. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
  485. change = 0;
  486. if (cmp_p == 0 && DB_REDO(op)) {
  487. LSN(pagep) = *lsnp;
  488. change = DB_MPOOL_DIRTY;
  489. } else if (cmp_n == 0 && DB_UNDO(op)) {
  490. LSN(pagep) = argp->prevlsn;
  491. change = DB_MPOOL_DIRTY;
  492. }
  493. ret = mpf->put(mpf, pagep, change);
  494. pagep = NULL;
  495. done: *lsnp = argp->prev_lsn;
  496. out: if (pagep != NULL)
  497. (void)mpf->put(mpf, pagep, 0);
  498. REC_CLOSE;
  499. }
  500. /*
  501.  * __db_pg_alloc_recover --
  502.  * Recovery function for pg_alloc.
  503.  *
  504.  * PUBLIC: int __db_pg_alloc_recover
  505.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  506.  */
  507. int
  508. __db_pg_alloc_recover(dbenv, dbtp, lsnp, op, info)
  509. DB_ENV *dbenv;
  510. DBT *dbtp;
  511. DB_LSN *lsnp;
  512. db_recops op;
  513. void *info;
  514. {
  515. __db_pg_alloc_args *argp;
  516. DB *file_dbp;
  517. DBC *dbc;
  518. DBMETA *meta;
  519. DB_MPOOLFILE *mpf;
  520. PAGE *pagep;
  521. db_pgno_t pgno;
  522. int cmp_n, cmp_p, created, level, modified, ret;
  523. meta = NULL;
  524. pagep = NULL;
  525. REC_PRINT(__db_pg_alloc_print);
  526. REC_INTRO(__db_pg_alloc_read, 0);
  527. /*
  528.  * Fix up the allocated page.  If we're redoing the operation, we have
  529.  * to get the page (creating it if it doesn't exist), and update its
  530.  * LSN.  If we're undoing the operation, we have to reset the page's
  531.  * LSN and put it on the free list.
  532.  *
  533.  * Fix up the metadata page.  If we're redoing the operation, we have
  534.  * to get the metadata page and update its LSN and its free pointer.
  535.  * If we're undoing the operation and the page was ever created, we put
  536.  * it on the freelist.
  537.  */
  538. pgno = PGNO_BASE_MD;
  539. if ((ret = mpf->get(mpf, &pgno, 0, &meta)) != 0) {
  540. /* The metadata page must always exist on redo. */
  541. if (DB_REDO(op)) {
  542. __db_pgerr(file_dbp, pgno, ret);
  543. goto out;
  544. } else
  545. goto done;
  546. }
  547. created = modified = 0;
  548. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  549. /*
  550.  * We have to be able to identify if a page was newly
  551.  * created so we can recover it properly.  We cannot simply
  552.  * look for an empty header, because hash uses a pgin
  553.  * function that will set the header.  Instead, we explicitly
  554.  * try for the page without CREATE and if that fails, then
  555.  * create it.
  556.  */
  557. if ((ret =
  558.     mpf->get(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
  559. __db_pgerr(file_dbp, argp->pgno, ret);
  560. goto out;
  561. }
  562. created = modified = 1;
  563. }
  564. /* Fix up the allocated page. */
  565. cmp_n = log_compare(lsnp, &LSN(pagep));
  566. cmp_p = log_compare(&LSN(pagep), &argp->page_lsn);
  567. /*
  568.  * If an inital allocation is aborted and then reallocated
  569.  * during an archival restore the log record will have
  570.  * an LSN for the page but the page will be empty.
  571.  */
  572. if (IS_ZERO_LSN(LSN(pagep)))
  573. cmp_p = 0;
  574. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->page_lsn);
  575. /*
  576.  * If we we rolled back this allocation previously during an
  577.  * archive restore, the page may have the LSN of the meta page
  578.  * at the point of the roll back.  This will be no more
  579.  * than the LSN of the metadata page at the time of this allocation.
  580.  * Another special case we have to handle is if we ended up with a
  581.  * page of all 0's which can happen if we abort between allocating a
  582.  * page in mpool and initializing it.  In that case, even if we're
  583.  * undoing, we need to re-initialize the page.
  584.  */
  585. if (DB_REDO(op) &&
  586.     (cmp_p == 0 ||
  587.     (IS_ZERO_LSN(argp->page_lsn) &&
  588.     log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) {
  589. /* Need to redo update described. */
  590. switch (argp->ptype) {
  591. case P_LBTREE:
  592. case P_LRECNO:
  593. case P_LDUP:
  594. level = LEAFLEVEL;
  595. break;
  596. default:
  597. level = 0;
  598. break;
  599. }
  600. P_INIT(pagep, file_dbp->pgsize,
  601.     argp->pgno, PGNO_INVALID, PGNO_INVALID, level, argp->ptype);
  602. pagep->lsn = *lsnp;
  603. modified = 1;
  604. } else if (DB_UNDO(op) && (cmp_n == 0 || created)) {
  605. /*
  606.  * This is where we handle the case of a 0'd page (pagep->pgno
  607.  * is equal to PGNO_INVALID).
  608.  * Undo the allocation, reinitialize the page and
  609.  * link its next pointer to the free list.
  610.  */
  611. P_INIT(pagep, file_dbp->pgsize,
  612.     argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
  613. pagep->lsn = argp->page_lsn;
  614. modified = 1;
  615. }
  616. /*
  617.  * If the page was newly created, put it on the limbo list.
  618.  */
  619. if (IS_ZERO_LSN(LSN(pagep)) &&
  620.     IS_ZERO_LSN(argp->page_lsn) && DB_UNDO(op)) {
  621. /* Put the page in limbo.*/
  622. if ((ret = __db_add_limbo(dbenv,
  623.     info, argp->fileid, argp->pgno, 1)) != 0)
  624. goto out;
  625. }
  626. if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  627. goto out;
  628. pagep = NULL;
  629. /* Fix up the metadata page. */
  630. modified = 0;
  631. cmp_n = log_compare(lsnp, &LSN(meta));
  632. cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
  633. CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
  634. if (cmp_p == 0 && DB_REDO(op)) {
  635. /* Need to redo update described. */
  636. LSN(meta) = *lsnp;
  637. meta->free = argp->next;
  638. modified = 1;
  639. } else if (cmp_n == 0 && DB_UNDO(op)) {
  640. /* Need to undo update described. */
  641. LSN(meta) = argp->meta_lsn;
  642. /*
  643.  * If the page has a zero LSN then its newly created
  644.  * and will go into limbo rather than directly on the
  645.  * free list.
  646.  */
  647. if (!IS_ZERO_LSN(argp->page_lsn))
  648. meta->free = argp->pgno;
  649. modified = 1;
  650. }
  651. if ((ret = mpf->put(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  652. goto out;
  653. meta = NULL;
  654. /*
  655.  * This could be the metapage from a subdb which is read from disk
  656.  * to recover its creation.
  657.  */
  658. if (F_ISSET(file_dbp, DB_AM_SUBDB))
  659. switch (argp->type) {
  660. case P_BTREEMETA:
  661. case P_HASHMETA:
  662. case P_QAMMETA:
  663. file_dbp->sync(file_dbp, 0);
  664. break;
  665. }
  666. done: *lsnp = argp->prev_lsn;
  667. ret = 0;
  668. out: if (pagep != NULL)
  669. (void)mpf->put(mpf, pagep, 0);
  670. if (meta != NULL)
  671. (void)mpf->put(mpf, meta, 0);
  672. if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
  673. ret = 0;
  674. REC_CLOSE;
  675. }
  676. /*
  677.  * __db_pg_free_recover --
  678.  * Recovery function for pg_free.
  679.  *
  680.  * PUBLIC: int __db_pg_free_recover
  681.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  682.  */
  683. int
  684. __db_pg_free_recover(dbenv, dbtp, lsnp, op, info)
  685. DB_ENV *dbenv;
  686. DBT *dbtp;
  687. DB_LSN *lsnp;
  688. db_recops op;
  689. void *info;
  690. {
  691. __db_pg_free_args *argp;
  692. DB *file_dbp;
  693. DBC *dbc;
  694. DBMETA *meta;
  695. DB_LSN copy_lsn;
  696. DB_MPOOLFILE *mpf;
  697. PAGE *pagep;
  698. db_pgno_t pgno;
  699. int cmp_n, cmp_p, modified, ret;
  700. COMPQUIET(info, NULL);
  701. meta = NULL;
  702. pagep = NULL;
  703. REC_PRINT(__db_pg_free_print);
  704. REC_INTRO(__db_pg_free_read, 1);
  705. /*
  706.  * Fix up the freed page.  If we're redoing the operation we get the
  707.  * page and explicitly discard its contents, then update its LSN.  If
  708.  * we're undoing the operation, we get the page and restore its header.
  709.  * Create the page if necessary, we may be freeing an aborted
  710.  * create.
  711.  */
  712. if ((ret = mpf->get(mpf, &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  713. goto out;
  714. modified = 0;
  715. (void)__ua_memcpy(&copy_lsn, &LSN(argp->header.data), sizeof(DB_LSN));
  716. cmp_n = log_compare(lsnp, &LSN(pagep));
  717. cmp_p = log_compare(&LSN(pagep), &copy_lsn);
  718. CHECK_LSN(op, cmp_p, &LSN(pagep), &copy_lsn);
  719. if (DB_REDO(op) &&
  720.     (cmp_p == 0 ||
  721.     (IS_ZERO_LSN(copy_lsn) &&
  722.     log_compare(&LSN(pagep), &argp->meta_lsn) <= 0))) {
  723. /* Need to redo update described. */
  724. P_INIT(pagep, file_dbp->pgsize,
  725.     argp->pgno, PGNO_INVALID, argp->next, 0, P_INVALID);
  726. pagep->lsn = *lsnp;
  727. modified = 1;
  728. } else if (cmp_n == 0 && DB_UNDO(op)) {
  729. /* Need to undo update described. */
  730. memcpy(pagep, argp->header.data, argp->header.size);
  731. modified = 1;
  732. }
  733. if ((ret = mpf->put(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  734. goto out;
  735. pagep = NULL;
  736. /*
  737.  * Fix up the metadata page.  If we're redoing or undoing the operation
  738.  * we get the page and update its LSN and free pointer.
  739.  */
  740. pgno = PGNO_BASE_MD;
  741. if ((ret = mpf->get(mpf, &pgno, 0, &meta)) != 0) {
  742. /* The metadata page must always exist. */
  743. __db_pgerr(file_dbp, pgno, ret);
  744. goto out;
  745. }
  746. modified = 0;
  747. cmp_n = log_compare(lsnp, &LSN(meta));
  748. cmp_p = log_compare(&LSN(meta), &argp->meta_lsn);
  749. CHECK_LSN(op, cmp_p, &LSN(meta), &argp->meta_lsn);
  750. if (cmp_p == 0 && DB_REDO(op)) {
  751. /* Need to redo the deallocation. */
  752. meta->free = argp->pgno;
  753. LSN(meta) = *lsnp;
  754. modified = 1;
  755. } else if (cmp_n == 0 && DB_UNDO(op)) {
  756. /* Need to undo the deallocation. */
  757. meta->free = argp->next;
  758. LSN(meta) = argp->meta_lsn;
  759. modified = 1;
  760. }
  761. if ((ret = mpf->put(mpf, meta, modified ? DB_MPOOL_DIRTY : 0)) != 0)
  762. goto out;
  763. meta = NULL;
  764. done: *lsnp = argp->prev_lsn;
  765. ret = 0;
  766. out: if (pagep != NULL)
  767. (void)mpf->put(mpf, pagep, 0);
  768. if (meta != NULL)
  769. (void)mpf->put(mpf, meta, 0);
  770. REC_CLOSE;
  771. }
  772. /*
  773.  * __db_cksum_recover --
  774.  * Recovery function for checksum failure log record.
  775.  *
  776.  * PUBLIC: int __db_cksum_recover __P((DB_ENV *,
  777.  * PUBLIC:      DBT *, DB_LSN *, db_recops, void *));
  778.  */
  779. int
  780. __db_cksum_recover(dbenv, dbtp, lsnp, op, info)
  781. DB_ENV *dbenv;
  782. DBT *dbtp;
  783. DB_LSN *lsnp;
  784. db_recops op;
  785. void *info;
  786. {
  787. __db_cksum_args *argp;
  788. int ret;
  789. COMPQUIET(info, NULL);
  790. COMPQUIET(lsnp, NULL);
  791. COMPQUIET(op, DB_TXN_ABORT);
  792. REC_PRINT(__db_cksum_print);
  793. if ((ret = __db_cksum_read(dbenv, dbtp->data, &argp)) != 0)
  794. return (ret);
  795. /*
  796.  * We had a checksum failure -- the only option is to run catastrophic
  797.  * recovery.
  798.  */
  799. if (F_ISSET(dbenv, DB_ENV_FATAL))
  800. ret = 0;
  801. else {
  802. __db_err(dbenv,
  803.     "Checksum failure requires catastrophic recovery");
  804. ret = __db_panic(dbenv, DB_RUNRECOVERY);
  805. }
  806. __os_free(dbenv, argp);
  807. return (ret);
  808. }