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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: log_get.c,v 11.81 2002/08/14 20:09:27 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "dbinc/crypto.h"
  18. #include "dbinc/db_page.h"
  19. #include "dbinc/hmac.h"
  20. #include "dbinc/log.h"
  21. #include "dbinc/hash.h"
  22. typedef enum { L_ALREADY, L_ACQUIRED, L_NONE } RLOCK;
  23. static int __log_c_close __P((DB_LOGC *, u_int32_t));
  24. static int __log_c_get __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t));
  25. static int __log_c_get_int __P((DB_LOGC *, DB_LSN *, DBT *, u_int32_t));
  26. static int __log_c_hdrchk __P((DB_LOGC *, HDR *, int *));
  27. static int __log_c_incursor __P((DB_LOGC *, DB_LSN *, HDR *, u_int8_t **));
  28. static int __log_c_inregion __P((DB_LOGC *,
  29.        DB_LSN *, RLOCK *, DB_LSN *, HDR *, u_int8_t **));
  30. static int __log_c_io __P((DB_LOGC *,
  31.        u_int32_t, u_int32_t, void *, size_t *, int *));
  32. static int __log_c_ondisk __P((DB_LOGC *,
  33.        DB_LSN *, DB_LSN *, int, HDR *, u_int8_t **, int *));
  34. static int __log_c_set_maxrec __P((DB_LOGC *, char *));
  35. static int __log_c_shortread __P((DB_LOGC *, int));
  36. /*
  37.  * __log_cursor --
  38.  * Create a log cursor.
  39.  *
  40.  * PUBLIC: int __log_cursor __P((DB_ENV *, DB_LOGC **, u_int32_t));
  41.  */
  42. int
  43. __log_cursor(dbenv, logcp, flags)
  44. DB_ENV *dbenv;
  45. DB_LOGC **logcp;
  46. u_int32_t flags;
  47. {
  48. DB_LOGC *logc;
  49. int ret;
  50. PANIC_CHECK(dbenv);
  51. ENV_REQUIRES_CONFIG(dbenv,
  52.     dbenv->lg_handle, "DB_ENV->log_cursor", DB_INIT_LOG);
  53. *logcp = NULL;
  54. /* Validate arguments. */
  55. if ((ret = __db_fchk(dbenv, "DB_ENV->log_cursor", flags, 0)) != 0)
  56. return (ret);
  57. /* Allocate memory for the cursor. */
  58. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_LOGC), &logc)) != 0)
  59. goto err;
  60. if ((ret = __os_calloc(dbenv, 1, sizeof(DB_FH), &logc->c_fh)) != 0)
  61. goto err;
  62. logc->bp_size = DB_LOGC_BUF_SIZE;
  63. if ((ret = __os_malloc(dbenv, logc->bp_size, &logc->bp)) != 0)
  64. goto err;
  65. logc->dbenv = dbenv;
  66. logc->close = __log_c_close;
  67. logc->get = __log_c_get;
  68. *logcp = logc;
  69. return (0);
  70. err: if (logc != NULL) {
  71. if (logc->c_fh != NULL)
  72. __os_free(dbenv, logc->c_fh);
  73. __os_free(dbenv, logc);
  74. }
  75. return (ret);
  76. }
  77. /*
  78.  * __log_c_close --
  79.  * Close a log cursor.
  80.  */
  81. static int
  82. __log_c_close(logc, flags)
  83. DB_LOGC *logc;
  84. u_int32_t flags;
  85. {
  86. DB_ENV *dbenv;
  87. int ret;
  88. dbenv = logc->dbenv;
  89. PANIC_CHECK(dbenv);
  90. if ((ret = __db_fchk(dbenv, "DB_LOGC->close", flags, 0)) != 0)
  91. return (ret);
  92. if (F_ISSET(logc->c_fh, DB_FH_VALID))
  93. (void)__os_closehandle(dbenv, logc->c_fh);
  94. if (logc->c_dbt.data != NULL)
  95. __os_free(dbenv, logc->c_dbt.data);
  96. __os_free(dbenv, logc->bp);
  97. __os_free(dbenv, logc->c_fh);
  98. __os_free(dbenv, logc);
  99. return (0);
  100. }
  101. /*
  102.  * __log_c_get --
  103.  * Get a log record.
  104.  */
  105. static int
  106. __log_c_get(logc, alsn, dbt, flags)
  107. DB_LOGC *logc;
  108. DB_LSN *alsn;
  109. DBT *dbt;
  110. u_int32_t flags;
  111. {
  112. DB_ENV *dbenv;
  113. DB_LSN saved_lsn;
  114. int ret;
  115. dbenv = logc->dbenv;
  116. PANIC_CHECK(dbenv);
  117. /* Validate arguments. */
  118. switch (flags) {
  119. case DB_CURRENT:
  120. case DB_FIRST:
  121. case DB_LAST:
  122. case DB_NEXT:
  123. case DB_PREV:
  124. break;
  125. case DB_SET:
  126. if (IS_ZERO_LSN(*alsn)) {
  127. __db_err(dbenv, "DB_LOGC->get: invalid LSN");
  128. return (EINVAL);
  129. }
  130. break;
  131. default:
  132. return (__db_ferr(dbenv, "DB_LOGC->get", 1));
  133. }
  134. /*
  135.  * On error, we take care not to overwrite the caller's LSN.  This
  136.  * is because callers looking for the end of the log loop using the
  137.  * DB_NEXT flag, and expect to take the last successful lsn out of
  138.  * the passed-in structure after DB_LOGC->get fails with DB_NOTFOUND.
  139.  *
  140.  * !!!
  141.  * This line is often flagged an uninitialized memory read during a
  142.  * Purify or similar tool run, as the application didn't initialize
  143.  * *alsn.  If the application isn't setting the DB_SET flag, there is
  144.  * no reason it should have initialized *alsn, but we can't know that
  145.  * and we want to make sure we never overwrite whatever the application
  146.  * put in there.
  147.  */
  148. saved_lsn = *alsn;
  149. /*
  150.  * If we get one of the log's header records as a result of doing a
  151.  * DB_FIRST, DB_NEXT, DB_LAST or DB_PREV, repeat the operation, log
  152.  * file header records aren't useful to applications.
  153.  */
  154. if ((ret = __log_c_get_int(logc, alsn, dbt, flags)) != 0) {
  155. *alsn = saved_lsn;
  156. return (ret);
  157. }
  158. if (alsn->offset == 0 && (flags == DB_FIRST ||
  159.     flags == DB_NEXT || flags == DB_LAST || flags == DB_PREV)) {
  160. switch (flags) {
  161. case DB_FIRST:
  162. flags = DB_NEXT;
  163. break;
  164. case DB_LAST:
  165. flags = DB_PREV;
  166. break;
  167. }
  168. if (F_ISSET(dbt, DB_DBT_MALLOC)) {
  169. __os_free(dbenv, dbt->data);
  170. dbt->data = NULL;
  171. }
  172. if ((ret = __log_c_get_int(logc, alsn, dbt, flags)) != 0) {
  173. *alsn = saved_lsn;
  174. return (ret);
  175. }
  176. }
  177. return (0);
  178. }
  179. /*
  180.  * __log_c_get_int --
  181.  * Get a log record; internal version.
  182.  */
  183. static int
  184. __log_c_get_int(logc, alsn, dbt, flags)
  185. DB_LOGC *logc;
  186. DB_LSN *alsn;
  187. DBT *dbt;
  188. u_int32_t flags;
  189. {
  190. DB_CIPHER *db_cipher;
  191. DB_ENV *dbenv;
  192. DB_LOG *dblp;
  193. DB_LSN last_lsn, nlsn;
  194. HDR hdr;
  195. LOG *lp;
  196. RLOCK rlock;
  197. logfile_validity status;
  198. u_int32_t cnt;
  199. u_int8_t *rp;
  200. int eof, is_hmac, ret;
  201. dbenv = logc->dbenv;
  202. dblp = dbenv->lg_handle;
  203. lp = dblp->reginfo.primary;
  204. is_hmac = 0;
  205. /*
  206.  * We don't acquire the log region lock until we need it, and we
  207.  * release it as soon as we're done.
  208.  */
  209. rlock = F_ISSET(logc, DB_LOG_LOCKED) ? L_ALREADY : L_NONE;
  210. nlsn = logc->c_lsn;
  211. switch (flags) {
  212. case DB_NEXT: /* Next log record. */
  213. if (!IS_ZERO_LSN(nlsn)) {
  214. /* Increment the cursor by the cursor record size. */
  215. nlsn.offset += logc->c_len;
  216. break;
  217. }
  218. flags = DB_FIRST;
  219. /* FALLTHROUGH */
  220. case DB_FIRST: /* First log record. */
  221. /* Find the first log file. */
  222. if ((ret = __log_find(dblp, 1, &cnt, &status)) != 0)
  223. goto err;
  224. /*
  225.  * DB_LV_INCOMPLETE:
  226.  * Theoretically, the log file we want could be created
  227.  * but not yet written, the "first" log record must be
  228.  * in the log buffer.
  229.  * DB_LV_NORMAL:
  230.  * DB_LV_OLD_READABLE:
  231.  * We found a log file we can read.
  232.  * DB_LV_NONEXISTENT:
  233.  * No log files exist, the "first" log record must be in
  234.  * the log buffer.
  235.  * DB_LV_OLD_UNREADABLE:
  236.  * No readable log files exist, we're at the cross-over
  237.  * point between two versions.  The "first" log record
  238.  * must be in the log buffer.
  239.  */
  240. switch (status) {
  241. case DB_LV_INCOMPLETE:
  242. DB_ASSERT(lp->lsn.file == cnt);
  243. /* FALLTHROUGH */
  244. case DB_LV_NORMAL:
  245. case DB_LV_OLD_READABLE:
  246. nlsn.file = cnt;
  247. break;
  248. case DB_LV_NONEXISTENT:
  249. nlsn.file = 1;
  250. DB_ASSERT(lp->lsn.file == nlsn.file);
  251. break;
  252. case DB_LV_OLD_UNREADABLE:
  253. nlsn.file = cnt + 1;
  254. DB_ASSERT(lp->lsn.file == nlsn.file);
  255. break;
  256. }
  257. nlsn.offset = 0;
  258. break;
  259. case DB_CURRENT: /* Current log record. */
  260. break;
  261. case DB_PREV: /* Previous log record. */
  262. if (!IS_ZERO_LSN(nlsn)) {
  263. /* If at start-of-file, move to the previous file. */
  264. if (nlsn.offset == 0) {
  265. if (nlsn.file == 1 ||
  266.     __log_valid(dblp,
  267. nlsn.file - 1, 0, &status) != 0) {
  268. ret = DB_NOTFOUND;
  269. goto err;
  270. }
  271. if (status != DB_LV_NORMAL &&
  272.     status != DB_LV_OLD_READABLE) {
  273. ret = DB_NOTFOUND;
  274. goto err;
  275. }
  276. --nlsn.file;
  277. }
  278. nlsn.offset = logc->c_prev;
  279. break;
  280. }
  281. /* FALLTHROUGH */
  282. case DB_LAST: /* Last log record. */
  283. if (rlock == L_NONE) {
  284. rlock = L_ACQUIRED;
  285. R_LOCK(dbenv, &dblp->reginfo);
  286. }
  287. nlsn.file = lp->lsn.file;
  288. nlsn.offset = lp->lsn.offset - lp->len;
  289. break;
  290. case DB_SET: /* Set log record. */
  291. nlsn = *alsn;
  292. break;
  293. }
  294. if (0) { /* Move to the next file. */
  295. next_file: ++nlsn.file;
  296. nlsn.offset = 0;
  297. }
  298. /*
  299.  * The above switch statement should have set nlsn to the lsn of
  300.  * the requested record.
  301.  */
  302. if (CRYPTO_ON(dbenv)) {
  303. hdr.size = HDR_CRYPTO_SZ;
  304. is_hmac = 1;
  305. } else {
  306. hdr.size = HDR_NORMAL_SZ;
  307. is_hmac = 0;
  308. }
  309. /* Check to see if the record is in the cursor's buffer. */
  310. if ((ret = __log_c_incursor(logc, &nlsn, &hdr, &rp)) != 0)
  311. goto err;
  312. if (rp != NULL)
  313. goto cksum;
  314. /*
  315.  * Look to see if we're moving backward in the log with the last record
  316.  * coming from the disk -- it means the record can't be in the region's
  317.  * buffer.  Else, check the region's buffer.
  318.  *
  319.  * If the record isn't in the region's buffer, we're going to have to
  320.  * read the record from disk.  We want to make a point of not reading
  321.  * past the end of the logical log (after recovery, there may be data
  322.  * after the end of the logical log, not to mention the log file may
  323.  * have been pre-allocated).  So, zero out last_lsn, and initialize it
  324.  * inside __log_c_inregion -- if it's still zero when we check it in
  325.  * __log_c_ondisk, that's OK, it just means the logical end of the log
  326.  * isn't an issue for this request.
  327.  */
  328. ZERO_LSN(last_lsn);
  329. if (!F_ISSET(logc, DB_LOG_DISK) ||
  330.     log_compare(&nlsn, &logc->c_lsn) > 0) {
  331. F_CLR(logc, DB_LOG_DISK);
  332. if ((ret = __log_c_inregion(logc,
  333.     &nlsn, &rlock, &last_lsn, &hdr, &rp)) != 0)
  334. goto err;
  335. if (rp != NULL)
  336. goto cksum;
  337. }
  338. /*
  339.  * We have to read from an on-disk file to retrieve the record.
  340.  * If we ever can't retrieve the record at offset 0, we're done,
  341.  * return EOF/DB_NOTFOUND.
  342.  *
  343.  * Discard the region lock if we're still holding it, the on-disk
  344.  * reading routines don't need it.
  345.  */
  346. if (rlock == L_ACQUIRED) {
  347. rlock = L_NONE;
  348. R_UNLOCK(dbenv, &dblp->reginfo);
  349. }
  350. if ((ret = __log_c_ondisk(
  351.     logc, &nlsn, &last_lsn, flags, &hdr, &rp, &eof)) != 0)
  352. goto err;
  353. if (eof == 1) {
  354. /*
  355.  * Only DB_NEXT automatically moves to the next file, and
  356.  * it only happens once.
  357.  */
  358. if (flags != DB_NEXT || nlsn.offset == 0)
  359. return (DB_NOTFOUND);
  360. goto next_file;
  361. }
  362. F_SET(logc, DB_LOG_DISK);
  363. cksum: /*
  364.  * Discard the region lock if we're still holding it.  (The path to
  365.  * get here is that we acquired the lock because of the caller's
  366.  * flag argument, but we found the record in the cursor's buffer.
  367.  * Improbable, but it's easy to avoid.
  368.  */
  369. if (rlock == L_ACQUIRED) {
  370. rlock = L_NONE;
  371. R_UNLOCK(dbenv, &dblp->reginfo);
  372. }
  373. /*
  374.  * Checksum: there are two types of errors -- a configuration error
  375.  * or a checksum mismatch.  The former is always bad.  The latter is
  376.  * OK if we're searching for the end of the log, and very, very bad
  377.  * if we're reading random log records.
  378.  */
  379. db_cipher = dbenv->crypto_handle;
  380. if ((ret = __db_check_chksum(dbenv, db_cipher,
  381.     hdr.chksum, rp + hdr.size, hdr.len - hdr.size, is_hmac)) != 0) {
  382. if (F_ISSET(logc, DB_LOG_SILENT_ERR)) {
  383. if (ret == 0 || ret == -1)
  384. ret = EIO;
  385. } else if (ret == -1) {
  386. __db_err(dbenv,
  387.     "DB_LOGC->get: log record checksum mismatch");
  388. __db_err(dbenv,
  389.     "DB_LOGC->get: catastrophic recovery may be required");
  390. ret = __db_panic(dbenv, DB_RUNRECOVERY);
  391. }
  392. goto err;
  393. }
  394. /*
  395.  * If we got a 0-length record, that means we're in the midst of
  396.  * some bytes that got 0'd as the result of a vtruncate.  We're
  397.  * going to have to retry.
  398.  */
  399. if (hdr.len == 0) {
  400. switch (flags) {
  401. case DB_FIRST:
  402. case DB_NEXT:
  403. /* Zero'd records always indicate the end of a file. */
  404. goto next_file;
  405. case DB_LAST:
  406. case DB_PREV:
  407. /*
  408.  * We should never get here.  If we recover a log
  409.  * file with 0's at the end, we'll treat the 0'd
  410.  * headers as the end of log and ignore them.  If
  411.  * we're reading backwards from another file, then
  412.  * the first record in that new file should have its
  413.  * prev field set correctly.
  414.  */
  415.  __db_err(dbenv,
  416. "Encountered zero length records while traversing backwards");
  417.  DB_ASSERT(0);
  418. case DB_SET:
  419. default:
  420. /* Return the 0-length record. */
  421. break;
  422. }
  423. }
  424. /* Copy the record into the user's DBT. */
  425. if ((ret = __db_retcopy(dbenv, dbt, rp + hdr.size,
  426.     (u_int32_t)(hdr.len - hdr.size),
  427.     &logc->c_dbt.data, &logc->c_dbt.ulen)) != 0)
  428. goto err;
  429. if (CRYPTO_ON(dbenv)) {
  430. if ((ret = db_cipher->decrypt(dbenv, db_cipher->data,
  431.     hdr.iv, dbt->data, hdr.len - hdr.size)) != 0) {
  432. ret = EAGAIN;
  433. goto err;
  434. }
  435. /*
  436.  * Return the original log record size to the user,
  437.  * even though we've allocated more than that, possibly.
  438.  * The log record is decrypted in the user dbt, not in
  439.  * the buffer, so we must do this here after decryption,
  440.  * not adjust the len passed to the __db_retcopy call.
  441.  */
  442. dbt->size = hdr.orig_size;
  443. }
  444. /* Update the cursor and the returned LSN. */
  445. *alsn = nlsn;
  446. logc->c_lsn = nlsn;
  447. logc->c_len = hdr.len;
  448. logc->c_prev = hdr.prev;
  449. err: if (rlock == L_ACQUIRED)
  450. R_UNLOCK(dbenv, &dblp->reginfo);
  451. return (ret);
  452. }
  453. /*
  454.  * __log_c_incursor --
  455.  * Check to see if the requested record is in the cursor's buffer.
  456.  */
  457. static int
  458. __log_c_incursor(logc, lsn, hdr, pp)
  459. DB_LOGC *logc;
  460. DB_LSN *lsn;
  461. HDR *hdr;
  462. u_int8_t **pp;
  463. {
  464. u_int8_t *p;
  465. *pp = NULL;
  466. /*
  467.  * Test to see if the requested LSN could be part of the cursor's
  468.  * buffer.
  469.  *
  470.  * The record must be part of the same file as the cursor's buffer.
  471.  * The record must start at a byte offset equal to or greater than
  472.  * the cursor buffer.
  473.  * The record must not start at a byte offset after the cursor
  474.  * buffer's end.
  475.  */
  476. if (logc->bp_lsn.file != lsn->file)
  477. return (0);
  478. if (logc->bp_lsn.offset > lsn->offset)
  479. return (0);
  480. if (logc->bp_lsn.offset + logc->bp_rlen <= lsn->offset + hdr->size)
  481. return (0);
  482. /*
  483.  * Read the record's header and check if the record is entirely held
  484.  * in the buffer.  If the record is not entirely held, get it again.
  485.  * (The only advantage in having part of the record locally is that
  486.  * we might avoid a system call because we already have the HDR in
  487.  * memory.)
  488.  *
  489.  * If the header check fails for any reason, it must be because the
  490.  * LSN is bogus.  Fail hard.
  491.  */
  492. p = logc->bp + (lsn->offset - logc->bp_lsn.offset);
  493. memcpy(hdr, p, hdr->size);
  494. if (__log_c_hdrchk(logc, hdr, NULL))
  495. return (DB_NOTFOUND);
  496. if (logc->bp_lsn.offset + logc->bp_rlen <= lsn->offset + hdr->len)
  497. return (0);
  498. *pp = p; /* Success. */
  499. return (0);
  500. }
  501. /*
  502.  * __log_c_inregion --
  503.  * Check to see if the requested record is in the region's buffer.
  504.  */
  505. static int
  506. __log_c_inregion(logc, lsn, rlockp, last_lsn, hdr, pp)
  507. DB_LOGC *logc;
  508. DB_LSN *lsn, *last_lsn;
  509. RLOCK *rlockp;
  510. HDR *hdr;
  511. u_int8_t **pp;
  512. {
  513. DB_ENV *dbenv;
  514. DB_LOG *dblp;
  515. LOG *lp;
  516. size_t len, nr;
  517. u_int32_t b_disk, b_region;
  518. int ret;
  519. u_int8_t *p;
  520. dbenv = logc->dbenv;
  521. dblp = dbenv->lg_handle;
  522. lp = ((DB_LOG *)logc->dbenv->lg_handle)->reginfo.primary;
  523. ret = 0;
  524. *pp = NULL;
  525. /* If we haven't yet acquired the log region lock, do so. */
  526. if (*rlockp == L_NONE) {
  527. *rlockp = L_ACQUIRED;
  528. R_LOCK(dbenv, &dblp->reginfo);
  529. }
  530. /*
  531.  * The routines to read from disk must avoid reading past the logical
  532.  * end of the log, so pass that information back to it.
  533.  *
  534.  * Since they're reading directly from the disk, they must also avoid
  535.  * reading past the offset we've written out.  If the log was
  536.  * truncated, it's possible that there are zeroes or garbage on
  537.  * disk after this offset, and the logical end of the log can
  538.  * come later than this point if the log buffer isn't empty.
  539.  */
  540. *last_lsn = lp->lsn;
  541. if (last_lsn->offset > lp->w_off)
  542. last_lsn->offset = lp->w_off;
  543. /*
  544.  * Test to see if the requested LSN could be part of the region's
  545.  * buffer.
  546.  *
  547.  * During recovery, we read the log files getting the information to
  548.  * initialize the region.  In that case, the region's lsn field will
  549.  * not yet have been filled in, use only the disk.
  550.  *
  551.  * The record must not start at a byte offset after the region buffer's
  552.  * end, since that means the request is for a record after the end of
  553.  * the log.  Do this test even if the region's buffer is empty -- after
  554.  * recovery, the log files may continue past the declared end-of-log,
  555.  * and the disk reading routine will incorrectly attempt to read the
  556.  * remainder of the log.
  557.  *
  558.  * Otherwise, test to see if the region's buffer actually has what we
  559.  * want:
  560.  *
  561.  * The buffer must have some useful content.
  562.  * The record must be in the same file as the region's buffer and must
  563.  * start at a byte offset equal to or greater than the region's buffer.
  564.  */
  565. if (IS_ZERO_LSN(lp->lsn))
  566. return (0);
  567. if (lsn->file > lp->lsn.file ||
  568.     (lsn->file == lp->lsn.file && lsn->offset >= lp->lsn.offset))
  569. return (DB_NOTFOUND);
  570. if (lp->b_off == 0)
  571. return (0);
  572. if (lsn->file < lp->f_lsn.file || lsn->offset < lp->f_lsn.offset)
  573. return (0);
  574. /*
  575.  * The current contents of the cursor's buffer will be useless for a
  576.  * future call -- trash it rather than try and make it look correct.
  577.  */
  578. ZERO_LSN(logc->bp_lsn);
  579. /*
  580.  * If the requested LSN is greater than the region buffer's first
  581.  * byte, we know the entire record is in the buffer.
  582.  *
  583.  * If the header check fails for any reason, it must be because the
  584.  * LSN is bogus.  Fail hard.
  585.  */
  586. if (lsn->offset > lp->f_lsn.offset) {
  587. p = dblp->bufp + (lsn->offset - lp->w_off);
  588. memcpy(hdr, p, hdr->size);
  589. if (__log_c_hdrchk(logc, hdr, NULL))
  590. return (DB_NOTFOUND);
  591. if (logc->bp_size <= hdr->len) {
  592. len = ALIGN(hdr->len * 2, 128);
  593. if ((ret =
  594.     __os_realloc(logc->dbenv, len, &logc->bp)) != 0)
  595.  return (ret);
  596. logc->bp_size = (u_int32_t)len;
  597. }
  598. memcpy(logc->bp, p, hdr->len);
  599. *pp = logc->bp;
  600. return (0);
  601. }
  602. /*
  603.  * There's a partial record, that is, the requested record starts
  604.  * in a log file and finishes in the region buffer.  We have to
  605.  * find out how many bytes of the record are in the region buffer
  606.  * so we can copy them out into the cursor buffer.  First, check
  607.  * to see if the requested record is the only record in the region
  608.  * buffer, in which case we should copy the entire region buffer.
  609.  *
  610.  * Else, walk back through the region's buffer to find the first LSN
  611.  * after the record that crosses the buffer boundary -- we can detect
  612.  * that LSN, because its "prev" field will reference the record we
  613.  * want.  The bytes we need to copy from the region buffer are the
  614.  * bytes up to the record we find.  The bytes we'll need to allocate
  615.  * to hold the log record are the bytes between the two offsets.
  616.  */
  617. b_disk = lp->w_off - lsn->offset;
  618. if (lp->b_off <= lp->len)
  619. b_region = (u_int32_t)lp->b_off;
  620. else
  621. for (p = dblp->bufp + (lp->b_off - lp->len);;) {
  622. memcpy(hdr, p, hdr->size);
  623. if (hdr->prev == lsn->offset) {
  624. b_region = (u_int32_t)(p - dblp->bufp);
  625. break;
  626. }
  627. p = dblp->bufp + (hdr->prev - lp->w_off);
  628. }
  629. /*
  630.  * If we don't have enough room for the record, we have to allocate
  631.  * space.  We have to do it while holding the region lock, which is
  632.  * truly annoying, but there's no way around it.  This call is why
  633.  * we allocate cursor buffer space when allocating the cursor instead
  634.  * of waiting.
  635.  */
  636. if (logc->bp_size <= b_region + b_disk) {
  637. len = ALIGN((b_region + b_disk) * 2, 128);
  638. if ((ret = __os_realloc(logc->dbenv, len, &logc->bp)) != 0)
  639. return (ret);
  640. logc->bp_size = (u_int32_t)len;
  641. }
  642. /* Copy the region's bytes to the end of the cursor's buffer. */
  643. p = (logc->bp + logc->bp_size) - b_region;
  644. memcpy(p, dblp->bufp, b_region);
  645. /* Release the region lock. */
  646. if (*rlockp == L_ACQUIRED) {
  647. *rlockp = L_NONE;
  648. R_UNLOCK(dbenv, &dblp->reginfo);
  649. }
  650. /*
  651.  * Read the rest of the information from disk.  Neither short reads
  652.  * or EOF are acceptable, the bytes we want had better be there.
  653.  */
  654. if (b_disk != 0) {
  655. p -= b_disk;
  656. nr = b_disk;
  657. if ((ret = __log_c_io(
  658.     logc, lsn->file, lsn->offset, p, &nr, NULL)) != 0)
  659. return (ret);
  660. if (nr < b_disk)
  661. return (__log_c_shortread(logc, 0));
  662. }
  663. /* Copy the header information into the caller's structure. */
  664. memcpy(hdr, p, hdr->size);
  665. *pp = p;
  666. return (0);
  667. }
  668. /*
  669.  * __log_c_ondisk --
  670.  * Read a record off disk.
  671.  */
  672. static int
  673. __log_c_ondisk(logc, lsn, last_lsn, flags, hdr, pp, eofp)
  674. DB_LOGC *logc;
  675. DB_LSN *lsn, *last_lsn;
  676. int flags, *eofp;
  677. HDR *hdr;
  678. u_int8_t **pp;
  679. {
  680. DB_ENV *dbenv;
  681. size_t len, nr;
  682. u_int32_t offset;
  683. int ret;
  684. dbenv = logc->dbenv;
  685. *eofp = 0;
  686. nr = hdr->size;
  687. if ((ret =
  688.     __log_c_io(logc, lsn->file, lsn->offset, hdr, &nr, eofp)) != 0)
  689. return (ret);
  690. if (*eofp)
  691. return (0);
  692. /* If we read 0 bytes, assume we've hit EOF. */
  693. if (nr == 0) {
  694. *eofp = 1;
  695. return (0);
  696. }
  697. /* Check the HDR. */
  698. if ((ret = __log_c_hdrchk(logc, hdr, eofp)) != 0)
  699. return (ret);
  700. if (*eofp)
  701. return (0);
  702. /* Otherwise, we should have gotten the bytes we wanted. */
  703. if (nr < hdr->size)
  704. return (__log_c_shortread(logc, 0));
  705. /*
  706.  * Regardless of how we return, the previous contents of the cursor's
  707.  * buffer are useless -- trash it.
  708.  */
  709. ZERO_LSN(logc->bp_lsn);
  710. /*
  711.  * Otherwise, we now (finally!) know how big the record is.  (Maybe
  712.  * we should have just stuck the length of the record into the LSN!?)
  713.  * Make sure we have enough space.
  714.  */
  715. if (logc->bp_size <= hdr->len) {
  716. len = ALIGN(hdr->len * 2, 128);
  717. if ((ret = __os_realloc(dbenv, len, &logc->bp)) != 0)
  718. return (ret);
  719. logc->bp_size = (u_int32_t)len;
  720. }
  721. /*
  722.  * If we're moving forward in the log file, read this record in at the
  723.  * beginning of the buffer.  Otherwise, read this record in at the end
  724.  * of the buffer, making sure we don't try and read before the start
  725.  * of the file.  (We prefer positioning at the end because transaction
  726.  * aborts use DB_SET to move backward through the log and we might get
  727.  * lucky.)
  728.  *
  729.  * Read a buffer's worth, without reading past the logical EOF.  The
  730.  * last_lsn may be a zero LSN, but that's OK, the test works anyway.
  731.  */
  732. if (flags == DB_FIRST || flags == DB_NEXT)
  733. offset = lsn->offset;
  734. else if (lsn->offset + hdr->len < logc->bp_size)
  735. offset = 0;
  736. else
  737. offset = (lsn->offset + hdr->len) - logc->bp_size;
  738. nr = logc->bp_size;
  739. if (lsn->file == last_lsn->file && offset + nr >= last_lsn->offset)
  740. nr = last_lsn->offset - offset;
  741. if ((ret =
  742.     __log_c_io(logc, lsn->file, offset, logc->bp, &nr, eofp)) != 0)
  743. return (ret);
  744. /*
  745.  * We should have at least gotten the bytes up-to-and-including the
  746.  * record we're reading.
  747.  */
  748. if (nr < (lsn->offset + hdr->len) - offset)
  749. return (__log_c_shortread(logc, 1));
  750. /* Set up the return information. */
  751. logc->bp_rlen = (u_int32_t)nr;
  752. logc->bp_lsn.file = lsn->file;
  753. logc->bp_lsn.offset = offset;
  754. *pp = logc->bp + (lsn->offset - offset);
  755. return (0);
  756. }
  757. /*
  758.  * __log_c_hdrchk --
  759.  *
  760.  * Check for corrupted HDRs before we use them to allocate memory or find
  761.  * records.
  762.  *
  763.  * If the log files were pre-allocated, a zero-filled HDR structure is the
  764.  * logical file end.  However, we can see buffers filled with 0's during
  765.  * recovery, too (because multiple log buffers were written asynchronously,
  766.  * and one made it to disk before a different one that logically precedes
  767.  * it in the log file.
  768.  *
  769.  * XXX
  770.  * I think there's a potential pre-allocation recovery flaw here -- if we
  771.  * fail to write a buffer at the end of a log file (by scheduling its
  772.  * write asynchronously, and it never making it to disk), then succeed in
  773.  * writing a log file block to a subsequent log file, I don't think we will
  774.  * detect that the buffer of 0's should have marked the end of the log files
  775.  * during recovery.  I think we may need to always write some garbage after
  776.  * each block write if we pre-allocate log files.  (At the moment, we do not
  777.  * pre-allocate, so this isn't currently an issue.)
  778.  *
  779.  * Check for impossibly large records.  The malloc should fail later, but we
  780.  * have customers that run mallocs that treat all allocation failures as fatal
  781.  * errors.
  782.  *
  783.  * Note that none of this is necessarily something awful happening.  We let
  784.  * the application hand us any LSN they want, and it could be a pointer into
  785.  * the middle of a log record, there's no way to tell.
  786.  */
  787. static int
  788. __log_c_hdrchk(logc, hdr, eofp)
  789. DB_LOGC *logc;
  790. HDR *hdr;
  791. int *eofp;
  792. {
  793. DB_ENV *dbenv;
  794. int ret;
  795. dbenv = logc->dbenv;
  796. /* Sanity check the log record's size. */
  797. if (hdr->len <= hdr->size)
  798. goto err;
  799. /*
  800.  * If the cursor's max-record value isn't yet set, it means we aren't
  801.  * reading these records from a log file and no check is necessary.
  802.  */
  803. if (logc->bp_maxrec != 0 && hdr->len > logc->bp_maxrec) {
  804. /*
  805.  * If we fail the check, there's the pathological case that
  806.  * we're reading the last file, it's growing, and our initial
  807.  * check information was wrong.  Get it again, to be sure.
  808.  */
  809. if ((ret = __log_c_set_maxrec(logc, NULL)) != 0) {
  810. __db_err(dbenv, "DB_LOGC->get: %s", db_strerror(ret));
  811. return (ret);
  812. }
  813. if (logc->bp_maxrec != 0 && hdr->len > logc->bp_maxrec)
  814. goto err;
  815. }
  816. if (eofp != NULL) {
  817. if (hdr->prev == 0 && hdr->chksum[0] == 0 && hdr->len == 0) {
  818. *eofp = 1;
  819. return (0);
  820. }
  821. *eofp = 0;
  822. }
  823. return (0);
  824. err: if (!F_ISSET(logc, DB_LOG_SILENT_ERR))
  825. __db_err(dbenv, "DB_LOGC->get: invalid log record header");
  826. return (EIO);
  827. }
  828. /*
  829.  * __log_c_io --
  830.  * Read records from a log file.
  831.  */
  832. static int
  833. __log_c_io(logc, fnum, offset, p, nrp, eofp)
  834. DB_LOGC *logc;
  835. u_int32_t fnum, offset;
  836. void *p;
  837. size_t *nrp;
  838. int *eofp;
  839. {
  840. DB_ENV *dbenv;
  841. DB_LOG *dblp;
  842. int ret;
  843. char *np;
  844. dbenv = logc->dbenv;
  845. dblp = dbenv->lg_handle;
  846. /*
  847.  * If we've switched files, discard the current file handle and acquire
  848.  * a new one.
  849.  */
  850. if (F_ISSET(logc->c_fh, DB_FH_VALID) && logc->bp_lsn.file != fnum)
  851. if ((ret = __os_closehandle(dbenv, logc->c_fh)) != 0)
  852. return (ret);
  853. if (!F_ISSET(logc->c_fh, DB_FH_VALID)) {
  854. if ((ret = __log_name(dblp, fnum,
  855.     &np, logc->c_fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) {
  856. /*
  857.  * If we're allowed to return EOF, assume that's the
  858.  * problem, set the EOF status flag and return 0.
  859.  */
  860. if (eofp != NULL) {
  861. *eofp = 1;
  862. ret = 0;
  863. } else if (!F_ISSET(logc, DB_LOG_SILENT_ERR))
  864. __db_err(dbenv, "DB_LOGC->get: %s: %s",
  865.     np, db_strerror(ret));
  866. __os_free(dbenv, np);
  867. return (ret);
  868. }
  869. if ((ret = __log_c_set_maxrec(logc, np)) != 0) {
  870. __db_err(dbenv,
  871.     "DB_LOGC->get: %s: %s", np, db_strerror(ret));
  872. __os_free(dbenv, np);
  873. return (ret);
  874. }
  875. __os_free(dbenv, np);
  876. }
  877. /* Seek to the record's offset. */
  878. if ((ret = __os_seek(dbenv,
  879.     logc->c_fh, 0, 0, offset, 0, DB_OS_SEEK_SET)) != 0) {
  880. if (!F_ISSET(logc, DB_LOG_SILENT_ERR))
  881. __db_err(dbenv,
  882.     "DB_LOGC->get: seek: %s", db_strerror(ret));
  883. return (ret);
  884. }
  885. /* Read the data. */
  886. if ((ret = __os_read(dbenv, logc->c_fh, p, *nrp, nrp)) != 0) {
  887. if (!F_ISSET(logc, DB_LOG_SILENT_ERR))
  888. __db_err(dbenv,
  889.     "DB_LOGC->get: read: %s", db_strerror(ret));
  890. return (ret);
  891. }
  892. return (0);
  893. }
  894. /*
  895.  * __log_c_shortread --
  896.  * Read was short -- return a consistent error message and error.
  897.  */
  898. static int
  899. __log_c_shortread(logc, silent)
  900. DB_LOGC *logc;
  901. int silent;
  902. {
  903. if (!silent || !F_ISSET(logc, DB_LOG_SILENT_ERR))
  904. __db_err(logc->dbenv, "DB_LOGC->get: short read");
  905. return (EIO);
  906. }
  907. /*
  908.  * __log_c_set_maxrec --
  909.  * Bound the maximum log record size in a log file.
  910.  */
  911. static int
  912. __log_c_set_maxrec(logc, np)
  913. DB_LOGC *logc;
  914. char *np;
  915. {
  916. DB_ENV *dbenv;
  917. DB_LOG *dblp;
  918. LOG *lp;
  919. u_int32_t mbytes, bytes;
  920. int ret;
  921. dbenv = logc->dbenv;
  922. dblp = dbenv->lg_handle;
  923. /*
  924.  * We don't want to try and allocate huge chunks of memory because
  925.  * applications with error-checking malloc's often consider that a
  926.  * hard failure.  If we're about to look at a corrupted record with
  927.  * a bizarre size, we need to know before trying to allocate space
  928.  * to hold it.  We could read the persistent data at the beginning
  929.  * of the file but that's hard -- we may have to decrypt it, checksum
  930.  * it and so on.  Stat the file instead.
  931.  */
  932. if ((ret =
  933.     __os_ioinfo(dbenv, np, logc->c_fh, &mbytes, &bytes, NULL)) != 0)
  934. return (ret);
  935. logc->bp_maxrec = mbytes * MEGABYTE + bytes;
  936. /*
  937.  * If reading from the log file currently being written, we could get
  938.  * an incorrect size, that is, if the cursor was opened on the file
  939.  * when it had only a few hundred bytes, and then the cursor used to
  940.  * move forward in the file, after more log records were written, the
  941.  * original stat value would be wrong.  Use the maximum of the current
  942.  * log file size and the size of the buffer -- that should represent
  943.  * the max of any log record currently in the file.
  944.  *
  945.  * The log buffer size is set when the environment is opened and never
  946.  * changed, we don't need a lock on it.
  947.  */
  948. lp = dblp->reginfo.primary;
  949. logc->bp_maxrec += lp->buffer_size;
  950. return (0);
  951. }