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

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_get.c,v 11.32 2001/01/11 18:19:53 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. #ifdef  HAVE_RPC
  17. #include "db_server.h"
  18. #endif
  19. #include "db_int.h"
  20. #include "db_page.h"
  21. #include "log.h"
  22. #include "hash.h"
  23. #ifdef HAVE_RPC
  24. #include "gen_client_ext.h"
  25. #include "rpc_client_ext.h"
  26. #endif
  27. /*
  28.  * log_get --
  29.  * Get a log record.
  30.  */
  31. int
  32. log_get(dbenv, alsn, dbt, flags)
  33. DB_ENV *dbenv;
  34. DB_LSN *alsn;
  35. DBT *dbt;
  36. u_int32_t flags;
  37. {
  38. DB_LOG *dblp;
  39. DB_LSN saved_lsn;
  40. int ret;
  41. #ifdef HAVE_RPC
  42. if (F_ISSET(dbenv, DB_ENV_RPCCLIENT))
  43. return (__dbcl_log_get(dbenv, alsn, dbt, flags));
  44. #endif
  45. PANIC_CHECK(dbenv);
  46. ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, DB_INIT_LOG);
  47. /* Validate arguments. */
  48. if (flags != DB_CHECKPOINT && flags != DB_CURRENT &&
  49.     flags != DB_FIRST && flags != DB_LAST &&
  50.     flags != DB_NEXT && flags != DB_PREV && flags != DB_SET)
  51. return (__db_ferr(dbenv, "log_get", 1));
  52. if (F_ISSET(dbenv, DB_ENV_THREAD)) {
  53. if (flags == DB_NEXT || flags == DB_PREV || flags == DB_CURRENT)
  54. return (__db_ferr(dbenv, "log_get", 1));
  55. if (!F_ISSET(dbt,
  56.     DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM))
  57. return (__db_ferr(dbenv, "threaded data", 1));
  58. }
  59. dblp = dbenv->lg_handle;
  60. R_LOCK(dbenv, &dblp->reginfo);
  61. /*
  62.  * The alsn field is only initialized if DB_SET is the flag, so this
  63.  * assignment causes uninitialized memory complaints for other flag
  64.  * values.
  65.  */
  66. #ifdef UMRW
  67. if (flags == DB_SET)
  68. saved_lsn = *alsn;
  69. else
  70. ZERO_LSN(saved_lsn);
  71. #else
  72. saved_lsn = *alsn;
  73. #endif
  74. /*
  75.  * If we get one of the log's header records, repeat the operation.
  76.  * This assumes that applications don't ever request the log header
  77.  * records by LSN, but that seems reasonable to me.
  78.  */
  79. if ((ret = __log_get(dblp,
  80.     alsn, dbt, flags, 0)) == 0 && alsn->offset == 0) {
  81. switch (flags) {
  82. case DB_FIRST:
  83. flags = DB_NEXT;
  84. break;
  85. case DB_LAST:
  86. flags = DB_PREV;
  87. break;
  88. }
  89. if (F_ISSET(dbt, DB_DBT_MALLOC)) {
  90. __os_free(dbt->data, dbt->size);
  91. dbt->data = NULL;
  92. }
  93. ret = __log_get(dblp, alsn, dbt, flags, 0);
  94. }
  95. if (ret != 0)
  96. *alsn = saved_lsn;
  97. R_UNLOCK(dbenv, &dblp->reginfo);
  98. return (ret);
  99. }
  100. /*
  101.  * __log_get --
  102.  * Get a log record; internal version.
  103.  *
  104.  * PUBLIC: int __log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t, int));
  105.  */
  106. int
  107. __log_get(dblp, alsn, dbt, flags, silent)
  108. DB_LOG *dblp;
  109. DB_LSN *alsn;
  110. DBT *dbt;
  111. u_int32_t flags;
  112. int silent;
  113. {
  114. DB_ENV *dbenv;
  115. DB_LSN nlsn;
  116. HDR hdr;
  117. LOG *lp;
  118. const char *fail;
  119. char *np, *tbuf;
  120. int cnt, ret;
  121. logfile_validity status;
  122. size_t len, nr;
  123. u_int32_t offset;
  124. u_int8_t *p;
  125. void *shortp, *readp;
  126. lp = dblp->reginfo.primary;
  127. fail = np = tbuf = NULL;
  128. dbenv = dblp->dbenv;
  129. nlsn = dblp->c_lsn;
  130. switch (flags) {
  131. case DB_CHECKPOINT:
  132. nlsn = lp->chkpt_lsn;
  133. if (IS_ZERO_LSN(nlsn)) {
  134. /* No db_err. The caller may expect this. */
  135. ret = ENOENT;
  136. goto err2;
  137. }
  138. break;
  139. case DB_NEXT: /* Next log record. */
  140. if (!IS_ZERO_LSN(nlsn)) {
  141. /* Increment the cursor by the cursor record size. */
  142. nlsn.offset += dblp->c_len;
  143. break;
  144. }
  145. /* FALLTHROUGH */
  146. case DB_FIRST: /* Find the first log record. */
  147. /* Find the first log file. */
  148. if ((ret = __log_find(dblp, 1, &cnt, &status)) != 0)
  149. goto err2;
  150. /*
  151.  * We want any readable version, so either DB_LV_NORMAL
  152.  * or DB_LV_OLD_READABLE is acceptable here.  If it's
  153.  * not one of those two, there is no first log record that
  154.  * we can read.
  155.  */
  156. if (status != DB_LV_NORMAL && status != DB_LV_OLD_READABLE) {
  157. ret = DB_NOTFOUND;
  158. goto err2;
  159. }
  160. /*
  161.  * We may have only entered records in the buffer, and not
  162.  * yet written a log file.  If no log files were found and
  163.  * there's anything in the buffer, it belongs to file 1.
  164.  */
  165. if (cnt == 0)
  166. cnt = 1;
  167. nlsn.file = cnt;
  168. nlsn.offset = 0;
  169. break;
  170. case DB_CURRENT: /* Current log record. */
  171. break;
  172. case DB_PREV: /* Previous log record. */
  173. if (!IS_ZERO_LSN(nlsn)) {
  174. /* If at start-of-file, move to the previous file. */
  175. if (nlsn.offset == 0) {
  176. if (nlsn.file == 1 ||
  177.     __log_valid(dblp,
  178. nlsn.file - 1, 0, &status) != 0)
  179. return (DB_NOTFOUND);
  180. if (status != DB_LV_NORMAL &&
  181.     status != DB_LV_OLD_READABLE)
  182. return (DB_NOTFOUND);
  183. --nlsn.file;
  184. nlsn.offset = dblp->c_off;
  185. } else
  186. nlsn.offset = dblp->c_off;
  187. break;
  188. }
  189. /* FALLTHROUGH */
  190. case DB_LAST: /* Last log record. */
  191. nlsn.file = lp->lsn.file;
  192. nlsn.offset = lp->lsn.offset - lp->len;
  193. break;
  194. case DB_SET: /* Set log record. */
  195. nlsn = *alsn;
  196. break;
  197. }
  198. if (0) { /* Move to the next file. */
  199. next_file: ++nlsn.file;
  200. nlsn.offset = 0;
  201. }
  202. /* Return 1 if the request is past the end of the log. */
  203. if (nlsn.file > lp->lsn.file ||
  204.     (nlsn.file == lp->lsn.file && nlsn.offset >= lp->lsn.offset))
  205. return (DB_NOTFOUND);
  206. /* If we've switched files, discard the current file handle. */
  207. if (dblp->c_lsn.file != nlsn.file &&
  208.     F_ISSET(&dblp->c_fh, DB_FH_VALID)) {
  209. (void)__os_closehandle(&dblp->c_fh);
  210. }
  211. /* If the entire record is in the in-memory buffer, copy it out. */
  212. if (nlsn.file == lp->lsn.file && nlsn.offset >= lp->w_off) {
  213. /* Copy the header. */
  214. p = dblp->bufp + (nlsn.offset - lp->w_off);
  215. memcpy(&hdr, p, sizeof(HDR));
  216. /* Copy the record. */
  217. len = hdr.len - sizeof(HDR);
  218. if ((ret = __db_retcopy(NULL, dbt, p + sizeof(HDR),
  219.     len, &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0)
  220. goto err2;
  221. goto cksum;
  222. }
  223. shortp = NULL;
  224. /* Acquire a file descriptor. */
  225. if (!F_ISSET(&dblp->c_fh, DB_FH_VALID)) {
  226. if ((ret = __log_name(dblp, nlsn.file,
  227.     &np, &dblp->c_fh, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) {
  228. fail = np;
  229. goto err1;
  230. }
  231. __os_freestr(np);
  232. np = NULL;
  233. }
  234. /* See if we've already read this */
  235. if (nlsn.file == dblp->r_file && nlsn.offset > dblp->r_off
  236.      && nlsn.offset + sizeof(HDR) < dblp->r_off + dblp->r_size)
  237. goto got_header;
  238. /*
  239.  * Seek to the header offset and read the header.  Because the file
  240.  * may be pre-allocated, we have to make sure that we're not reading
  241.  * past the information in the start of the in-memory buffer.
  242.  */
  243. readp = &hdr;
  244. offset = nlsn.offset;
  245. if (nlsn.file == lp->lsn.file && offset + sizeof(HDR) > lp->w_off)
  246. nr = lp->w_off - offset;
  247. else if (dblp->readbufp == NULL)
  248. nr = sizeof(HDR);
  249. else  {
  250. nr = lp->buffer_size;
  251. readp = dblp->readbufp;
  252. dblp->r_file = nlsn.file;
  253. /* Going backwards.  Put the current in the middle. */
  254. if (flags == DB_PREV || flags == DB_LAST) {
  255. if (offset <= lp->buffer_size/2)
  256. offset = 0;
  257. else
  258. offset = offset - lp->buffer_size/2;
  259. }
  260. if (nlsn.file == lp->lsn.file && offset + nr > lp->lsn.offset)
  261. nr = lp->lsn.offset - offset;
  262. dblp->r_off = offset;
  263. }
  264. if ((ret = __os_seek(dblp->dbenv,
  265.     &dblp->c_fh, 0, 0, offset, 0, DB_OS_SEEK_SET)) != 0) {
  266. fail = "seek";
  267. goto err1;
  268. }
  269. if ((ret = __os_read(dblp->dbenv, &dblp->c_fh, readp, nr, &nr)) != 0) {
  270. fail = "read";
  271. goto err1;
  272. }
  273. if (nr < sizeof(HDR)) {
  274. /* If read returns EOF, try the next file. */
  275. if (nr == 0) {
  276. if (flags != DB_NEXT || nlsn.file == lp->lsn.file)
  277. goto corrupt;
  278. goto next_file;
  279. }
  280. if (dblp->readbufp != NULL)
  281. memcpy((u_int8_t *) &hdr, readp, nr);
  282. /*
  283.  * If read returns a short count the rest of the record has
  284.  * to be in the in-memory buffer.
  285.  */
  286. if (lp->b_off < sizeof(HDR) - nr)
  287. goto corrupt;
  288. /* Get the rest of the header from the in-memory buffer. */
  289. memcpy((u_int8_t *)&hdr + nr, dblp->bufp, sizeof(HDR) - nr);
  290. if (hdr.len == 0)
  291. goto next_file;
  292. shortp = dblp->bufp + (sizeof(HDR) - nr);
  293. }
  294. else if (dblp->readbufp != NULL) {
  295. dblp->r_size = nr;
  296. got_header: memcpy((u_int8_t *)&hdr,
  297.     dblp->readbufp + (nlsn.offset - dblp->r_off), sizeof(HDR));
  298. }
  299. /*
  300.  * Check for buffers of 0's, that's what we usually see during recovery,
  301.  * although it's certainly not something on which we can depend.  Check
  302.  * for impossibly large records.  The malloc should fail later, but we
  303.  * have customers that run mallocs that handle allocation failure as a
  304.  * fatal error.
  305.  */
  306. if (hdr.len == 0)
  307. goto next_file;
  308. if (hdr.len <= sizeof(HDR) || hdr.len > lp->persist.lg_max)
  309. goto corrupt;
  310. len = hdr.len - sizeof(HDR);
  311. /* If we've already moved to the in-memory buffer, fill from there. */
  312. if (shortp != NULL) {
  313. if (lp->b_off < ((u_int8_t *)shortp - dblp->bufp) + len)
  314. goto corrupt;
  315. if ((ret = __db_retcopy(NULL, dbt, shortp, len,
  316.     &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0)
  317. goto err2;
  318. goto cksum;
  319. }
  320. if (dblp->readbufp != NULL) {
  321. if (nlsn.offset + hdr.len < dblp->r_off + dblp->r_size) {
  322. if ((ret = __db_retcopy(NULL, dbt, dblp->readbufp +
  323.      (nlsn.offset - dblp->r_off) + sizeof(HDR),
  324.      len, &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0)
  325. goto err2;
  326. goto cksum;
  327. } else if ((ret = __os_seek(dblp->dbenv, &dblp->c_fh, 0,
  328.     0, nlsn.offset + sizeof(HDR), 0, DB_OS_SEEK_SET)) != 0) {
  329. fail = "seek";
  330. goto err1;
  331. }
  332. }
  333. /*
  334.  * Allocate temporary memory to hold the record.
  335.  *
  336.  * XXX
  337.  * We're calling malloc(3) with a region locked.  This isn't
  338.  * a good idea.
  339.  */
  340. if ((ret = __os_malloc(dbenv, len, NULL, &tbuf)) != 0)
  341. goto err1;
  342. /*
  343.  * Read the record into the buffer.  If read returns a short count,
  344.  * there was an error or the rest of the record is in the in-memory
  345.  * buffer.  Note, the information may be garbage if we're in recovery,
  346.  * so don't read past the end of the buffer's memory.
  347.  *
  348.  * Because the file may be pre-allocated, we have to make sure that
  349.  * we're not reading past the information in the start of the in-memory
  350.  * buffer.
  351.  */
  352. if (nlsn.file == lp->lsn.file &&
  353.     nlsn.offset + sizeof(HDR) + len > lp->w_off)
  354. nr = lp->w_off - (nlsn.offset + sizeof(HDR));
  355. else
  356. nr = len;
  357. if ((ret = __os_read(dblp->dbenv, &dblp->c_fh, tbuf, nr, &nr)) != 0) {
  358. fail = "read";
  359. goto err1;
  360. }
  361. if (len - nr > lp->buffer_size)
  362. goto corrupt;
  363. if (nr != len) {
  364. if (lp->b_off < len - nr)
  365. goto corrupt;
  366. /* Get the rest of the record from the in-memory buffer. */
  367. memcpy((u_int8_t *)tbuf + nr, dblp->bufp, len - nr);
  368. }
  369. /* Copy the record into the user's DBT. */
  370. if ((ret = __db_retcopy(NULL, dbt, tbuf, len,
  371.     &dblp->c_dbt.data, &dblp->c_dbt.ulen)) != 0)
  372. goto err2;
  373. __os_free(tbuf, 0);
  374. tbuf = NULL;
  375. cksum: /*
  376.  * If the user specified a partial record read, the checksum can't
  377.  * match.  It's not an obvious thing to do, but a user testing for
  378.  * the length of a record might do it.
  379.  */
  380. if (!F_ISSET(dbt, DB_DBT_PARTIAL) &&
  381.     hdr.cksum != __ham_func4(NULL, dbt->data, dbt->size)) {
  382. if (!silent)
  383. __db_err(dbenv, "log_get: checksum mismatch");
  384. goto corrupt;
  385. }
  386. /* Update the cursor and the return lsn. */
  387. dblp->c_off = hdr.prev;
  388. dblp->c_len = hdr.len;
  389. dblp->c_lsn = nlsn;
  390. *alsn = nlsn;
  391. return (0);
  392. corrupt:/*
  393.  * This is the catchall -- for some reason we didn't find enough
  394.  * information or it wasn't reasonable information, and it wasn't
  395.  * because a system call failed.
  396.  */
  397. ret = EIO;
  398. fail = "read";
  399. err1: if (!silent) {
  400. if (fail == NULL)
  401. __db_err(dbenv, "log_get: %s", db_strerror(ret));
  402. else
  403. __db_err(dbenv,
  404.     "log_get: %s: %s", fail, db_strerror(ret));
  405. }
  406. err2: if (np != NULL)
  407. __os_freestr(np);
  408. if (tbuf != NULL)
  409. __os_free(tbuf, 0);
  410. return (ret);
  411. }