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

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. /*
  8.  * Copyright (c) 1995, 1996
  9.  * The President and Fellows of Harvard University.  All rights reserved.
  10.  *
  11.  * This code is derived from software contributed to Berkeley by
  12.  * Margo Seltzer.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or without
  15.  * modification, are permitted provided that the following conditions
  16.  * are met:
  17.  * 1. Redistributions of source code must retain the above copyright
  18.  *    notice, this list of conditions and the following disclaimer.
  19.  * 2. Redistributions in binary form must reproduce the above copyright
  20.  *    notice, this list of conditions and the following disclaimer in the
  21.  *    documentation and/or other materials provided with the distribution.
  22.  * 3. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  */
  38. #include "db_config.h"
  39. #ifndef lint
  40. static const char revid[] = "$Id: db_dispatch.c,v 11.121 2002/09/07 17:36:31 ubell Exp $";
  41. #endif /* not lint */
  42. #ifndef NO_SYSTEM_INCLUDES
  43. #include <sys/types.h>
  44. #include <stddef.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #endif
  48. #include "db_int.h"
  49. #include "dbinc/db_page.h"
  50. #include "dbinc/hash.h"
  51. #include "dbinc/log.h"
  52. #include "dbinc/fop.h"
  53. #include "dbinc/rep.h"
  54. #include "dbinc/txn.h"
  55. static int __db_limbo_fix __P((DB *,
  56.     DB_TXN *, DB_TXNLIST *, db_pgno_t *, DBMETA *));
  57. static int __db_limbo_bucket __P((DB_ENV *, DB_TXN *, DB_TXNLIST *));
  58. static int __db_limbo_move __P((DB_ENV *, DB_TXN *, DB_TXN *, DB_TXNLIST *));
  59. static int __db_lock_move __P((DB_ENV *,
  60. u_int8_t *, db_pgno_t, db_lockmode_t, DB_TXN *, DB_TXN *));
  61. static int __db_default_getpgnos __P((DB_ENV *, DB_LSN *lsnp, void *));
  62. static int __db_txnlist_find_internal __P((DB_ENV *, void *, db_txnlist_type,
  63. u_int32_t, u_int8_t [DB_FILE_ID_LEN], DB_TXNLIST **, int));
  64. static int __db_txnlist_pgnoadd __P((DB_ENV *, DB_TXNHEAD *,
  65. int32_t, u_int8_t [DB_FILE_ID_LEN], char *, db_pgno_t));
  66. /*
  67.  * __db_dispatch --
  68.  *
  69.  * This is the transaction dispatch function used by the db access methods.
  70.  * It is designed to handle the record format used by all the access
  71.  * methods (the one automatically generated by the db_{h,log,read}.sh
  72.  * scripts in the tools directory).  An application using a different
  73.  * recovery paradigm will supply a different dispatch function to txn_open.
  74.  *
  75.  * PUBLIC: int __db_dispatch __P((DB_ENV *,
  76.  * PUBLIC:     int (**)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *)),
  77.  * PUBLIC:     size_t, DBT *, DB_LSN *, db_recops, void *));
  78.  */
  79. int
  80. __db_dispatch(dbenv, dtab, dtabsize, db, lsnp, redo, info)
  81. DB_ENV *dbenv; /* The environment. */
  82. int (**dtab)__P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  83. size_t dtabsize; /* Size of the dtab. */
  84. DBT *db; /* The log record upon which to dispatch. */
  85. DB_LSN *lsnp; /* The lsn of the record being dispatched. */
  86. db_recops redo; /* Redo this op (or undo it). */
  87. void *info;
  88. {
  89. DB_LSN prev_lsn;
  90. u_int32_t rectype, txnid;
  91. int make_call, ret;
  92. memcpy(&rectype, db->data, sizeof(rectype));
  93. memcpy(&txnid, (u_int8_t *)db->data + sizeof(rectype), sizeof(txnid));
  94. make_call = ret = 0;
  95. /* If we don't have a dispatch table, it's hard to dispatch. */
  96. DB_ASSERT(dtab != NULL);
  97. /*
  98.  * If we find a record that is in the user's number space and they
  99.  * have specified a recovery routine, let them handle it.  If they
  100.  * didn't specify a recovery routine, then we expect that they've
  101.  * followed all our rules and registered new recovery functions.
  102.  */
  103. switch (redo) {
  104. case DB_TXN_ABORT:
  105. case DB_TXN_APPLY:
  106. case DB_TXN_PRINT:
  107. make_call = 1;
  108. break;
  109. case DB_TXN_OPENFILES:
  110. /*
  111.  * We collect all the transactions that have
  112.  * "begin" records, those with no previous LSN,
  113.  * so that we do not abort partial transactions.
  114.  * These are known to be undone, otherwise the
  115.  * log would not have been freeable.
  116.  */
  117. memcpy(&prev_lsn, (u_int8_t *)db->data +
  118.     sizeof(rectype) + sizeof(txnid), sizeof(prev_lsn));
  119. if (txnid != 0 && prev_lsn.file == 0 && (ret =
  120.     __db_txnlist_add(dbenv, info, txnid, TXN_OK, NULL)) != 0)
  121. return (ret);
  122. /* FALLTHROUGH */
  123. case DB_TXN_POPENFILES:
  124. if (rectype == DB___dbreg_register ||
  125.     rectype == DB___txn_ckp || rectype == DB___txn_recycle)
  126. return (dtab[rectype](dbenv, db, lsnp, redo, info));
  127. break;
  128. case DB_TXN_BACKWARD_ROLL:
  129. /*
  130.  * Running full recovery in the backward pass.  If we've
  131.  * seen this txnid before and added to it our commit list,
  132.  * then we do nothing during this pass, unless this is a child
  133.  * commit record, in which case we need to process it.  If
  134.  * we've never seen it, then we call the appropriate recovery
  135.  * routine.
  136.  *
  137.  * We need to always undo DB___db_noop records, so that we
  138.  * properly handle any aborts before the file was closed.
  139.  */
  140. switch(rectype) {
  141. case DB___txn_regop:
  142. case DB___txn_recycle:
  143. case DB___txn_ckp:
  144. case DB___db_noop:
  145. case DB___fop_file_remove:
  146. case DB___txn_child:
  147. make_call = 1;
  148. break;
  149. case DB___dbreg_register:
  150. if (txnid == 0) {
  151. make_call = 1;
  152. break;
  153. }
  154. /* FALLTHROUGH */
  155. default:
  156. if (txnid != 0 && (ret =
  157.     __db_txnlist_find(dbenv,
  158.     info, txnid)) != TXN_COMMIT && ret != TXN_IGNORE) {
  159. /*
  160.  * If not found then, this is an incomplete
  161.  * abort.
  162.  */
  163. if (ret == TXN_NOTFOUND)
  164. return (__db_txnlist_add(dbenv,
  165.     info, txnid, TXN_IGNORE, lsnp));
  166. make_call = 1;
  167. if (ret == TXN_OK &&
  168.     (ret = __db_txnlist_update(dbenv,
  169.     info, txnid,
  170.     rectype == DB___txn_xa_regop ?
  171.     TXN_PREPARE : TXN_ABORT, NULL)) != 0)
  172. return (ret);
  173. }
  174. }
  175. break;
  176. case DB_TXN_FORWARD_ROLL:
  177. /*
  178.  * In the forward pass, if we haven't seen the transaction,
  179.  * do nothing, else recover it.
  180.  *
  181.  * We need to always redo DB___db_noop records, so that we
  182.  * properly handle any commits after the file was closed.
  183.  */
  184. switch(rectype) {
  185. case DB___txn_recycle:
  186. case DB___txn_ckp:
  187. case DB___db_noop:
  188. make_call = 1;
  189. break;
  190. default:
  191. if (txnid != 0 && (ret = __db_txnlist_find(dbenv,
  192.     info, txnid)) == TXN_COMMIT)
  193. make_call = 1;
  194. else if (ret != TXN_IGNORE &&
  195.     (rectype == DB___ham_metagroup ||
  196.     rectype == DB___ham_groupalloc ||
  197.     rectype == DB___db_pg_alloc)) {
  198. /*
  199.  * Because we cannot undo file extensions
  200.  * all allocation records must be reprocessed
  201.  * during rollforward in case the file was
  202.  * just created.  It may not have been
  203.  * present during the backward pass.
  204.  */
  205. make_call = 1;
  206. redo = DB_TXN_BACKWARD_ALLOC;
  207. } else if (rectype == DB___dbreg_register) {
  208. /*
  209.  * This may be a transaction dbreg_register.
  210.  * If it is, we only make the call on a COMMIT,
  211.  * which we checked above. If it's not, then we
  212.  * should always make the call, because we need
  213.  * the file open information.
  214.  */
  215. if (txnid == 0)
  216. make_call = 1;
  217. }
  218. }
  219. break;
  220. case DB_TXN_GETPGNOS:
  221. /*
  222.  * If this is one of DB's own log records, we simply
  223.  * dispatch.
  224.  */
  225. if (rectype < DB_user_BEGIN) {
  226. make_call = 1;
  227. break;
  228. }
  229. /*
  230.  * If we're still here, this is a custom record in an
  231.  * application that's doing app-specific logging.  Such a
  232.  * record doesn't have a getpgno function for the user
  233.  * dispatch function to call--the getpgnos functions return
  234.  * which pages replication needs to lock using the TXN_RECS
  235.  * structure, which is private and not something we want to
  236.  * document.
  237.  *
  238.  * Thus, we leave any necessary locking for the app's
  239.  * recovery function to do during the upcoming
  240.  * DB_TXN_APPLY.  Fill in default getpgnos info (we need
  241.  * a stub entry for every log record that will get
  242.  * DB_TXN_APPLY'd) and return success.
  243.  */
  244. return (__db_default_getpgnos(dbenv, lsnp, info));
  245. default:
  246. return (__db_unknown_flag(dbenv, "__db_dispatch", redo));
  247. }
  248. /*
  249.  * The switch statement uses ret to receive the return value of
  250.  * __db_txnlist_find, which returns a large number of different
  251.  * statuses, none of which we will be returning.  For safety,
  252.  * let's reset this here in case we ever do a "return(ret)"
  253.  * below in the future.
  254.  */
  255. ret = 0;
  256. if (make_call) {
  257. if (rectype >= DB_user_BEGIN && dbenv->app_dispatch != NULL)
  258. return (dbenv->app_dispatch(dbenv, db, lsnp, redo));
  259. else {
  260. /*
  261.  * The size of the dtab table argument is the same as
  262.  * the standard table, use the standard table's size
  263.  * as our sanity check.
  264.  */
  265. if (rectype > dtabsize || dtab[rectype] == NULL) {
  266. __db_err(dbenv,
  267.     "Illegal record type %lu in log",
  268.     (u_long)rectype);
  269. return (EINVAL);
  270. }
  271. return (dtab[rectype](dbenv, db, lsnp, redo, info));
  272. }
  273. }
  274. return (0);
  275. }
  276. /*
  277.  * __db_add_recovery --
  278.  *
  279.  * PUBLIC: int __db_add_recovery __P((DB_ENV *,
  280.  * PUBLIC:   int (***)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), size_t *,
  281.  * PUBLIC:   int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), u_int32_t));
  282.  */
  283. int
  284. __db_add_recovery(dbenv, dtab, dtabsize, func, ndx)
  285. DB_ENV *dbenv;
  286. int (***dtab) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  287. size_t *dtabsize;
  288. int (*func) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  289. u_int32_t ndx;
  290. {
  291. size_t i, nsize;
  292. int ret;
  293. /* Check if we have to grow the table. */
  294. if (ndx >= *dtabsize) {
  295. nsize = ndx + 40;
  296. if ((ret =
  297.     __os_realloc(dbenv, nsize * sizeof((*dtab)[0]), dtab)) != 0)
  298. return (ret);
  299. for (i = *dtabsize; i < nsize; ++i)
  300. (*dtab)[i] = NULL;
  301. *dtabsize = nsize;
  302. }
  303. (*dtab)[ndx] = func;
  304. return (0);
  305. }
  306. /*
  307.  * __db_txnlist_init --
  308.  * Initialize transaction linked list.
  309.  *
  310.  * PUBLIC: int __db_txnlist_init __P((DB_ENV *,
  311.  * PUBLIC:     u_int32_t, u_int32_t, DB_LSN *, void *));
  312.  */
  313. int
  314. __db_txnlist_init(dbenv, low_txn, hi_txn, trunc_lsn, retp)
  315. DB_ENV *dbenv;
  316. u_int32_t low_txn, hi_txn;
  317. DB_LSN *trunc_lsn;
  318. void *retp;
  319. {
  320. DB_TXNHEAD *headp;
  321. u_int32_t tmp;
  322. int ret, size;
  323. /*
  324.  * Size a hash table.
  325.  * If low is zero then we are being called during rollback
  326.  * and we need only one slot.
  327.  * Hi maybe lower than low if we have recycled txnid's.
  328.  * The numbers here are guesses about txn density, we can afford
  329.  * to look at a few entries in each slot.
  330.  */
  331. if (low_txn == 0)
  332. size = 1;
  333. else {
  334. if (hi_txn < low_txn) {
  335. tmp = hi_txn;
  336. hi_txn = low_txn;
  337. low_txn = tmp;
  338. }
  339. tmp = hi_txn - low_txn;
  340. /* See if we wrapped around. */
  341. if (tmp > (TXN_MAXIMUM - TXN_MINIMUM) / 2)
  342. tmp = (low_txn - TXN_MINIMUM) + (TXN_MAXIMUM - hi_txn);
  343. size = tmp / 5;
  344. if (size < 100)
  345. size = 100;
  346. }
  347. if ((ret = __os_malloc(dbenv,
  348.     sizeof(DB_TXNHEAD) + size * sizeof(headp->head), &headp)) != 0)
  349. return (ret);
  350. memset(headp, 0, sizeof(DB_TXNHEAD) + size * sizeof(headp->head));
  351. headp->maxid = hi_txn;
  352. headp->generation = 0;
  353. headp->nslots = size;
  354. headp->gen_alloc = 8;
  355. if ((ret = __os_malloc(dbenv, headp->gen_alloc *
  356.     sizeof(headp->gen_array[0]), &headp->gen_array)) != 0) {
  357. __os_free(dbenv, headp);
  358. return (ret);
  359. }
  360. headp->gen_array[0].generation = 0;
  361. headp->gen_array[0].txn_min = TXN_MINIMUM;
  362. headp->gen_array[0].txn_max = TXN_MAXIMUM;
  363. if (trunc_lsn != NULL)
  364. headp->trunc_lsn = *trunc_lsn;
  365. else
  366. ZERO_LSN(headp->trunc_lsn);
  367. ZERO_LSN(headp->maxlsn);
  368. ZERO_LSN(headp->ckplsn);
  369. *(void **)retp = headp;
  370. return (0);
  371. }
  372. /*
  373.  * __db_txnlist_add --
  374.  * Add an element to our transaction linked list.
  375.  *
  376.  * PUBLIC: int __db_txnlist_add __P((DB_ENV *,
  377.  * PUBLIC:     void *, u_int32_t, int32_t, DB_LSN *));
  378.  */
  379. int
  380. __db_txnlist_add(dbenv, listp, txnid, status, lsn)
  381. DB_ENV *dbenv;
  382. void *listp;
  383. u_int32_t txnid;
  384. int32_t status;
  385. DB_LSN *lsn;
  386. {
  387. DB_TXNHEAD *hp;
  388. DB_TXNLIST *elp;
  389. int ret;
  390. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0)
  391. return (ret);
  392. hp = (DB_TXNHEAD *)listp;
  393. LIST_INSERT_HEAD(&hp->head[DB_TXNLIST_MASK(hp, txnid)], elp, links);
  394. elp->type = TXNLIST_TXNID;
  395. elp->u.t.txnid = txnid;
  396. elp->u.t.status = status;
  397. elp->u.t.generation = hp->generation;
  398. if (txnid > hp->maxid)
  399. hp->maxid = txnid;
  400. if (lsn != NULL && IS_ZERO_LSN(hp->maxlsn) && status == TXN_COMMIT)
  401. hp->maxlsn = *lsn;
  402. DB_ASSERT(lsn == NULL ||
  403.     status != TXN_COMMIT || log_compare(&hp->maxlsn, lsn) >= 0);
  404. return (0);
  405. }
  406. /*
  407.  * __db_txnlist_remove --
  408.  * Remove an element from our transaction linked list.
  409.  *
  410.  * PUBLIC: int __db_txnlist_remove __P((DB_ENV *, void *, u_int32_t));
  411.  */
  412. int
  413. __db_txnlist_remove(dbenv, listp, txnid)
  414. DB_ENV *dbenv;
  415. void *listp;
  416. u_int32_t txnid;
  417. {
  418. DB_TXNLIST *entry;
  419. return (__db_txnlist_find_internal(dbenv,
  420.     listp, TXNLIST_TXNID, txnid,
  421.     NULL, &entry, 1) == TXN_NOTFOUND ? TXN_NOTFOUND : TXN_OK);
  422. }
  423. /*
  424.  * __db_txnlist_ckp --
  425.  * Used to record the maximum checkpoint that will be retained
  426.  * after recovery.  Typically this is simply the max checkpoint, but
  427.  * if we are doing client replication recovery or timestamp-based
  428.  * recovery, we are going to virtually truncate the log and we need
  429.  * to retain the last checkpoint before the truncation point.
  430.  *
  431.  * PUBLIC: void __db_txnlist_ckp __P((DB_ENV *, void *, DB_LSN *));
  432.  */
  433. void
  434. __db_txnlist_ckp(dbenv, listp, ckp_lsn)
  435. DB_ENV *dbenv;
  436. void *listp;
  437. DB_LSN *ckp_lsn;
  438. {
  439. DB_TXNHEAD *hp;
  440. COMPQUIET(dbenv, NULL);
  441. hp = (DB_TXNHEAD *)listp;
  442. if (IS_ZERO_LSN(hp->ckplsn) && !IS_ZERO_LSN(hp->maxlsn) &&
  443.     log_compare(&hp->maxlsn, ckp_lsn) >= 0)
  444. hp->ckplsn = *ckp_lsn;
  445. }
  446. /*
  447.  * __db_txnlist_end --
  448.  * Discard transaction linked list. Print out any error messages
  449.  * for deleted files.
  450.  *
  451.  * PUBLIC: void __db_txnlist_end __P((DB_ENV *, void *));
  452.  */
  453. void
  454. __db_txnlist_end(dbenv, listp)
  455. DB_ENV *dbenv;
  456. void *listp;
  457. {
  458. DB_TXNHEAD *hp;
  459. DB_TXNLIST *p;
  460. int i;
  461. if ((hp = (DB_TXNHEAD *)listp) == NULL)
  462. return;
  463. for (i = 0; i < hp->nslots; i++)
  464. while (hp != NULL && (p = LIST_FIRST(&hp->head[i])) != NULL) {
  465. LIST_REMOVE(p, links);
  466. switch (p->type) {
  467. case TXNLIST_LSN:
  468. __os_free(dbenv, p->u.l.lsn_array);
  469. break;
  470. default:
  471. /*
  472.  * Possibly an incomplete DB_TXNLIST; just
  473.  * free it.
  474.  */
  475. break;
  476. }
  477. __os_free(dbenv, p);
  478. }
  479. if (hp->gen_array != NULL)
  480. __os_free(dbenv, hp->gen_array);
  481. __os_free(dbenv, listp);
  482. }
  483. /*
  484.  * __db_txnlist_find --
  485.  * Checks to see if a txnid with the current generation is in the
  486.  * txnid list.  This returns TXN_NOTFOUND if the item isn't in the
  487.  * list otherwise it returns (like __db_txnlist_find_internal)
  488.  * the status of the transaction.  A txnid of 0 means the record
  489.  * was generated while not in a transaction.
  490.  *
  491.  * PUBLIC: int __db_txnlist_find __P((DB_ENV *, void *, u_int32_t));
  492.  */
  493. int
  494. __db_txnlist_find(dbenv, listp, txnid)
  495. DB_ENV *dbenv;
  496. void *listp;
  497. u_int32_t txnid;
  498. {
  499. DB_TXNLIST *entry;
  500. if (txnid == 0)
  501. return (TXN_NOTFOUND);
  502. return (__db_txnlist_find_internal(dbenv, listp,
  503.     TXNLIST_TXNID, txnid, NULL, &entry, 0));
  504. }
  505. /*
  506.  * __db_txnlist_update --
  507.  * Change the status of an existing transaction entry.
  508.  * Returns TXN_NOTFOUND if no such entry exists.
  509.  *
  510.  * PUBLIC: int __db_txnlist_update __P((DB_ENV *,
  511.  * PUBLIC:     void *, u_int32_t, u_int32_t, DB_LSN *));
  512.  */
  513. int
  514. __db_txnlist_update(dbenv, listp, txnid, status, lsn)
  515. DB_ENV *dbenv;
  516. void *listp;
  517. u_int32_t txnid;
  518. u_int32_t status;
  519. DB_LSN *lsn;
  520. {
  521. DB_TXNHEAD *hp;
  522. DB_TXNLIST *elp;
  523. int ret;
  524. if (txnid == 0)
  525. return (TXN_NOTFOUND);
  526. hp = (DB_TXNHEAD *)listp;
  527. ret = __db_txnlist_find_internal(dbenv,
  528.     listp, TXNLIST_TXNID, txnid, NULL, &elp, 0);
  529. if (ret == TXN_NOTFOUND)
  530. return (ret);
  531. elp->u.t.status = status;
  532. if (lsn != NULL && IS_ZERO_LSN(hp->maxlsn) && status == TXN_COMMIT)
  533. hp->maxlsn = *lsn;
  534. return (ret);
  535. }
  536. /*
  537.  * __db_txnlist_find_internal --
  538.  * Find an entry on the transaction list.  If the entry is not there or
  539.  * the list pointer is not initialized we return TXN_NOTFOUND.  If the
  540.  * item is found, we return the status.  Currently we always call this
  541.  * with an initialized list pointer but checking for NULL keeps it general.
  542.  */
  543. static int
  544. __db_txnlist_find_internal(dbenv, listp, type, txnid, uid, txnlistp, delete)
  545. DB_ENV *dbenv;
  546. void *listp;
  547. db_txnlist_type type;
  548. u_int32_t  txnid;
  549. u_int8_t uid[DB_FILE_ID_LEN];
  550. DB_TXNLIST **txnlistp;
  551. int delete;
  552. {
  553. DB_TXNHEAD *hp;
  554. DB_TXNLIST *p;
  555. int32_t generation;
  556. u_int32_t hash;
  557. struct __db_headlink *head;
  558. int i, ret;
  559. if ((hp = (DB_TXNHEAD *)listp) == NULL)
  560. return (TXN_NOTFOUND);
  561. switch (type) {
  562. case TXNLIST_TXNID:
  563. hash = txnid;
  564. /* Find the most recent generation containing this ID */
  565. for (i = 0; i <= hp->generation; i++)
  566. /* The range may wrap around the end. */
  567. if (hp->gen_array[i].txn_min <
  568.     hp->gen_array[i].txn_max ?
  569.     (txnid >= hp->gen_array[i].txn_min &&
  570.     txnid <= hp->gen_array[i].txn_max) :
  571.     (txnid >= hp->gen_array[i].txn_min ||
  572.     txnid <= hp->gen_array[i].txn_max))
  573. break;
  574. DB_ASSERT(i <= hp->generation);
  575. generation = hp->gen_array[i].generation;
  576. break;
  577. case TXNLIST_PGNO:
  578. memcpy(&hash, uid, sizeof(hash));
  579. generation = 0;
  580. break;
  581. default:
  582. DB_ASSERT(0);
  583. return (EINVAL);
  584. }
  585. head = &hp->head[DB_TXNLIST_MASK(hp, hash)];
  586. for (p = LIST_FIRST(head); p != NULL; p = LIST_NEXT(p, links)) {
  587. if (p->type != type)
  588. continue;
  589. switch (type) {
  590. case TXNLIST_TXNID:
  591. if (p->u.t.txnid != txnid ||
  592.     generation != p->u.t.generation)
  593. continue;
  594. ret = p->u.t.status;
  595. break;
  596. case TXNLIST_PGNO:
  597. if (memcmp(uid, p->u.p.uid, DB_FILE_ID_LEN) != 0)
  598. continue;
  599. ret = 0;
  600. break;
  601. default:
  602. DB_ASSERT(0);
  603. ret = EINVAL;
  604. }
  605. if (delete == 1) {
  606. LIST_REMOVE(p, links);
  607. __os_free(dbenv, p);
  608. } else if (p != LIST_FIRST(head)) {
  609. /* Move it to head of list. */
  610. LIST_REMOVE(p, links);
  611. LIST_INSERT_HEAD(head, p, links);
  612. }
  613. *txnlistp = p;
  614. return (ret);
  615. }
  616. return (TXN_NOTFOUND);
  617. }
  618. /*
  619.  * __db_txnlist_gen --
  620.  * Change the current generation number.
  621.  *
  622.  * PUBLIC: int __db_txnlist_gen __P((DB_ENV *,
  623.  * PUBLIC:       void *, int, u_int32_t, u_int32_t));
  624.  */
  625. int
  626. __db_txnlist_gen(dbenv, listp, incr, min, max)
  627. DB_ENV *dbenv;
  628. void *listp;
  629. int incr;
  630. u_int32_t min, max;
  631. {
  632. DB_TXNHEAD *hp;
  633. int ret;
  634. /*
  635.  * During recovery generation numbers keep track of "restart"
  636.  * checkpoints and recycle records.  Restart checkpoints occur
  637.  * whenever we take a checkpoint and there are no outstanding
  638.  * transactions.  When that happens, we can reset transaction IDs
  639.  * back to TXNID_MINIMUM.  Currently we only do the reset
  640.  * at then end of recovery.  Recycle records occrur when txnids
  641.  * are exhausted during runtime.  A free range of ids is identified
  642.  * and logged.  This code maintains a stack of ranges.  A txnid
  643.  * is given the generation number of the first range it falls into
  644.  * in the stack.
  645.  */
  646. hp = (DB_TXNHEAD *)listp;
  647. hp->generation += incr;
  648. if (incr < 0)
  649. memmove(hp->gen_array, &hp->gen_array[1],
  650.     (hp->generation + 1) * sizeof(hp->gen_array[0]));
  651. else {
  652. if (hp->generation >= hp->gen_alloc) {
  653. hp->gen_alloc *= 2;
  654. if ((ret = __os_realloc(dbenv, hp->gen_alloc *
  655.     sizeof(hp->gen_array[0]), &hp->gen_array)) != 0)
  656. return (ret);
  657. }
  658. memmove(&hp->gen_array[1], &hp->gen_array[0],
  659.     hp->generation * sizeof(hp->gen_array[0]));
  660. hp->gen_array[0].generation = hp->generation;
  661. hp->gen_array[0].txn_min = min;
  662. hp->gen_array[0].txn_max = max;
  663. }
  664. return (0);
  665. }
  666. #define TXN_BUBBLE(AP, MAX) {
  667. int __j;
  668. DB_LSN __tmp;
  669. for (__j = 0; __j < MAX - 1; __j++)
  670. if (log_compare(&AP[__j], &AP[__j + 1]) < 0) {
  671. __tmp = AP[__j];
  672. AP[__j] = AP[__j + 1];
  673. AP[__j + 1] = __tmp;
  674. }
  675. }
  676. /*
  677.  * __db_txnlist_lsnadd --
  678.  * Add to or re-sort the transaction list lsn entry.  Note that since this
  679.  * is used during an abort, the __txn_undo code calls into the "recovery"
  680.  * subsystem explicitly, and there is only a single TXNLIST_LSN entry on
  681.  * the list.
  682.  *
  683.  * PUBLIC: int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t));
  684.  */
  685. int
  686. __db_txnlist_lsnadd(dbenv, listp, lsnp, flags)
  687. DB_ENV *dbenv;
  688. void *listp;
  689. DB_LSN *lsnp;
  690. u_int32_t flags;
  691. {
  692. DB_TXNHEAD *hp;
  693. DB_TXNLIST *elp;
  694. int i, ret;
  695. hp = (DB_TXNHEAD *)listp;
  696. for (elp = LIST_FIRST(&hp->head[0]);
  697.     elp != NULL; elp = LIST_NEXT(elp, links))
  698. if (elp->type == TXNLIST_LSN)
  699. break;
  700. if (elp == NULL)
  701. return (DB_SURPRISE_KID);
  702. if (LF_ISSET(TXNLIST_NEW)) {
  703. if (elp->u.l.ntxns >= elp->u.l.maxn) {
  704. if ((ret = __os_realloc(dbenv,
  705.     2 * elp->u.l.maxn * sizeof(DB_LSN),
  706.     &elp->u.l.lsn_array)) != 0)
  707. return (ret);
  708. elp->u.l.maxn *= 2;
  709. }
  710. elp->u.l.lsn_array[elp->u.l.ntxns++] = *lsnp;
  711. } else
  712. /* Simply replace the 0th element. */
  713. elp->u.l.lsn_array[0] = *lsnp;
  714. /*
  715.  * If we just added a new entry and there may be NULL entries, so we
  716.  * have to do a complete bubble sort, not just trickle a changed entry
  717.  * around.
  718.  */
  719. for (i = 0; i < (!LF_ISSET(TXNLIST_NEW) ? 1 : elp->u.l.ntxns); i++)
  720. TXN_BUBBLE(elp->u.l.lsn_array, elp->u.l.ntxns);
  721. *lsnp = elp->u.l.lsn_array[0];
  722. return (0);
  723. }
  724. /*
  725.  * __db_txnlist_lsninit --
  726.  * Initialize a transaction list with an lsn array entry.
  727.  *
  728.  * PUBLIC: int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *));
  729.  */
  730. int
  731. __db_txnlist_lsninit(dbenv, hp, lsnp)
  732. DB_ENV *dbenv;
  733. DB_TXNHEAD *hp;
  734. DB_LSN *lsnp;
  735. {
  736. DB_TXNLIST *elp;
  737. int ret;
  738. elp = NULL;
  739. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0)
  740. goto err;
  741. LIST_INSERT_HEAD(&hp->head[0], elp, links);
  742. if ((ret = __os_malloc(dbenv,
  743.     12 * sizeof(DB_LSN), &elp->u.l.lsn_array)) != 0)
  744. goto err;
  745. elp->type = TXNLIST_LSN;
  746. elp->u.l.maxn = 12;
  747. elp->u.l.ntxns = 1;
  748. elp->u.l.lsn_array[0] = *lsnp;
  749. return (0);
  750. err: __db_txnlist_end(dbenv, hp);
  751. return (ret);
  752. }
  753. /*
  754.  * __db_add_limbo -- add pages to the limbo list.
  755.  * Get the file information and call pgnoadd for each page.
  756.  *
  757.  * PUBLIC: int __db_add_limbo __P((DB_ENV *,
  758.  * PUBLIC:      void *, int32_t, db_pgno_t, int32_t));
  759.  */
  760. int
  761. __db_add_limbo(dbenv, info, fileid, pgno, count)
  762. DB_ENV *dbenv;
  763. void *info;
  764. int32_t fileid;
  765. db_pgno_t pgno;
  766. int32_t count;
  767. {
  768. DB_LOG *dblp;
  769. FNAME *fnp;
  770. int ret;
  771. dblp = dbenv->lg_handle;
  772. if ((ret = __dbreg_id_to_fname(dblp, fileid, 0, &fnp)) != 0)
  773. return (ret);
  774. do {
  775. if ((ret =
  776.     __db_txnlist_pgnoadd(dbenv, info, fileid, fnp->ufid,
  777.     R_ADDR(&dblp->reginfo, fnp->name_off), pgno)) != 0)
  778. return (ret);
  779. pgno++;
  780. } while (--count != 0);
  781. return (0);
  782. }
  783. /*
  784.  * __db_do_the_limbo -- move pages from limbo to free.
  785.  *
  786.  * Limbo processing is what ensures that we correctly handle and
  787.  * recover from page allocations.  During recovery, for each database,
  788.  * we process each in-question allocation, link them into the free list
  789.  * and then write out the new meta-data page that contains the pointer
  790.  * to the new beginning of the free list.  On an abort, we use our
  791.  * standard __db_free mechanism in a compensating transaction which logs
  792.  * the specific modifications to the free list.
  793.  *
  794.  * If we run out of log space during an abort, then we can't write the
  795.  * compensating transaction, so we abandon the idea of a compenating
  796.  * transaction, and go back to processing how we do during recovery.
  797.  * The reason that this is not the norm is that it's expensive: it requires
  798.  * that we flush any database with an in-question allocation.  Thus if
  799.  * a compensating transaction fails, we never try to restart it.
  800.  *
  801.  * Since files may be open and closed within transactions (in particular,
  802.  * the master database for subdatabases), we must be prepared to open
  803.  * files during this process.  If there is a compensating transaction, we
  804.  * can open the files in that transaction.  If this was an abort and there
  805.  * is no compensating transaction, then we've got to perform these opens
  806.  * in the context of the aborting transaction so that we do not deadlock.
  807.  * During recovery, there's no locking, so this isn't an issue.
  808.  *
  809.  * What you want to keep in mind when reading this is that there are two
  810.  * algorithms going on here:  ctxn == NULL, then we're either in recovery
  811.  * or our compensating transaction has failed and we're doing the
  812.  * "create list and write meta-data page" algorithm.  Otherwise, we're in
  813.  * an abort and doing the "use compensating transaction" algorithm.
  814.  *
  815.  * PUBLIC: int __db_do_the_limbo __P((DB_ENV *,
  816.  * PUBLIC:     DB_TXN *, DB_TXN *, DB_TXNHEAD *));
  817.  */
  818. int
  819. __db_do_the_limbo(dbenv, ptxn, txn, hp)
  820. DB_ENV *dbenv;
  821. DB_TXN *ptxn, *txn;
  822. DB_TXNHEAD *hp;
  823. {
  824. DB_TXNLIST *elp;
  825. int h, ret;
  826. ret = 0;
  827. /*
  828.  * The slots correspond to hash buckets.  We've hashed the
  829.  * fileids into hash buckets and need to pick up all affected
  830.  * files. (There will only be a single slot for an abort.)
  831.  */
  832. for (h = 0; h < hp->nslots; h++) {
  833. if ((elp = LIST_FIRST(&hp->head[h])) == NULL)
  834. continue;
  835. if (ptxn != NULL) {
  836. if ((ret =
  837.     __db_limbo_move(dbenv, ptxn, txn, elp)) != 0)
  838. goto err;
  839. } else if ((ret = __db_limbo_bucket(dbenv, txn, elp)) != 0)
  840. goto err;
  841. }
  842. err: if (ret != 0) {
  843. __db_err(dbenv, "Fatal error in abort of an allocation");
  844. ret = __db_panic(dbenv, ret);
  845. }
  846. return (ret);
  847. }
  848. /* Limbo support routines. */
  849. /*
  850.  * __db_lock_move --
  851.  * Move a lock from child to parent.
  852.  */
  853. static int
  854. __db_lock_move(dbenv, fileid, pgno, mode, ptxn, txn)
  855. DB_ENV *dbenv;
  856. u_int8_t *fileid;
  857. db_pgno_t pgno;
  858. db_lockmode_t mode;
  859. DB_TXN *ptxn, *txn;
  860. {
  861. DBT lock_dbt;
  862. DB_LOCK lock;
  863. DB_LOCK_ILOCK lock_obj;
  864. DB_LOCKREQ req;
  865. int ret;
  866. lock_obj.pgno = pgno;
  867. memcpy(lock_obj.fileid, fileid, DB_FILE_ID_LEN);
  868. lock_obj.type = DB_PAGE_LOCK;
  869. memset(&lock_dbt, 0, sizeof(lock_dbt));
  870. lock_dbt.data = &lock_obj;
  871. lock_dbt.size = sizeof(lock_obj);
  872. if ((ret = dbenv->lock_get(dbenv,
  873.     txn->txnid, 0, &lock_dbt, mode, &lock)) == 0) {
  874. memset(&req, 0, sizeof(req));
  875. req.lock = lock;
  876. req.op = DB_LOCK_TRADE;
  877. ret = dbenv->lock_vec(dbenv, ptxn->txnid, 0, &req, 1, NULL);
  878. }
  879. return (ret);
  880. }
  881. /*
  882.  * __db_limbo_move
  883.  * Move just the metapage lock to the parent.
  884.  */
  885. static int
  886. __db_limbo_move(dbenv, ptxn, txn, elp)
  887. DB_ENV *dbenv;
  888. DB_TXN *ptxn, *txn;
  889. DB_TXNLIST *elp;
  890. {
  891. int ret;
  892. for (; elp != NULL; elp = LIST_NEXT(elp, links)) {
  893. if (elp->type != TXNLIST_PGNO || elp->u.p.locked == 1)
  894. continue;
  895. if ((ret = __db_lock_move(dbenv, elp->u.p.uid,
  896.     PGNO_BASE_MD, DB_LOCK_WRITE, ptxn, txn)) != 0)
  897. return (ret);
  898. elp->u.p.locked = 1;
  899. }
  900. return (0);
  901. }
  902. /*
  903.  * __db_limbo_bucket
  904.  * Perform limbo processing for a single hash bucket in the txnlist.
  905.  * txn is the transaction aborting in the case of an abort and ctxn is the
  906.  * compensating transaction.
  907.  */
  908. #define T_RESTORED(txn)       ((txn) != NULL && F_ISSET(txn, TXN_RESTORED))
  909. static int
  910. __db_limbo_bucket(dbenv, txn, elp)
  911. DB_ENV *dbenv;
  912. DB_TXN *txn;
  913. DB_TXNLIST *elp;
  914. {
  915. DB *dbp;
  916. DB_MPOOLFILE *mpf;
  917. DBMETA *meta;
  918. DB_TXN *ctxn, *t;
  919. db_pgno_t last_pgno, pgno;
  920. int dbp_created, in_retry, ret, t_ret;
  921. ctxn = NULL;
  922. in_retry = 0;
  923. meta = NULL;
  924. mpf = NULL;
  925. ret = 0;
  926. for (; elp != NULL; elp = LIST_NEXT(elp, links)) {
  927. if (elp->type != TXNLIST_PGNO)
  928. continue;
  929. retry: dbp_created = 0;
  930. /*
  931.  * Pick the transaction in which to potentially
  932.  * log compensations.
  933.  */
  934. if (!in_retry && !IS_RECOVERING(dbenv) && !T_RESTORED(txn)
  935.     && (ret = __txn_compensate_begin(dbenv, &ctxn)) != 0)
  936. return (ret);
  937. /*
  938.  * Either use the compensating transaction or
  939.  * the one passed in, which will be null if recovering.
  940.  */
  941. t = ctxn == NULL ? txn : ctxn;
  942. /* First try to get a dbp by fileid. */
  943. ret = __dbreg_id_to_db(dbenv, t, &dbp, elp->u.p.fileid, 0);
  944. /*
  945.  * File is being destroyed.  No need to worry about
  946.  * dealing with recovery of allocations.
  947.  */
  948. if (ret == DB_DELETED ||
  949.     (ret == 0 && F_ISSET(dbp, DB_AM_DISCARD)))
  950. goto next;
  951. if (ret != 0) {
  952. if ((ret = db_create(&dbp, dbenv, 0)) != 0)
  953. goto err;
  954. /*
  955.  * This tells the system not to lock, which is always
  956.  * OK, whether this is an abort or recovery.
  957.  */
  958. F_SET(dbp, DB_AM_COMPENSATE);
  959. dbp_created = 1;
  960. /* It is ok if the file is nolonger there. */
  961. dbp->type = DB_UNKNOWN;
  962. ret = __db_dbopen(dbp, t, elp->u.p.fname, NULL,
  963.     DB_ODDFILESIZE, __db_omode("rw----"), PGNO_BASE_MD);
  964. if (ret == ENOENT)
  965. goto next;
  966. }
  967. /*
  968.  * Verify that we are opening the same file that we were
  969.  * referring to when we wrote this log record.
  970.  */
  971. if (memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
  972. goto next;
  973. mpf = dbp->mpf;
  974. last_pgno = PGNO_INVALID;
  975. if (ctxn == NULL) {
  976. pgno = PGNO_BASE_MD;
  977. if ((ret =
  978.     mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
  979. goto err;
  980. last_pgno = meta->free;
  981. }
  982. ret = __db_limbo_fix(dbp, ctxn, elp, &last_pgno, meta);
  983. /*
  984.  * If we were doing compensating transactions, then we are
  985.  * going to hope this error was due to running out of space.
  986.  * We'll change modes (into the sync the file mode) and keep
  987.  * trying.  If we weren't doing compensating transactions,
  988.  * then this is a real error and we're sunk.
  989.  */
  990. if (ret != 0) {
  991. if (ret == DB_RUNRECOVERY || ctxn == NULL)
  992. goto err;
  993. in_retry = 1;
  994. goto retry;
  995. }
  996. if (ctxn != NULL) {
  997. ret = ctxn->commit(ctxn, DB_TXN_NOSYNC);
  998. ctxn = NULL;
  999. if (ret != 0)
  1000. goto retry;
  1001. goto next;
  1002. }
  1003. /*
  1004.  * This is where we handle the case where we're explicitly
  1005.  * putting together a free list.  We need to decide whether
  1006.  * we have to write the meta-data page, and if we do, then
  1007.  * we need to sync it as well.
  1008.  */
  1009. if (last_pgno == meta->free) {
  1010. /* No change to page; just put the page back. */
  1011. if ((ret = mpf->put(mpf, meta, 0)) != 0)
  1012. goto err;
  1013. meta = NULL;
  1014. } else {
  1015. /*
  1016.  * These changes are unlogged so we cannot have the
  1017.  * metapage pointing at pages that are not on disk.
  1018.  * Therefore, we flush the new free list, then update
  1019.  * the metapage.  We have to put the meta-data page
  1020.  * first so that it isn't pinned when we try to sync.
  1021.  */
  1022. if (!IS_RECOVERING(dbenv) && !T_RESTORED(txn))
  1023. __db_err(dbenv, "Flushing free list to disk");
  1024. if ((ret = mpf->put(mpf, meta, 0)) != 0)
  1025. goto err;
  1026. meta = NULL;
  1027. dbp->sync(dbp, 0);
  1028. pgno = PGNO_BASE_MD;
  1029. if ((ret =
  1030.     mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
  1031. goto err;
  1032. meta->free = last_pgno;
  1033. if ((ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY)) != 0)
  1034. goto err;
  1035. meta = NULL;
  1036. }
  1037. next:
  1038. /*
  1039.  * If we get here, either we have processed the list
  1040.  * or the db file has been deleted or could no be opened.
  1041.  */
  1042. if (ctxn != NULL &&
  1043.     (t_ret = ctxn->abort(ctxn)) != 0 && ret == 0)
  1044. ret = t_ret;
  1045. if (dbp_created &&
  1046.     (t_ret = __db_close_i(dbp, txn, 0)) != 0 && ret == 0)
  1047. ret = t_ret;
  1048. dbp = NULL;
  1049. __os_free(dbenv, elp->u.p.fname);
  1050. __os_free(dbenv, elp->u.p.pgno_array);
  1051. if (ret == ENOENT)
  1052. ret = 0;
  1053. else if (ret != 0)
  1054. goto err;
  1055. }
  1056. err: if (meta != NULL)
  1057. (void)mpf->put(mpf, meta, 0);
  1058. return (ret);
  1059. }
  1060. /*
  1061.  * __db_limbo_fix --
  1062.  * Process a single limbo entry which describes all the page allocations
  1063.  * for a single file.
  1064.  */
  1065. static int
  1066. __db_limbo_fix(dbp, ctxn, elp, lastp, meta)
  1067. DB *dbp;
  1068. DB_TXN *ctxn;
  1069. DB_TXNLIST *elp;
  1070. db_pgno_t *lastp;
  1071. DBMETA *meta;
  1072. {
  1073. DBC *dbc;
  1074. DB_MPOOLFILE *mpf;
  1075. PAGE *freep, *pagep;
  1076. db_pgno_t next, pgno;
  1077. int i, put_page, ret, t_ret;
  1078. /*
  1079.  * Loop through the entries for this txnlist element and
  1080.  * either link them into the free list or write a compensating
  1081.  * record for each.
  1082.  */
  1083. put_page = 0;
  1084. ret = 0;
  1085. mpf = dbp->mpf;
  1086. dbc = NULL;
  1087. for (i = 0; i < elp->u.p.nentries; i++) {
  1088. pgno = elp->u.p.pgno_array[i];
  1089. if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  1090. goto err;
  1091. put_page = 1;
  1092. if (IS_ZERO_LSN(LSN(pagep))) {
  1093. if (ctxn == NULL) {
  1094. /*
  1095.  * If this is a fatal recovery which
  1096.  * spans a previous crash this page may
  1097.  * be on the free list already.
  1098.  */
  1099. for (next = *lastp; next != 0; ) {
  1100. if (next == pgno)
  1101. break;
  1102. if ((ret = mpf->get(mpf,
  1103.     &next, 0, &freep)) != 0)
  1104. goto err;
  1105. next = NEXT_PGNO(freep);
  1106. if ((ret =
  1107.     mpf->put(mpf, freep, 0)) != 0)
  1108. goto err;
  1109. }
  1110. if (next != pgno) {
  1111. P_INIT(pagep, dbp->pgsize, pgno,
  1112.     PGNO_INVALID, *lastp, 0, P_INVALID);
  1113. LSN(pagep) = LSN(meta);
  1114. *lastp = pgno;
  1115. }
  1116. } else {
  1117. P_INIT(pagep, dbp->pgsize, pgno,
  1118.     PGNO_INVALID, *lastp, 0, P_INVALID);
  1119. if (dbc == NULL && (ret =
  1120.     dbp->cursor(dbp, ctxn, &dbc, 0)) != 0)
  1121. goto err;
  1122. /*
  1123.  * If the dbp is compensating (because we
  1124.  * opened it), the dbc will automatically be
  1125.  * marked compensating, but in case we didn't
  1126.  * do the open, we have to mark it explicitly.
  1127.  */
  1128. F_SET(dbc, DBC_COMPENSATE);
  1129. ret = __db_free(dbc, pagep);
  1130. put_page = 0;
  1131. /*
  1132.  * On any error, we hope that the error was
  1133.  * caused due to running out of space, and we
  1134.  * switch modes, doing the processing where we
  1135.  * sync out files instead of doing compensating
  1136.  * transactions.  If this was a real error and
  1137.  * not out of space, we assume that some other
  1138.  * call will fail real soon.
  1139.  */
  1140. if (ret != 0) {
  1141. /* Assume that this is out of space. */
  1142. (void)dbc->c_close(dbc);
  1143. dbc = NULL;
  1144. goto err;
  1145. }
  1146. }
  1147. }
  1148. if (put_page == 1) {
  1149. ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY);
  1150. put_page = 0;
  1151. }
  1152. if (ret != 0)
  1153. goto err;
  1154. }
  1155. err: if (put_page &&
  1156.     (t_ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0)
  1157. ret = t_ret;
  1158. if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  1159. ret = t_ret;
  1160. return (ret);
  1161. }
  1162. #define DB_TXNLIST_MAX_PGNO 8 /* A nice even number. */
  1163. /*
  1164.  * __db_txnlist_pgnoadd --
  1165.  * Find the txnlist entry for a file and add this pgno, or add the list
  1166.  * entry for the file and then add the pgno.
  1167.  */
  1168. static int
  1169. __db_txnlist_pgnoadd(dbenv, hp, fileid, uid, fname, pgno)
  1170. DB_ENV *dbenv;
  1171. DB_TXNHEAD *hp;
  1172. int32_t fileid;
  1173. u_int8_t uid[DB_FILE_ID_LEN];
  1174. char *fname;
  1175. db_pgno_t pgno;
  1176. {
  1177. DB_TXNLIST *elp;
  1178. u_int32_t hash;
  1179. int len, ret;
  1180. elp = NULL;
  1181. if (__db_txnlist_find_internal(dbenv, hp,
  1182.     TXNLIST_PGNO, 0, uid, &elp, 0) != 0) {
  1183. if ((ret =
  1184.     __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0)
  1185. goto err;
  1186. memcpy(&hash, uid, sizeof(hash));
  1187. LIST_INSERT_HEAD(
  1188.     &hp->head[DB_TXNLIST_MASK(hp, hash)], elp, links);
  1189. elp->u.p.fileid = fileid;
  1190. memcpy(elp->u.p.uid, uid, DB_FILE_ID_LEN);
  1191. len = (int)strlen(fname) + 1;
  1192. if ((ret = __os_malloc(dbenv, len, &elp->u.p.fname)) != 0)
  1193. goto err;
  1194. memcpy(elp->u.p.fname, fname, len);
  1195. elp->u.p.maxentry = 0;
  1196. elp->u.p.locked = 0;
  1197. elp->type = TXNLIST_PGNO;
  1198. if ((ret = __os_malloc(dbenv,
  1199.     8 * sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0)
  1200. goto err;
  1201. elp->u.p.maxentry = DB_TXNLIST_MAX_PGNO;
  1202. elp->u.p.nentries = 0;
  1203. } else if (elp->u.p.nentries == elp->u.p.maxentry) {
  1204. elp->u.p.maxentry <<= 1;
  1205. if ((ret = __os_realloc(dbenv, elp->u.p.maxentry *
  1206.     sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0)
  1207. goto err;
  1208. }
  1209. elp->u.p.pgno_array[elp->u.p.nentries++] = pgno;
  1210. return (0);
  1211. err: __db_txnlist_end(dbenv, hp);
  1212. return (ret);
  1213. }
  1214. /*
  1215.  * __db_default_getpgnos --
  1216.  * Fill in default getpgnos information for an application-specific
  1217.  * log record.
  1218.  */
  1219. static int
  1220. __db_default_getpgnos(dbenv, lsnp, summary)
  1221. DB_ENV *dbenv;
  1222. DB_LSN *lsnp;
  1223. void *summary;
  1224. {
  1225. TXN_RECS *t;
  1226. int ret;
  1227. t = (TXN_RECS *)summary;
  1228. if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0)
  1229. return (ret);
  1230. t->array[t->npages].flags = LSN_PAGE_NOLOCK;
  1231. t->array[t->npages].lsn = *lsnp;
  1232. t->array[t->npages].fid = DB_LOGFILEID_INVALID;
  1233. memset(&t->array[t->npages].pgdesc, 0,
  1234.     sizeof(t->array[t->npages].pgdesc));
  1235. t->npages++;
  1236. return (0);
  1237. }
  1238. #ifdef DEBUG
  1239. /*
  1240.  * __db_txnlist_print --
  1241.  * Print out the transaction list.
  1242.  *
  1243.  * PUBLIC: void __db_txnlist_print __P((void *));
  1244.  */
  1245. void
  1246. __db_txnlist_print(listp)
  1247. void *listp;
  1248. {
  1249. DB_TXNHEAD *hp;
  1250. DB_TXNLIST *p;
  1251. int i;
  1252. char *stats[] = { "ok", "commit", "prepare", "abort", "notfound",
  1253.     "ignore", "expected", "unexpected" };
  1254. hp = (DB_TXNHEAD *)listp;
  1255. printf("Maxid: %lu Generation: %lun",
  1256.     (u_long)hp->maxid, (u_long)hp->generation);
  1257. for (i = 0; i < hp->nslots; i++)
  1258. for (p = LIST_FIRST(&hp->head[i]); p != NULL; p = LIST_NEXT(p, links)) {
  1259. switch (p->type) {
  1260. case TXNLIST_TXNID:
  1261. printf("TXNID: %lx(%lu): %sn",
  1262.     (u_long)p->u.t.txnid, (u_long)p->u.t.generation,
  1263.     stats[p->u.t.status]);
  1264. break;
  1265. default:
  1266. printf("Unrecognized type: %dn", p->type);
  1267. break;
  1268. }
  1269. }
  1270. }
  1271. #endif