db_dispatch.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:24k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  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.41 2001/01/11 18:19:50 bostic 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 "db_page.h"
  50. #include "db_dispatch.h"
  51. #include "db_am.h"
  52. #include "log_auto.h"
  53. #include "txn.h"
  54. #include "txn_auto.h"
  55. #include "log.h"
  56. static int __db_txnlist_find_internal __P((void *, db_txnlist_type,
  57.      u_int32_t, u_int8_t [DB_FILE_ID_LEN], DB_TXNLIST **, int));
  58. /*
  59.  * __db_dispatch --
  60.  *
  61.  * This is the transaction dispatch function used by the db access methods.
  62.  * It is designed to handle the record format used by all the access
  63.  * methods (the one automatically generated by the db_{h,log,read}.sh
  64.  * scripts in the tools directory).  An application using a different
  65.  * recovery paradigm will supply a different dispatch function to txn_open.
  66.  *
  67.  * PUBLIC: int __db_dispatch __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  68.  */
  69. int
  70. __db_dispatch(dbenv, db, lsnp, redo, info)
  71. DB_ENV *dbenv; /* The environment. */
  72. DBT *db; /* The log record upon which to dispatch. */
  73. DB_LSN *lsnp; /* The lsn of the record being dispatched. */
  74. db_recops redo; /* Redo this op (or undo it). */
  75. void *info;
  76. {
  77. u_int32_t rectype, txnid;
  78. int make_call, ret;
  79. memcpy(&rectype, db->data, sizeof(rectype));
  80. memcpy(&txnid, (u_int8_t *)db->data + sizeof(rectype), sizeof(txnid));
  81. make_call = ret = 0;
  82. /*
  83.  * If we find a record that is in the user's number space and they
  84.  * have specified a recovery routine, let them handle it.  If they
  85.  * didn't specify a recovery routine, then we expect that they've
  86.  * followed all our rules and registered new recovery functions.
  87.  */
  88. switch (redo) {
  89. case DB_TXN_ABORT:
  90. /*
  91.  * XXX
  92.  * db_printlog depends on DB_TXN_ABORT not examining the TXN
  93.  * list.  If that ever changes, fix db_printlog too.
  94.  */
  95. make_call = 1;
  96. break;
  97. case DB_TXN_OPENFILES:
  98. if (rectype == DB_log_register)
  99. return (dbenv->dtab[rectype](dbenv,
  100.     db, lsnp, redo, info));
  101. break;
  102. case DB_TXN_BACKWARD_ROLL:
  103. /*
  104.  * Running full recovery in the backward pass.  If we've
  105.  * seen this txnid before and added to it our commit list,
  106.  * then we do nothing during this pass, unless this is a child
  107.  * commit record, in which case we need to process it.  If
  108.  * we've never seen it, then we call the appropriate recovery
  109.  * routine.
  110.  *
  111.  * We need to always undo DB_db_noop records, so that we
  112.  * properly handle any aborts before the file was closed.
  113.  */
  114. if (rectype == DB_log_register ||
  115.     rectype == DB_txn_ckp || rectype == DB_db_noop
  116.     || rectype == DB_txn_child || (txnid != 0 &&
  117.     (ret = __db_txnlist_find(info, txnid)) != 0)) {
  118. make_call = 1;
  119. if (ret == DB_NOTFOUND && rectype != DB_txn_regop &&
  120.     rectype != DB_txn_xa_regop && (ret =
  121.     __db_txnlist_add(dbenv, info, txnid, 1)) != 0)
  122. return (ret);
  123. }
  124. break;
  125. case DB_TXN_FORWARD_ROLL:
  126. /*
  127.  * In the forward pass, if we haven't seen the transaction,
  128.  * do nothing, else recovery it.
  129.  *
  130.  * We need to always redo DB_db_noop records, so that we
  131.  * properly handle any commits after the file was closed.
  132.  */
  133. if (rectype == DB_log_register ||
  134.     rectype == DB_txn_ckp ||
  135.     rectype == DB_db_noop ||
  136.     __db_txnlist_find(info, txnid) == 0)
  137. make_call = 1;
  138. break;
  139. default:
  140. return (__db_unknown_flag(dbenv, "__db_dispatch", redo));
  141. }
  142. if (make_call) {
  143. if (rectype >= DB_user_BEGIN && dbenv->tx_recover != NULL)
  144. return (dbenv->tx_recover(dbenv, db, lsnp, redo));
  145. else
  146. return (dbenv->dtab[rectype](dbenv, db, lsnp, redo, info));
  147. }
  148. return (0);
  149. }
  150. /*
  151.  * __db_add_recovery --
  152.  *
  153.  * PUBLIC: int __db_add_recovery __P((DB_ENV *,
  154.  * PUBLIC:    int (*)(DB_ENV *, DBT *, DB_LSN *, db_recops, void *), u_int32_t));
  155.  */
  156. int
  157. __db_add_recovery(dbenv, func, ndx)
  158. DB_ENV *dbenv;
  159. int (*func) __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  160. u_int32_t ndx;
  161. {
  162. u_int32_t i, nsize;
  163. int ret;
  164. /* Check if we have to grow the table. */
  165. if (ndx >= dbenv->dtab_size) {
  166. nsize = ndx + 40;
  167. if ((ret = __os_realloc(dbenv,
  168.     nsize * sizeof(dbenv->dtab[0]), NULL, &dbenv->dtab)) != 0)
  169. return (ret);
  170. for (i = dbenv->dtab_size; i < nsize; ++i)
  171. dbenv->dtab[i] = NULL;
  172. dbenv->dtab_size = nsize;
  173. }
  174. dbenv->dtab[ndx] = func;
  175. return (0);
  176. }
  177. /*
  178.  * __deprecated_recover --
  179.  * Stub routine for deprecated recovery functions.
  180.  *
  181.  * PUBLIC: int __deprecated_recover
  182.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  183.  */
  184. int
  185. __deprecated_recover(dbenv, dbtp, lsnp, op, info)
  186. DB_ENV *dbenv;
  187. DBT *dbtp;
  188. DB_LSN *lsnp;
  189. db_recops op;
  190. void *info;
  191. {
  192. COMPQUIET(dbenv, NULL);
  193. COMPQUIET(dbtp, NULL);
  194. COMPQUIET(lsnp, NULL);
  195. COMPQUIET(op, 0);
  196. COMPQUIET(info, NULL);
  197. return (EINVAL);
  198. }
  199. /*
  200.  * __db_txnlist_init --
  201.  * Initialize transaction linked list.
  202.  *
  203.  * PUBLIC: int __db_txnlist_init __P((DB_ENV *, void *));
  204.  */
  205. int
  206. __db_txnlist_init(dbenv, retp)
  207. DB_ENV *dbenv;
  208. void *retp;
  209. {
  210. DB_TXNHEAD *headp;
  211. int ret;
  212. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNHEAD), NULL, &headp)) != 0)
  213. return (ret);
  214. LIST_INIT(&headp->head);
  215. headp->maxid = 0;
  216. headp->generation = 1;
  217. *(void **)retp = headp;
  218. return (0);
  219. }
  220. /*
  221.  * __db_txnlist_add --
  222.  * Add an element to our transaction linked list.
  223.  *
  224.  * PUBLIC: int __db_txnlist_add __P((DB_ENV *, void *, u_int32_t, int32_t));
  225.  */
  226. int
  227. __db_txnlist_add(dbenv, listp, txnid, aborted)
  228. DB_ENV *dbenv;
  229. void *listp;
  230. u_int32_t txnid;
  231. int32_t aborted;
  232. {
  233. DB_TXNHEAD *hp;
  234. DB_TXNLIST *elp;
  235. int ret;
  236. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0)
  237. return (ret);
  238. hp = (DB_TXNHEAD *)listp;
  239. LIST_INSERT_HEAD(&hp->head, elp, links);
  240. elp->type = TXNLIST_TXNID;
  241. elp->u.t.txnid = txnid;
  242. elp->u.t.aborted = aborted;
  243. if (txnid > hp->maxid)
  244. hp->maxid = txnid;
  245. elp->u.t.generation = hp->generation;
  246. return (0);
  247. }
  248. /*
  249.  * __db_txnlist_remove --
  250.  * Remove an element from our transaction linked list.
  251.  *
  252.  * PUBLIC: int __db_txnlist_remove __P((void *, u_int32_t));
  253.  */
  254. int
  255. __db_txnlist_remove(listp, txnid)
  256. void *listp;
  257. u_int32_t txnid;
  258. {
  259. DB_TXNLIST *entry;
  260. return (__db_txnlist_find_internal(listp,
  261.      TXNLIST_TXNID, txnid, NULL, &entry, 1));
  262. }
  263. /* __db_txnlist_close --
  264.  *
  265.  * Call this when we close a file.  It allows us to reconcile whether
  266.  * we have done any operations on this file with whether the file appears
  267.  * to have been deleted.  If you never do any operations on a file, then
  268.  * we assume it's OK to appear deleted.
  269.  *
  270.  * PUBLIC: int __db_txnlist_close __P((void *, int32_t, u_int32_t));
  271.  */
  272. int
  273. __db_txnlist_close(listp, lid, count)
  274. void *listp;
  275. int32_t lid;
  276. u_int32_t count;
  277. {
  278. DB_TXNHEAD *hp;
  279. DB_TXNLIST *p;
  280. hp = (DB_TXNHEAD *)listp;
  281. for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) {
  282. if (p->type == TXNLIST_DELETE)
  283. if (lid == p->u.d.fileid &&
  284.     !F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED)) {
  285. p->u.d.count += count;
  286. return (0);
  287. }
  288. }
  289. return (0);
  290. }
  291. /*
  292.  * __db_txnlist_delete --
  293.  *
  294.  * Record that a file was missing or deleted.  If the deleted
  295.  * flag is set, then we've encountered a delete of a file, else we've
  296.  * just encountered a file that is missing.  The lid is the log fileid
  297.  * and is only meaningful if deleted is not equal to 0.
  298.  *
  299.  * PUBLIC: int __db_txnlist_delete __P((DB_ENV *,
  300.  * PUBLIC:     void *, char *, u_int32_t, int));
  301.  */
  302. int
  303. __db_txnlist_delete(dbenv, listp, name, lid, deleted)
  304. DB_ENV *dbenv;
  305. void *listp;
  306. char *name;
  307. u_int32_t lid;
  308. int deleted;
  309. {
  310. DB_TXNHEAD *hp;
  311. DB_TXNLIST *p;
  312. int ret;
  313. hp = (DB_TXNHEAD *)listp;
  314. for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) {
  315. if (p->type == TXNLIST_DELETE)
  316. if (strcmp(name, p->u.d.fname) == 0) {
  317. if (deleted)
  318. F_SET(&p->u.d, TXNLIST_FLAG_DELETED);
  319. else
  320. F_CLR(&p->u.d, TXNLIST_FLAG_CLOSED);
  321. return (0);
  322. }
  323. }
  324. /* Need to add it. */
  325. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &p)) != 0)
  326. return (ret);
  327. LIST_INSERT_HEAD(&hp->head, p, links);
  328. p->type = TXNLIST_DELETE;
  329. p->u.d.flags = 0;
  330. if (deleted)
  331. F_SET(&p->u.d, TXNLIST_FLAG_DELETED);
  332. p->u.d.fileid = lid;
  333. p->u.d.count = 0;
  334. ret = __os_strdup(dbenv, name, &p->u.d.fname);
  335. return (ret);
  336. }
  337. /*
  338.  * __db_txnlist_end --
  339.  * Discard transaction linked list. Print out any error messages
  340.  * for deleted files.
  341.  *
  342.  * PUBLIC: void __db_txnlist_end __P((DB_ENV *, void *));
  343.  */
  344. void
  345. __db_txnlist_end(dbenv, listp)
  346. DB_ENV *dbenv;
  347. void *listp;
  348. {
  349. DB_TXNHEAD *hp;
  350. DB_TXNLIST *p;
  351. DB_LOG *lp;
  352. hp = (DB_TXNHEAD *)listp;
  353. lp = (DB_LOG *)dbenv->lg_handle;
  354. while (hp != NULL && (p = LIST_FIRST(&hp->head)) != NULL) {
  355. LIST_REMOVE(p, links);
  356. switch (p->type) {
  357. case TXNLIST_DELETE:
  358. /*
  359.  * If we have a file that is not deleted and has
  360.  * some operations, we flag the warning.  Since
  361.  * the file could still be open, we need to check
  362.  * the actual log table as well.
  363.  */
  364. if ((!F_ISSET(&p->u.d, TXNLIST_FLAG_DELETED) &&
  365.     p->u.d.count != 0) ||
  366.     (!F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED) &&
  367.     p->u.d.fileid != (int32_t) TXNLIST_INVALID_ID &&
  368.     p->u.d.fileid < lp->dbentry_cnt &&
  369.     lp->dbentry[p->u.d.fileid].count != 0))
  370. __db_err(dbenv, "warning: %s: %s",
  371.     p->u.d.fname, db_strerror(ENOENT));
  372. __os_freestr(p->u.d.fname);
  373. break;
  374. case TXNLIST_LSN:
  375. __os_free(p->u.l.lsn_array,
  376.     p->u.l.maxn * sizeof(DB_LSN));
  377. break;
  378. default:
  379. /* Possibly an incomplete DB_TXNLIST;  just free it. */
  380. break;
  381. }
  382. __os_free(p, sizeof(DB_TXNLIST));
  383. }
  384. __os_free(listp, sizeof(DB_TXNHEAD));
  385. }
  386. /*
  387.  * __db_txnlist_find --
  388.  * Checks to see if a txnid with the current generation is in the
  389.  * txnid list.  This returns DB_NOTFOUND if the item isn't in the
  390.  * list otherwise it returns (like __db_txnlist_find_internal) a
  391.  * 1 or 0 indicating if the transaction is aborted or not.  A txnid
  392.  * of 0 means the record was generated while not in a transaction.
  393.  *
  394.  * PUBLIC: int __db_txnlist_find __P((void *, u_int32_t));
  395.  */
  396. int
  397. __db_txnlist_find(listp, txnid)
  398. void *listp;
  399. u_int32_t txnid;
  400. {
  401. DB_TXNLIST *entry;
  402. if (txnid == 0)
  403. return (DB_NOTFOUND);
  404. return (__db_txnlist_find_internal(listp,
  405.      TXNLIST_TXNID, txnid, NULL, &entry, 0));
  406. }
  407. /*
  408.  * __db_txnlist_find_internal --
  409.  * Find an entry on the transaction list.
  410.  * If the entry is not there or the list pointeris not initialized
  411.  * we return DB_NOTFOUND.  If the item is found, we return the aborted
  412.  * status (1 for aborted, 0 for not aborted).  Currently we always call
  413.  * this with an initialized list pointer but checking for NULL keeps it general.
  414.  */
  415. static int
  416. __db_txnlist_find_internal(listp, type, txnid, uid, txnlistp, delete)
  417. void *listp;
  418. db_txnlist_type type;
  419. u_int32_t txnid;
  420. u_int8_t uid[DB_FILE_ID_LEN];
  421. DB_TXNLIST **txnlistp;
  422. int delete;
  423. {
  424. DB_TXNHEAD *hp;
  425. DB_TXNLIST *p;
  426. int ret;
  427. if ((hp = (DB_TXNHEAD *)listp) == NULL)
  428. return (DB_NOTFOUND);
  429. for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) {
  430. if (p->type != type)
  431. continue;
  432. switch (type) {
  433. case TXNLIST_TXNID:
  434. if (p->u.t.txnid != txnid ||
  435.     hp->generation != p->u.t.generation)
  436. continue;
  437. ret = p->u.t.aborted;
  438. break;
  439. case TXNLIST_PGNO:
  440. if (memcmp(uid, p->u.p.uid, DB_FILE_ID_LEN) != 0)
  441. continue;
  442. ret = 0;
  443. break;
  444. default:
  445. DB_ASSERT(0);
  446. ret = EINVAL;
  447. }
  448. if (delete == 1) {
  449. LIST_REMOVE(p, links);
  450. __os_free(p, sizeof(DB_TXNLIST));
  451. } else if (p != LIST_FIRST(&hp->head)) {
  452. /* Move it to head of list. */
  453. LIST_REMOVE(p, links);
  454. LIST_INSERT_HEAD(&hp->head, p, links);
  455. }
  456. *txnlistp = p;
  457. return (ret);
  458. }
  459. return (DB_NOTFOUND);
  460. }
  461. /*
  462.  * __db_txnlist_gen --
  463.  * Change the current generation number.
  464.  *
  465.  * PUBLIC: void __db_txnlist_gen __P((void *, int));
  466.  */
  467. void
  468. __db_txnlist_gen(listp, incr)
  469. void *listp;
  470. int incr;
  471. {
  472. DB_TXNHEAD *hp;
  473. /*
  474.  * During recovery generation numbers keep track of how many "restart"
  475.  * checkpoints we've seen.  Restart checkpoints occur whenever we take
  476.  * a checkpoint and there are no outstanding transactions.  When that
  477.  * happens, we can reset transaction IDs back to 1.  It always happens
  478.  * at recovery and it prevents us from exhausting the transaction IDs
  479.  * name space.
  480.  */
  481. hp = (DB_TXNHEAD *)listp;
  482. hp->generation += incr;
  483. }
  484. #define TXN_BUBBLE(AP, MAX) {
  485. int __j;
  486. DB_LSN __tmp;
  487. for (__j = 0; __j < MAX - 1; __j++)
  488. if (log_compare(&AP[__j], &AP[__j + 1]) < 0) {
  489. __tmp = AP[__j];
  490. AP[__j] = AP[__j + 1];
  491. AP[__j + 1] = __tmp;
  492. }
  493. }
  494. /*
  495.  * __db_txnlist_lsnadd --
  496.  * Add to or re-sort the transaction list lsn entry.
  497.  * Note that since this is used during an abort, the __txn_undo
  498.  * code calls into the "recovery" subsystem explicitly, and there
  499.  * is only a single TXNLIST_LSN entry on the list.
  500.  *
  501.  * PUBLIC: int __db_txnlist_lsnadd __P((DB_ENV *, void *, DB_LSN *, u_int32_t));
  502.  */
  503. int
  504. __db_txnlist_lsnadd(dbenv, listp, lsnp, flags)
  505. DB_ENV *dbenv;
  506. void *listp;
  507. DB_LSN *lsnp;
  508. u_int32_t flags;
  509. {
  510. DB_TXNHEAD *hp;
  511. DB_TXNLIST *elp;
  512. int i, ret;
  513. hp = (DB_TXNHEAD *)listp;
  514. for (elp = LIST_FIRST(&hp->head);
  515.     elp != NULL; elp = LIST_NEXT(elp, links))
  516. if (elp->type == TXNLIST_LSN)
  517. break;
  518. if (elp == NULL)
  519. return (EINVAL);
  520. if (LF_ISSET(TXNLIST_NEW)) {
  521. if (elp->u.l.ntxns >= elp->u.l.maxn) {
  522. if ((ret = __os_realloc(dbenv,
  523.     2 * elp->u.l.maxn * sizeof(DB_LSN),
  524.     NULL, &elp->u.l.lsn_array)) != 0)
  525. return (ret);
  526. elp->u.l.maxn *= 2;
  527. }
  528. elp->u.l.lsn_array[elp->u.l.ntxns++] = *lsnp;
  529. } else
  530. /* Simply replace the 0th element. */
  531. elp->u.l.lsn_array[0] = *lsnp;
  532. /*
  533.  * If we just added a new entry and there may be NULL
  534.  * entries, so we have to do a complete bubble sort,
  535.  * not just trickle a changed entry around.
  536.  */
  537. for (i = 0; i < (!LF_ISSET(TXNLIST_NEW) ? 1 : elp->u.l.ntxns); i++)
  538. TXN_BUBBLE(elp->u.l.lsn_array, elp->u.l.ntxns);
  539. *lsnp = elp->u.l.lsn_array[0];
  540. return (0);
  541. }
  542. /*
  543.  * __db_txnlist_lsnhead --
  544.  * Return a pointer to the beginning of the lsn_array.
  545.  *
  546.  * PUBLIC: int __db_txnlist_lsnhead __P((void *, DB_LSN **));
  547.  */
  548. int
  549. __db_txnlist_lsnhead(listp, lsnpp)
  550. void *listp;
  551. DB_LSN **lsnpp;
  552. {
  553. DB_TXNHEAD *hp;
  554. DB_TXNLIST *elp;
  555. hp = (DB_TXNHEAD *)listp;
  556. for (elp = LIST_FIRST(&hp->head);
  557.     elp != NULL; elp = LIST_NEXT(elp, links))
  558. if (elp->type == TXNLIST_LSN)
  559. break;
  560. if (elp == NULL)
  561. return (EINVAL);
  562. *lsnpp = &elp->u.l.lsn_array[0];
  563. return (0);
  564. }
  565. /*
  566.  * __db_txnlist_lsninit --
  567.  * Initialize a transaction list with an lsn array entry.
  568.  *
  569.  * PUBLIC: int __db_txnlist_lsninit __P((DB_ENV *, DB_TXNHEAD *, DB_LSN *));
  570.  */
  571. int
  572. __db_txnlist_lsninit(dbenv, hp, lsnp)
  573. DB_ENV *dbenv;
  574. DB_TXNHEAD *hp;
  575. DB_LSN *lsnp;
  576. {
  577. DB_TXNLIST *elp;
  578. int ret;
  579. elp = NULL;
  580. if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0)
  581. goto err;
  582. LIST_INSERT_HEAD(&hp->head, elp, links);
  583. if ((ret = __os_malloc(dbenv,
  584.     12 * sizeof(DB_LSN), NULL, &elp->u.l.lsn_array)) != 0)
  585. goto err;
  586. elp->type = TXNLIST_LSN;
  587. elp->u.l.maxn = 12;
  588. elp->u.l.ntxns = 1;
  589. elp->u.l.lsn_array[0] = *lsnp;
  590. return (0);
  591. err: __db_txnlist_end(dbenv, hp);
  592. return (ret);
  593. }
  594. /*
  595.  * __db_add_limbo -- add pages to the limbo list.
  596.  * Get the file information and call pgnoadd
  597.  * for each page.
  598.  *
  599.  * PUBLIC: int __db_add_limbo __P((DB_ENV *,
  600.  * PUBLIC:      void *, int32_t, db_pgno_t, int32_t));
  601.  */
  602. int
  603. __db_add_limbo(dbenv, info, fileid, pgno, count)
  604. DB_ENV *dbenv;
  605. void *info;
  606. int32_t fileid;
  607. db_pgno_t pgno;
  608. int32_t count;
  609. {
  610. DB_LOG *dblp;
  611. FNAME *fnp;
  612. int ret;
  613. dblp = dbenv->lg_handle;
  614. if ((ret = __log_lid_to_fname(dblp, fileid, &fnp)) != 0)
  615. return (ret);
  616. do {
  617. if ((ret =
  618.     __db_txnlist_pgnoadd(dbenv, info, fileid, fnp->ufid,
  619.     R_ADDR(&dblp->reginfo, fnp->name_off), pgno)) != 0)
  620. return (ret);
  621. pgno++;
  622. } while (--count != 0);
  623. return (0);
  624. }
  625. /*
  626.  * __db_do_the_limbo -- move pages from limbo to free.
  627.  *
  628.  * If we are in recovery we add things to the free list without
  629.  * logging becasue we want to incrementaly apply logs that
  630.  * may be generated on another copy of this environment.
  631.  * Otherwise we just call __db_free to put the pages on
  632.  * the free list and log the activity.
  633.  *
  634.  * PUBLIC: int __db_do_the_limbo __P((DB_ENV *, DB_TXNHEAD *));
  635.  */
  636. int
  637. __db_do_the_limbo(dbenv, hp)
  638. DB_ENV *dbenv;
  639. DB_TXNHEAD *hp;
  640. {
  641. DB *dbp;
  642. DBC *dbc;
  643. DBMETA *meta;
  644. DB_TXN *txn;
  645. DB_TXNLIST *elp;
  646. PAGE *pagep;
  647. db_pgno_t last_pgno, pgno;
  648. int i, in_recover, put_page, ret, t_ret;
  649. dbp = NULL;
  650. dbc = NULL;
  651. txn = NULL;
  652. ret = 0;
  653. /* Are we in recovery? */
  654. in_recover = F_ISSET((DB_LOG *)dbenv->lg_handle, DBLOG_RECOVER);
  655. for (elp = LIST_FIRST(&hp->head);
  656.     elp != NULL; elp = LIST_NEXT(elp, links)) {
  657. if (elp->type != TXNLIST_PGNO)
  658. continue;
  659. if (in_recover) {
  660. if ((ret = db_create(&dbp, dbenv, 0)) != 0)
  661. goto err;
  662. /*
  663.  * It is ok if the file is nolonger there.
  664.  */
  665. dbp->type = DB_UNKNOWN;
  666. ret = __db_dbopen(dbp,
  667.     elp->u.p.fname, 0, __db_omode("rw----"), 0);
  668. } else {
  669. /*
  670.  * If we are in transaction undo, then we know
  671.  * the fileid is still correct.
  672.  */
  673. if ((ret =
  674.     __db_fileid_to_db(dbenv, &dbp,
  675.     elp->u.p.fileid, 0)) != 0 && ret != DB_DELETED)
  676. goto err;
  677. /* File is being destroyed. */
  678. if (F_ISSET(dbp, DB_AM_DISCARD))
  679. ret = DB_DELETED;
  680. }
  681. /*
  682.  * Verify that we are opening the same file that we were
  683.  * referring to when we wrote this log record.
  684.  */
  685. if (ret == 0 &&
  686.     memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) == 0) {
  687. last_pgno = PGNO_INVALID;
  688. if (in_recover) {
  689. pgno = PGNO_BASE_MD;
  690. if ((ret = memp_fget(dbp->mpf,
  691.     &pgno, 0, (PAGE **)&meta)) != 0)
  692. goto err;
  693. last_pgno = meta->free;
  694. /*
  695.  * Check to see if the head of the free
  696.  * list is any of the pages we are about
  697.  * to link in.  We could have crashed
  698.  * after linking them in and before writing
  699.  * a checkpoint.
  700.  * It may not be the last one since
  701.  * any page may get reallocated before here.
  702.  */
  703. if (last_pgno != PGNO_INVALID)
  704. for (i = 0; i < elp->u.p.nentries; i++)
  705. if (last_pgno
  706.      == elp->u.p.pgno_array[i])
  707. goto done_it;
  708. }
  709. for (i = 0; i < elp->u.p.nentries; i++) {
  710. pgno = elp->u.p.pgno_array[i];
  711. if ((ret = memp_fget(dbp->mpf,
  712.     &pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  713. goto err;
  714. put_page = 1;
  715. if (IS_ZERO_LSN(LSN(pagep))) {
  716. P_INIT(pagep, dbp->pgsize,
  717.     pgno, PGNO_INVALID,
  718.     last_pgno, 0, P_INVALID);
  719. if (in_recover) {
  720. LSN(pagep) = LSN(meta);
  721. last_pgno = pgno;
  722. } else {
  723. /*
  724.  * Starting the transaction
  725.  * is postponed until we know
  726.  * we have something to do.
  727.  */
  728. if (txn == NULL &&
  729.     (ret = txn_begin(dbenv,
  730.     NULL, &txn, 0)) != 0)
  731. goto err;
  732. if (dbc == NULL &&
  733.     (ret = dbp->cursor(dbp,
  734.     txn, &dbc, 0)) != 0)
  735. goto err;
  736. /* Turn off locking. */
  737. F_SET(dbc, DBC_COMPENSATE);
  738. /* __db_free puts the page. */
  739. if ((ret =
  740.     __db_free(dbc, pagep)) != 0)
  741. goto err;
  742. put_page = 0;
  743. }
  744. }
  745. if (put_page == 1 &&
  746.     (ret = memp_fput(dbp->mpf,
  747.     pagep, DB_MPOOL_DIRTY)) != 0)
  748. goto err;
  749. }
  750. if (in_recover) {
  751. if (last_pgno == meta->free) {
  752. done_it:
  753. if ((ret =
  754.     memp_fput(dbp->mpf, meta, 0)) != 0)
  755. goto err;
  756. } else {
  757. /*
  758.  * Flush the new free list then
  759.  * update the metapage.  This is
  760.  * unlogged so we cannot have the
  761.  * metapage pointing at pages that
  762.  * are not on disk.
  763.  */
  764. dbp->sync(dbp, 0);
  765. meta->free = last_pgno;
  766. if ((ret = memp_fput(dbp->mpf,
  767.     meta, DB_MPOOL_DIRTY)) != 0)
  768. goto err;
  769. }
  770. }
  771. if (dbc != NULL && (ret = dbc->c_close(dbc)) != 0)
  772. goto err;
  773. dbc = NULL;
  774. }
  775. if (in_recover && (t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
  776. ret = t_ret;
  777. dbp = NULL;
  778. __os_free(elp->u.p.fname, 0);
  779. __os_free(elp->u.p.pgno_array, 0);
  780. if (ret == ENOENT)
  781. ret = 0;
  782. else if (ret != 0)
  783. goto err;
  784. }
  785. if (txn != NULL) {
  786. ret = txn_commit(txn, 0);
  787. txn = NULL;
  788. }
  789. err:
  790. if (dbc != NULL)
  791. (void)dbc->c_close(dbc);
  792. if (in_recover && dbp != NULL)
  793. (void)dbp->close(dbp, 0);
  794. if (txn != NULL)
  795. (void)txn_abort(txn);
  796. return (ret);
  797. }
  798. #define DB_TXNLIST_MAX_PGNO 8 /* A nice even number. */
  799. /*
  800.  * __db_txnlist_pgnoadd --
  801.  * Find the txnlist entry for a file and add this pgno,
  802.  * or add the list entry for the file and then add the pgno.
  803.  *
  804.  * PUBLIC: int __db_txnlist_pgnoadd __P((DB_ENV *, DB_TXNHEAD *,
  805.  * PUBLIC:      int32_t, u_int8_t [DB_FILE_ID_LEN], char *, db_pgno_t));
  806.  */
  807. int
  808. __db_txnlist_pgnoadd(dbenv, hp, fileid, uid, fname, pgno)
  809. DB_ENV *dbenv;
  810. DB_TXNHEAD *hp;
  811. int32_t fileid;
  812. u_int8_t uid[DB_FILE_ID_LEN];
  813. char *fname;
  814. db_pgno_t pgno;
  815. {
  816. DB_TXNLIST *elp;
  817. int len, ret;
  818. elp = NULL;
  819. if (__db_txnlist_find_internal(hp, TXNLIST_PGNO, 0, uid, &elp, 0) != 0) {
  820. if ((ret =
  821.     __os_malloc(dbenv, sizeof(DB_TXNLIST), NULL, &elp)) != 0)
  822. goto err;
  823. LIST_INSERT_HEAD(&hp->head, elp, links);
  824. elp->u.p.fileid = fileid;
  825. memcpy(elp->u.p.uid, uid, DB_FILE_ID_LEN);
  826. len = strlen(fname) + 1;
  827. if ((ret = __os_malloc(dbenv, len, NULL, &elp->u.p.fname)) != 0)
  828. goto err;
  829. memcpy(elp->u.p.fname, fname, len);
  830. elp->u.p.maxentry = 0;
  831. elp->type = TXNLIST_PGNO;
  832. if ((ret = __os_malloc(dbenv,
  833.     8 * sizeof(db_pgno_t), NULL, &elp->u.p.pgno_array)) != 0)
  834. goto err;
  835. elp->u.p.maxentry = DB_TXNLIST_MAX_PGNO;
  836. elp->u.p.nentries = 0;
  837. } else if (elp->u.p.nentries == elp->u.p.maxentry) {
  838. elp->u.p.maxentry <<= 1;
  839. if ((ret = __os_realloc(dbenv, elp->u.p.maxentry *
  840.     sizeof(db_pgno_t), NULL, &elp->u.p.pgno_array)) != 0)
  841. goto err;
  842. }
  843. elp->u.p.pgno_array[elp->u.p.nentries++] = pgno;
  844. return (0);
  845. err: __db_txnlist_end(dbenv, hp);
  846. return (ret);
  847. }
  848. #ifdef DEBUG
  849. /*
  850.  * __db_txnlist_print --
  851.  * Print out the transaction list.
  852.  *
  853.  * PUBLIC: void __db_txnlist_print __P((void *));
  854.  */
  855. void
  856. __db_txnlist_print(listp)
  857. void *listp;
  858. {
  859. DB_TXNHEAD *hp;
  860. DB_TXNLIST *p;
  861. hp = (DB_TXNHEAD *)listp;
  862. printf("Maxid: %lu Generation: %lun",
  863.     (u_long)hp->maxid, (u_long)hp->generation);
  864. for (p = LIST_FIRST(&hp->head); p != NULL; p = LIST_NEXT(p, links)) {
  865. switch (p->type) {
  866. case TXNLIST_TXNID:
  867. printf("TXNID: %lu(%lu)n",
  868.     (u_long)p->u.t.txnid, (u_long)p->u.t.generation);
  869. break;
  870. case TXNLIST_DELETE:
  871. printf("FILE: %s id=%d ops=%d %s %sn",
  872.     p->u.d.fname, p->u.d.fileid, p->u.d.count,
  873.     F_ISSET(&p->u.d, TXNLIST_FLAG_DELETED) ?
  874.     "(deleted)" : "(missing)",
  875.     F_ISSET(&p->u.d, TXNLIST_FLAG_CLOSED) ?
  876.     "(closed)" : "(open)");
  877. break;
  878. default:
  879. printf("Unrecognized type: %dn", p->type);
  880. break;
  881. }
  882. }
  883. }
  884. #endif