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

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. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: log.c,v 11.42 2001/01/15 16:42:37 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #endif
  17. #ifdef  HAVE_RPC
  18. #include "db_server.h"
  19. #endif
  20. #include "db_int.h"
  21. #include "log.h"
  22. #include "db_dispatch.h"
  23. #include "txn.h"
  24. #include "txn_auto.h"
  25. #ifdef HAVE_RPC
  26. #include "gen_client_ext.h"
  27. #include "rpc_client_ext.h"
  28. #endif
  29. static int __log_init __P((DB_ENV *, DB_LOG *));
  30. static int __log_recover __P((DB_LOG *));
  31. /*
  32.  * __log_open --
  33.  * Internal version of log_open: only called from DB_ENV->open.
  34.  *
  35.  * PUBLIC: int __log_open __P((DB_ENV *));
  36.  */
  37. int
  38. __log_open(dbenv)
  39. DB_ENV *dbenv;
  40. {
  41. DB_LOG *dblp;
  42. LOG *lp;
  43. int ret;
  44. u_int8_t *readbufp;
  45. readbufp = NULL;
  46. /* Create/initialize the DB_LOG structure. */
  47. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOG), &dblp)) != 0)
  48. return (ret);
  49. if ((ret = __os_calloc(dbenv, 1, dbenv->lg_bsize, &readbufp)) != 0)
  50. goto err;
  51. ZERO_LSN(dblp->c_lsn);
  52. dblp->dbenv = dbenv;
  53. /* Join/create the log region. */
  54. dblp->reginfo.type = REGION_TYPE_LOG;
  55. dblp->reginfo.id = INVALID_REGION_ID;
  56. dblp->reginfo.mode = dbenv->db_mode;
  57. dblp->reginfo.flags = REGION_JOIN_OK;
  58. if (F_ISSET(dbenv, DB_ENV_CREATE))
  59. F_SET(&dblp->reginfo, REGION_CREATE_OK);
  60. if ((ret = __db_r_attach(
  61.     dbenv, &dblp->reginfo, LG_BASE_REGION_SIZE + dbenv->lg_bsize)) != 0)
  62. goto err;
  63. dblp->readbufp = readbufp;
  64. /* If we created the region, initialize it. */
  65. if (F_ISSET(&dblp->reginfo, REGION_CREATE) &&
  66.     (ret = __log_init(dbenv, dblp)) != 0)
  67. goto err;
  68. /* Set the local addresses. */
  69. lp = dblp->reginfo.primary =
  70.     R_ADDR(&dblp->reginfo, dblp->reginfo.rp->primary);
  71. dblp->bufp = R_ADDR(&dblp->reginfo, lp->buffer_off);
  72. /*
  73.  * If the region is threaded, then we have to lock both the handles
  74.  * and the region, and we need to allocate a mutex for that purpose.
  75.  */
  76. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  77. if ((ret = __db_mutex_alloc(
  78.     dbenv, &dblp->reginfo, &dblp->mutexp)) != 0)
  79. goto err;
  80. if ((ret = __db_mutex_init(
  81.     dbenv, dblp->mutexp, 0, MUTEX_THREAD)) != 0)
  82. goto err;
  83. }
  84. R_UNLOCK(dbenv, &dblp->reginfo);
  85. dblp->r_file = 0;
  86. dblp->r_off = 0;
  87. dblp->r_size = 0;
  88. dbenv->lg_handle = dblp;
  89. return (0);
  90. err: if (dblp->reginfo.addr != NULL) {
  91. if (F_ISSET(&dblp->reginfo, REGION_CREATE))
  92. ret = __db_panic(dbenv, ret);
  93. R_UNLOCK(dbenv, &dblp->reginfo);
  94. (void)__db_r_detach(dbenv, &dblp->reginfo, 0);
  95. }
  96. if (readbufp != NULL)
  97. __os_free(readbufp, dbenv->lg_bsize);
  98. if (dblp->mutexp != NULL)
  99. __db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp);
  100. __os_free(dblp, sizeof(*dblp));
  101. return (ret);
  102. }
  103. /*
  104.  * __log_init --
  105.  * Initialize a log region in shared memory.
  106.  */
  107. static int
  108. __log_init(dbenv, dblp)
  109. DB_ENV *dbenv;
  110. DB_LOG *dblp;
  111. {
  112. LOG *region;
  113. int ret;
  114. void *p;
  115. if ((ret = __db_shalloc(dblp->reginfo.addr,
  116.     sizeof(*region), 0, &dblp->reginfo.primary)) != 0)
  117. goto mem_err;
  118. dblp->reginfo.rp->primary =
  119.     R_OFFSET(&dblp->reginfo, dblp->reginfo.primary);
  120. region = dblp->reginfo.primary;
  121. memset(region, 0, sizeof(*region));
  122. region->persist.lg_max = dbenv->lg_max;
  123. region->persist.magic = DB_LOGMAGIC;
  124. region->persist.version = DB_LOGVERSION;
  125. region->persist.mode = dbenv->db_mode;
  126. SH_TAILQ_INIT(&region->fq);
  127. /* Initialize LOG LSNs. */
  128. region->lsn.file = 1;
  129. region->lsn.offset = 0;
  130. /* Initialize the buffer. */
  131. if ((ret =
  132.     __db_shalloc(dblp->reginfo.addr, dbenv->lg_bsize, 0, &p)) != 0) {
  133. mem_err: __db_err(dbenv, "Unable to allocate memory for the log buffer");
  134. return (ret);
  135. }
  136. region->buffer_size = dbenv->lg_bsize;
  137. region->buffer_off = R_OFFSET(&dblp->reginfo, p);
  138. /* Try and recover any previous log files before releasing the lock. */
  139. return (__log_recover(dblp));
  140. }
  141. /*
  142.  * __log_recover --
  143.  * Recover a log.
  144.  */
  145. static int
  146. __log_recover(dblp)
  147. DB_LOG *dblp;
  148. {
  149. DBT dbt;
  150. DB_LSN lsn;
  151. LOG *lp;
  152. int cnt, found_checkpoint, ret;
  153. u_int32_t chk;
  154. logfile_validity status;
  155. lp = dblp->reginfo.primary;
  156. /*
  157.  * Find a log file.  If none exist, we simply return, leaving
  158.  * everything initialized to a new log.
  159.  */
  160. if ((ret = __log_find(dblp, 0, &cnt, &status)) != 0)
  161. return (ret);
  162. if (cnt == 0)
  163. return (0);
  164. /*
  165.  * If the last file is an old version, readable or no, start a new
  166.  * file.  Don't bother finding checkpoints;  if we didn't take a
  167.  * checkpoint right before upgrading, the user screwed up anyway.
  168.  */
  169. if (status == DB_LV_OLD_READABLE || status == DB_LV_OLD_UNREADABLE) {
  170. lp->lsn.file = lp->s_lsn.file = cnt + 1;
  171. lp->lsn.offset = lp->s_lsn.offset = 0;
  172. goto skipsearch;
  173. }
  174. DB_ASSERT(status == DB_LV_NORMAL);
  175. /*
  176.  * We have the last useful log file and we've loaded any persistent
  177.  * information.  Set the end point of the log past the end of the last
  178.  * file. Read the last file, looking for the last checkpoint and
  179.  * the log's end.
  180.  */
  181. lp->lsn.file = cnt + 1;
  182. lp->lsn.offset = 0;
  183. lsn.file = cnt;
  184. lsn.offset = 0;
  185. /* Set the cursor.  Shouldn't fail;  leave error messages on. */
  186. memset(&dbt, 0, sizeof(dbt));
  187. if ((ret = __log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0)
  188. return (ret);
  189. /*
  190.  * Read to the end of the file, saving checkpoints.  This will fail
  191.  * at some point, so turn off error messages.
  192.  */
  193. found_checkpoint = 0;
  194. while (__log_get(dblp, &lsn, &dbt, DB_NEXT, 1) == 0) {
  195. if (dbt.size < sizeof(u_int32_t))
  196. continue;
  197. memcpy(&chk, dbt.data, sizeof(u_int32_t));
  198. if (chk == DB_txn_ckp) {
  199. lp->chkpt_lsn = lsn;
  200. found_checkpoint = 1;
  201. }
  202. }
  203. /*
  204.  * We now know where the end of the log is.  Set the first LSN that
  205.  * we want to return to an application and the LSN of the last known
  206.  * record on disk.
  207.  */
  208. lp->lsn = lsn;
  209. lp->s_lsn = lsn;
  210. lp->lsn.offset += dblp->c_len;
  211. lp->s_lsn.offset += dblp->c_len;
  212. /* Set up the current buffer information, too. */
  213. lp->len = dblp->c_len;
  214. lp->b_off = 0;
  215. lp->w_off = lp->lsn.offset;
  216. /*
  217.  * It's possible that we didn't find a checkpoint because there wasn't
  218.  * one in the last log file.  Start searching.
  219.  */
  220. if (!found_checkpoint && cnt > 1) {
  221. lsn.file = cnt;
  222. lsn.offset = 0;
  223. /* Set the cursor.  Shouldn't fail, leave error messages on. */
  224. if ((ret = __log_get(dblp, &lsn, &dbt, DB_SET, 0)) != 0)
  225. return (ret);
  226. /*
  227.  * Read to the end of the file, saving checkpoints.  Again,
  228.  * this can fail if there are no checkpoints in any log file,
  229.  * so turn error messages off.
  230.  */
  231. while (__log_get(dblp, &lsn, &dbt, DB_PREV, 1) == 0) {
  232. if (dbt.size < sizeof(u_int32_t))
  233. continue;
  234. memcpy(&chk, dbt.data, sizeof(u_int32_t));
  235. if (chk == DB_txn_ckp) {
  236. lp->chkpt_lsn = lsn;
  237. found_checkpoint = 1;
  238. break;
  239. }
  240. }
  241. }
  242. /* If we never find a checkpoint, that's okay, just 0 it out. */
  243. if (!found_checkpoint)
  244. skipsearch: ZERO_LSN(lp->chkpt_lsn);
  245. /*
  246.  * Reset the cursor lsn to the beginning of the log, so that an
  247.  * initial call to DB_NEXT does the right thing.
  248.  */
  249. ZERO_LSN(dblp->c_lsn);
  250. if (FLD_ISSET(dblp->dbenv->verbose, DB_VERB_RECOVERY))
  251. __db_err(dblp->dbenv,
  252.     "Finding last valid log LSN: file: %lu offset %lu",
  253.     (u_long)lp->lsn.file, (u_long)lp->lsn.offset);
  254. return (0);
  255. }
  256. /*
  257.  * __log_find --
  258.  * Try to find a log file.  If find_first is set, valp will contain
  259.  * the number of the first readable log file, else it will contain the number
  260.  * of the last log file (which may be too old to read).
  261.  *
  262.  * PUBLIC: int __log_find __P((DB_LOG *, int, int *, logfile_validity *));
  263.  */
  264. int
  265. __log_find(dblp, find_first, valp, statusp)
  266. DB_LOG *dblp;
  267. int find_first, *valp;
  268. logfile_validity *statusp;
  269. {
  270. logfile_validity clv_status, status;
  271. u_int32_t clv, logval;
  272. int cnt, fcnt, ret;
  273. const char *dir;
  274. char **names, *p, *q, savech;
  275. clv_status = status = DB_LV_NORMAL;
  276. /* Return a value of 0 as the log file number on failure. */
  277. *valp = 0;
  278. /* Find the directory name. */
  279. if ((ret = __log_name(dblp, 1, &p, NULL, 0)) != 0)
  280. return (ret);
  281. if ((q = __db_rpath(p)) == NULL) {
  282. COMPQUIET(savech, 0);
  283. dir = PATH_DOT;
  284. } else {
  285. savech = *q;
  286. *q = '';
  287. dir = p;
  288. }
  289. /* Get the list of file names. */
  290. ret = __os_dirlist(dblp->dbenv, dir, &names, &fcnt);
  291. /*
  292.  * !!!
  293.  * We overwrote a byte in the string with a nul.  Restore the string
  294.  * so that the diagnostic checks in the memory allocation code work
  295.  * and any error messages display the right file name.
  296.  */
  297. if (q != NULL)
  298. *q = savech;
  299. if (ret != 0) {
  300. __db_err(dblp->dbenv, "%s: %s", dir, db_strerror(ret));
  301. __os_freestr(p);
  302. return (ret);
  303. }
  304. /* Search for a valid log file name. */
  305. for (cnt = fcnt, clv = logval = 0; --cnt >= 0;) {
  306. if (strncmp(names[cnt], LFPREFIX, sizeof(LFPREFIX) - 1) != 0)
  307. continue;
  308. /*
  309.  * Use atol, not atoi; if an "int" is 16-bits, the largest
  310.  * log file name won't fit.
  311.  */
  312. clv = atol(names[cnt] + (sizeof(LFPREFIX) - 1));
  313. if (find_first) {
  314. if (logval != 0 && clv > logval)
  315. continue;
  316. } else
  317. if (logval != 0 && clv < logval)
  318. continue;
  319. /*
  320.  * Take note of whether the log file logval is
  321.  * an old version or incompletely initialized.
  322.  */
  323. if ((ret = __log_valid(dblp, clv, 1, &status)) != 0)
  324. goto err;
  325. switch (status) {
  326. case DB_LV_INCOMPLETE:
  327. /*
  328.  * It's acceptable for the last log file to
  329.  * have been incompletely initialized--it's possible
  330.  * to create a log file but not write anything to it,
  331.  * and recovery needs to gracefully handle this.
  332.  *
  333.  * Just ignore it;  we don't want to return this
  334.  * as a valid log file.
  335.  */
  336. break;
  337. case DB_LV_NORMAL:
  338. case DB_LV_OLD_READABLE:
  339. logval = clv;
  340. clv_status = status;
  341. break;
  342. case DB_LV_OLD_UNREADABLE:
  343. /*
  344.  * Continue;  we want the oldest valid log,
  345.  * and clv is too old to be useful.  We don't
  346.  * want it to supplant logval if we're looking for
  347.  * the oldest valid log, but we do want to return
  348.  * it if it's the last log file--we want the very
  349.  * last file number, so that our caller can
  350.  * start a new file after it.
  351.  *
  352.  * The code here assumes that there will never
  353.  * be a too-old log that's preceded by a log
  354.  * of the current version, but in order to
  355.  * attain that state of affairs the user
  356.  * would have had to really seriously screw
  357.  * up;  I think we can safely assume this won't
  358.  * happen.
  359.  */
  360. if (!find_first) {
  361. logval = clv;
  362. clv_status = status;
  363. }
  364. break;
  365. }
  366. }
  367. *valp = logval;
  368. err: __os_dirfree(names, fcnt);
  369. __os_freestr(p);
  370. *statusp = clv_status;
  371. return (ret);
  372. }
  373. /*
  374.  * log_valid --
  375.  * Validate a log file.  Returns an error code in the event of
  376.  * a fatal flaw in a the specified log file;  returns success with
  377.  * a code indicating the currentness and completeness of the specified
  378.  * log file if it is not unexpectedly flawed (that is, if it's perfectly
  379.  * normal, if it's zero-length, or if it's an old version).
  380.  *
  381.  * PUBLIC: int __log_valid __P((DB_LOG *, u_int32_t, int, logfile_validity *));
  382.  */
  383. int
  384. __log_valid(dblp, number, set_persist, statusp)
  385. DB_LOG *dblp;
  386. u_int32_t number;
  387. int set_persist;
  388. logfile_validity *statusp;
  389. {
  390. DB_FH fh;
  391. LOG *region;
  392. LOGP persist;
  393. char *fname;
  394. int ret;
  395. logfile_validity status;
  396. size_t nw;
  397. status = DB_LV_NORMAL;
  398. /* Try to open the log file. */
  399. if ((ret = __log_name(dblp,
  400.     number, &fname, &fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) {
  401. __os_freestr(fname);
  402. return (ret);
  403. }
  404. /* Try to read the header. */
  405. if ((ret =
  406.     __os_seek(dblp->dbenv,
  407.     &fh, 0, 0, sizeof(HDR), 0, DB_OS_SEEK_SET)) != 0 ||
  408.     (ret =
  409.     __os_read(dblp->dbenv, &fh, &persist, sizeof(LOGP), &nw)) != 0 ||
  410.     nw != sizeof(LOGP)) {
  411. if (ret == 0)
  412. status = DB_LV_INCOMPLETE;
  413. else
  414. /*
  415.  * The error was a fatal read error, not just an
  416.  * incompletely initialized log file.
  417.  */
  418. __db_err(dblp->dbenv, "Ignoring log file: %s: %s",
  419.     fname, db_strerror(ret));
  420. (void)__os_closehandle(&fh);
  421. goto err;
  422. }
  423. (void)__os_closehandle(&fh);
  424. /* Validate the header. */
  425. if (persist.magic != DB_LOGMAGIC) {
  426. __db_err(dblp->dbenv,
  427.     "Ignoring log file: %s: magic number %lx, not %lx",
  428.     fname, (u_long)persist.magic, (u_long)DB_LOGMAGIC);
  429. ret = EINVAL;
  430. goto err;
  431. }
  432. /*
  433.  * Set our status code to indicate whether the log file
  434.  * belongs to an unreadable or readable old version;  leave it
  435.  * alone if and only if the log file version is the current one.
  436.  */
  437. if (persist.version > DB_LOGVERSION) {
  438. /* This is a fatal error--the log file is newer than DB. */
  439. __db_err(dblp->dbenv,
  440.     "Ignoring log file: %s: unsupported log version %lu",
  441.     fname, (u_long)persist.version);
  442. ret = EINVAL;
  443. goto err;
  444. } else if (persist.version < DB_LOGOLDVER) {
  445. status = DB_LV_OLD_UNREADABLE;
  446. /*
  447.  * We don't want to set persistent info based on an
  448.  * unreadable region, so jump to "err".
  449.  */
  450. goto err;
  451. } else if (persist.version < DB_LOGVERSION)
  452. status = DB_LV_OLD_READABLE;
  453. /*
  454.  * If the log is thus far readable and we're doing system
  455.  * initialization, set the region's persistent information
  456.  * based on the headers.
  457.  */
  458. if (set_persist) {
  459. region = dblp->reginfo.primary;
  460. region->persist.lg_max = persist.lg_max;
  461. region->persist.mode = persist.mode;
  462. }
  463. err: __os_freestr(fname);
  464. *statusp = status;
  465. return (ret);
  466. }
  467. /*
  468.  * __log_close --
  469.  * Internal version of log_close: only called from dbenv_refresh.
  470.  *
  471.  * PUBLIC: int __log_close __P((DB_ENV *));
  472.  */
  473. int
  474. __log_close(dbenv)
  475. DB_ENV *dbenv;
  476. {
  477. DB_LOG *dblp;
  478. int ret, t_ret;
  479. ret = 0;
  480. dblp = dbenv->lg_handle;
  481. /* We may have opened files as part of XA; if so, close them. */
  482. F_SET(dblp, DBLOG_RECOVER);
  483. __log_close_files(dbenv);
  484. /* Discard the per-thread lock. */
  485. if (dblp->mutexp != NULL)
  486. __db_mutex_free(dbenv, &dblp->reginfo, dblp->mutexp);
  487. /* Detach from the region. */
  488. ret = __db_r_detach(dbenv, &dblp->reginfo, 0);
  489. /* Close open files, release allocated memory. */
  490. if (F_ISSET(&dblp->lfh, DB_FH_VALID) &&
  491.     (t_ret = __os_closehandle(&dblp->lfh)) != 0 && ret == 0)
  492. ret = t_ret;
  493. if (dblp->c_dbt.data != NULL)
  494. __os_free(dblp->c_dbt.data, dblp->c_dbt.ulen);
  495. if (F_ISSET(&dblp->c_fh, DB_FH_VALID) &&
  496.     (t_ret = __os_closehandle(&dblp->c_fh)) != 0 && ret == 0)
  497. ret = t_ret;
  498. if (dblp->dbentry != NULL)
  499. __os_free(dblp->dbentry,
  500.     (dblp->dbentry_cnt * sizeof(DB_ENTRY)));
  501. if (dblp->readbufp != NULL)
  502. __os_free(dblp->readbufp, dbenv->lg_bsize);
  503. __os_free(dblp, sizeof(*dblp));
  504. dbenv->lg_handle = NULL;
  505. return (ret);
  506. }
  507. /*
  508.  * log_stat --
  509.  * Return LOG statistics.
  510.  */
  511. int
  512. log_stat(dbenv, statp, db_malloc)
  513. DB_ENV *dbenv;
  514. DB_LOG_STAT **statp;
  515. void *(*db_malloc) __P((size_t));
  516. {
  517. DB_LOG *dblp;
  518. DB_LOG_STAT *stats;
  519. LOG *region;
  520. int ret;
  521. #ifdef HAVE_RPC
  522. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  523. return (__dbcl_log_stat(dbenv, statp, db_malloc));
  524. #endif
  525. PANIC_CHECK(dbenv);
  526. ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
  527. *statp = NULL;
  528. dblp = dbenv->lg_handle;
  529. region = dblp->reginfo.primary;
  530. if ((ret = __os_malloc(dbenv,
  531.     sizeof(DB_LOG_STAT), db_malloc, &stats)) != 0)
  532. return (ret);
  533. /* Copy out the global statistics. */
  534. R_LOCK(dbenv, &dblp->reginfo);
  535. *stats = region->stat;
  536. stats->st_magic = region->persist.magic;
  537. stats->st_version = region->persist.version;
  538. stats->st_mode = region->persist.mode;
  539. stats->st_lg_bsize = region->buffer_size;
  540. stats->st_lg_max = region->persist.lg_max;
  541. stats->st_region_wait = dblp->reginfo.rp->mutex.mutex_set_wait;
  542. stats->st_region_nowait = dblp->reginfo.rp->mutex.mutex_set_nowait;
  543. stats->st_regsize = dblp->reginfo.rp->size;
  544. stats->st_cur_file = region->lsn.file;
  545. stats->st_cur_offset = region->lsn.offset;
  546. R_UNLOCK(dbenv, &dblp->reginfo);
  547. *statp = stats;
  548. return (0);
  549. }
  550. /*
  551.  * __log_lastckp --
  552.  * Return the current chkpt_lsn, so that we can store it in
  553.  * the transaction region and keep the chain of checkpoints
  554.  * unbroken across environment recreates.
  555.  *
  556.  * PUBLIC: int __log_lastckp __P((DB_ENV *, DB_LSN *));
  557.  */
  558. int
  559. __log_lastckp(dbenv, lsnp)
  560. DB_ENV *dbenv;
  561. DB_LSN *lsnp;
  562. {
  563. LOG *lp;
  564. lp = (LOG *)(((DB_LOG *)dbenv->lg_handle)->reginfo.primary);
  565. *lsnp = lp->chkpt_lsn;
  566. return (0);
  567. }