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

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_put.c,v 11.112 2002/09/10 02:39:26 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #if TIME_WITH_SYS_TIME
  14. #include <sys/time.h>
  15. #include <time.h>
  16. #else
  17. #if HAVE_SYS_TIME_H
  18. #include <sys/time.h>
  19. #else
  20. #include <time.h>
  21. #endif
  22. #endif
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <unistd.h>
  26. #endif
  27. #include "db_int.h"
  28. #include "dbinc/crypto.h"
  29. #include "dbinc/hmac.h"
  30. #include "dbinc/log.h"
  31. #include "dbinc/rep.h"
  32. #include "dbinc/txn.h"
  33. static int __log_encrypt_record __P((DB_ENV *, DBT *, HDR *, u_int32_t));
  34. static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t));
  35. static int __log_flush_commit __P((DB_ENV *, const DB_LSN *, u_int32_t));
  36. static int __log_flush_int __P((DB_LOG *, const DB_LSN *, int));
  37. static int __log_newfh __P((DB_LOG *));
  38. static int __log_put_next __P((DB_ENV *,
  39.     DB_LSN *, const DBT *, HDR *, DB_LSN *));
  40. static int __log_putr __P((DB_LOG *,
  41.     DB_LSN *, const DBT *, u_int32_t, HDR *));
  42. static int __log_write __P((DB_LOG *, void *, u_int32_t));
  43. /*
  44.  * __log_put --
  45.  * Write a log record.  This is the public interface, DB_ENV->log_put.
  46.  *
  47.  * PUBLIC: int __log_put __P((DB_ENV *, DB_LSN *, const DBT *, u_int32_t));
  48.  */
  49. int
  50. __log_put(dbenv, lsnp, udbt, flags)
  51. DB_ENV *dbenv;
  52. DB_LSN *lsnp;
  53. const DBT *udbt;
  54. u_int32_t flags;
  55. {
  56. DB_CIPHER *db_cipher;
  57. DBT *dbt, t;
  58. DB_LOG *dblp;
  59. DB_LSN lsn, old_lsn;
  60. HDR hdr;
  61. LOG *lp;
  62. u_int32_t do_flush, op, writeonly;
  63. int lock_held, need_free, ret;
  64. u_int8_t *key;
  65. PANIC_CHECK(dbenv);
  66. ENV_REQUIRES_CONFIG(dbenv,
  67.     dbenv->lg_handle, "DB_ENV->log_put", DB_INIT_LOG);
  68. /* Validate arguments. */
  69. op = DB_OPFLAGS_MASK & flags;
  70. if (op != 0 && op != DB_COMMIT)
  71. return (__db_ferr(dbenv, "DB_ENV->log_put", 0));
  72. /* Check for allowed bit-flags. */
  73. if (LF_ISSET(~(DB_OPFLAGS_MASK |
  74.     DB_FLUSH | DB_NOCOPY | DB_PERMANENT | DB_WRNOSYNC)))
  75. return (__db_ferr(dbenv, "DB_ENV->log_put", 0));
  76. /* DB_WRNOSYNC and DB_FLUSH are mutually exclusive. */
  77. if (LF_ISSET(DB_WRNOSYNC) && LF_ISSET(DB_FLUSH))
  78. return (__db_ferr(dbenv, "DB_ENV->log_put", 1));
  79. /* Replication clients should never write log records. */
  80. if (F_ISSET(dbenv, DB_ENV_REP_CLIENT) ||
  81.     F_ISSET(dbenv, DB_ENV_REP_LOGSONLY)) {
  82. __db_err(dbenv,
  83.     "DB_ENV->log_put is illegal on replication clients");
  84. return (EINVAL);
  85. }
  86. dblp = dbenv->lg_handle;
  87. lp = dblp->reginfo.primary;
  88. db_cipher = dbenv->crypto_handle;
  89. dbt = &t;
  90. t = *udbt;
  91. lock_held = need_free = 0;
  92. do_flush = LF_ISSET(DB_FLUSH);
  93. writeonly = LF_ISSET(DB_WRNOSYNC);
  94. /*
  95.  * If we are coming from the logging code, we use an internal
  96.  * flag, DB_NOCOPY, because we know we can overwrite/encrypt
  97.  * the log record in place.  Otherwise, if a user called log_put
  98.  * then we must copy it to new memory so that we know we can
  99.  * write it.
  100.  *
  101.  * We also must copy it to new memory if we are a replication
  102.  * master so that we retain an unencrypted copy of the log
  103.  * record to send to clients.
  104.  */
  105. if (!LF_ISSET(DB_NOCOPY) || F_ISSET(dbenv, DB_ENV_REP_MASTER)) {
  106. if (CRYPTO_ON(dbenv))
  107. t.size += db_cipher->adj_size(udbt->size);
  108. if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
  109. goto err;
  110. need_free = 1;
  111. memcpy(t.data, udbt->data, udbt->size);
  112. }
  113. if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, udbt->size)) != 0)
  114. goto err;
  115. if (CRYPTO_ON(dbenv))
  116. key = db_cipher->mac_key;
  117. else
  118. key = NULL;
  119. /* Otherwise, we actually have a record to put.  Put it. */
  120. /* Before we grab the region lock, calculate the record's checksum. */
  121. __db_chksum(dbt->data, dbt->size, key, hdr.chksum);
  122. R_LOCK(dbenv, &dblp->reginfo);
  123. lock_held = 1;
  124. ZERO_LSN(old_lsn);
  125. if ((ret = __log_put_next(dbenv, &lsn, dbt, &hdr, &old_lsn)) != 0)
  126. goto err;
  127. if (F_ISSET(dbenv, DB_ENV_REP_MASTER)) {
  128. /*
  129.  * Replication masters need to drop the lock to send
  130.  * messages, but we want to drop and reacquire it a minimal
  131.  * number of times.
  132.  */
  133. R_UNLOCK(dbenv, &dblp->reginfo);
  134. lock_held = 0;
  135. /*
  136.  * If we changed files and we're in a replicated
  137.  * environment, we need to inform our clients now that
  138.  * we've dropped the region lock.
  139.  *
  140.  * Note that a failed NEWFILE send is a dropped message
  141.  * that our client can handle, so we can ignore it.  It's
  142.  * possible that the record we already put is a commit, so
  143.  * we don't just want to return failure.
  144.  */
  145. if (!IS_ZERO_LSN(old_lsn))
  146. (void)__rep_send_message(dbenv,
  147.     DB_EID_BROADCAST, REP_NEWFILE, &old_lsn, NULL, 0);
  148. /*
  149.  * Then send the log record itself on to our clients.
  150.  *
  151.  * If the send fails and we're a commit or checkpoint,
  152.  * there's nothing we can do;  the record's in the log.
  153.  * Flush it, even if we're running with TXN_NOSYNC, on the
  154.  * grounds that it should be in durable form somewhere.
  155.  */
  156. /*
  157.  * !!!
  158.  * In the crypto case, we MUST send the udbt, not the
  159.  * now-encrypted dbt.  Clients have no way to decrypt
  160.  * without the header.
  161.  */
  162. if ((__rep_send_message(dbenv,
  163.     DB_EID_BROADCAST, REP_LOG, &lsn, udbt, flags) != 0) &&
  164.     LF_ISSET(DB_PERMANENT))
  165. do_flush |= DB_FLUSH;
  166. }
  167. /*
  168.  * If needed, do a flush.  Note that failures at this point
  169.  * are only permissible if we know we haven't written a commit
  170.  * record;  __log_flush_commit is responsible for enforcing this.
  171.  *
  172.  * If a flush is not needed, see if WRITE_NOSYNC was set and we
  173.  * need to write out the log buffer.
  174.  */
  175. if (do_flush || writeonly) {
  176. if (!lock_held) {
  177. R_LOCK(dbenv, &dblp->reginfo);
  178. lock_held = 1;
  179. }
  180. if (do_flush)
  181. ret = __log_flush_commit(dbenv, &lsn, flags);
  182. else if (lp->b_off != 0)
  183. /*
  184.  * writeonly: if there's anything in the current
  185.  * log buffer, we need to write it out.
  186.  */
  187. if ((ret = __log_write(dblp,
  188.     dblp->bufp, (u_int32_t)lp->b_off)) == 0)
  189. lp->b_off = 0;
  190. }
  191. err: if (lock_held)
  192. R_UNLOCK(dbenv, &dblp->reginfo);
  193. if (need_free)
  194. __os_free(dbenv, dbt->data);
  195. if (ret == 0)
  196. *lsnp = lsn;
  197. return (ret);
  198. }
  199. /*
  200.  * __log_txn_lsn --
  201.  *
  202.  * PUBLIC: void __log_txn_lsn
  203.  * PUBLIC:     __P((DB_ENV *, DB_LSN *, u_int32_t *, u_int32_t *));
  204.  */
  205. void
  206. __log_txn_lsn(dbenv, lsnp, mbytesp, bytesp)
  207. DB_ENV *dbenv;
  208. DB_LSN *lsnp;
  209. u_int32_t *mbytesp, *bytesp;
  210. {
  211. DB_LOG *dblp;
  212. LOG *lp;
  213. dblp = dbenv->lg_handle;
  214. lp = dblp->reginfo.primary;
  215. R_LOCK(dbenv, &dblp->reginfo);
  216. /*
  217.  * We are trying to get the LSN of the last entry in the log.  We use
  218.  * this in two places: 1) DB_ENV->txn_checkpiont uses it as a first
  219.  * value when trying to compute an LSN such that all transactions begun
  220.  * before it are complete.   2) DB_ENV->txn_begin uses it as the
  221.  * begin_lsn.
  222.  *
  223.  * Typically, it's easy to get the last written LSN, you simply look
  224.  * at the current log pointer and back up the number of bytes of the
  225.  * last log record.  However, if the last thing we did was write the
  226.  * log header of a new log file, then, this doesn't work, so we return
  227.  * the first log record that will be written in this new file.
  228.  */
  229. *lsnp = lp->lsn;
  230. if (lp->lsn.offset > lp->len)
  231. lsnp->offset -= lp->len;
  232. /*
  233.  * Since we're holding the log region lock, return the bytes put into
  234.  * the log since the last checkpoint, transaction checkpoint needs it.
  235.  *
  236.  * We add the current buffer offset so as to count bytes that have not
  237.  * yet been written, but are sitting in the log buffer.
  238.  */
  239. if (mbytesp != NULL) {
  240. *mbytesp = lp->stat.st_wc_mbytes;
  241. *bytesp = (u_int32_t)(lp->stat.st_wc_bytes + lp->b_off);
  242. lp->stat.st_wc_mbytes = lp->stat.st_wc_bytes = 0;
  243. }
  244. R_UNLOCK(dbenv, &dblp->reginfo);
  245. }
  246. /*
  247.  * __log_put_next --
  248.  * Put the given record as the next in the log, wherever that may
  249.  * turn out to be.
  250.  */
  251. static int
  252. __log_put_next(dbenv, lsn, dbt, hdr, old_lsnp)
  253. DB_ENV *dbenv;
  254. DB_LSN *lsn;
  255. const DBT *dbt;
  256. HDR *hdr;
  257. DB_LSN *old_lsnp;
  258. {
  259. DB_LOG *dblp;
  260. DB_LSN old_lsn;
  261. LOG *lp;
  262. int newfile, ret;
  263. dblp = dbenv->lg_handle;
  264. lp = dblp->reginfo.primary;
  265. /*
  266.  * Save a copy of lp->lsn before we might decide to switch log
  267.  * files and change it.  If we do switch log files, and we're
  268.  * doing replication, we'll need to tell our clients about the
  269.  * switch, and they need to receive a NEWFILE message
  270.  * with this "would-be" LSN in order to know they're not
  271.  * missing any log records.
  272.  */
  273. old_lsn = lp->lsn;
  274. newfile = 0;
  275. /*
  276.  * If this information won't fit in the file, or if we're a
  277.  * replication client environment and have been told to do so,
  278.  * swap files.
  279.  */
  280. if (lp->lsn.offset == 0 ||
  281.     lp->lsn.offset + hdr->size + dbt->size > lp->log_size) {
  282. if (hdr->size + sizeof(LOGP) + dbt->size > lp->log_size) {
  283. __db_err(dbenv,
  284.     "DB_ENV->log_put: record larger than maximum file size");
  285. return (EINVAL);
  286. }
  287. if ((ret = __log_newfile(dblp, NULL)) != 0)
  288. return (ret);
  289. /*
  290.  * Flag that we switched files, in case we're a master
  291.  * and need to send this information to our clients.
  292.  * We postpone doing the actual send until we can
  293.  * safely release the log region lock and are doing so
  294.  * anyway.
  295.  */
  296. newfile = 1;
  297. if (dbenv->db_noticecall != NULL)
  298. dbenv->db_noticecall(dbenv, DB_NOTICE_LOGFILE_CHANGED);
  299. }
  300. /*
  301.  * The offset into the log file at this point is the LSN where
  302.  * we're about to put this record, and is the LSN the caller wants.
  303.  */
  304. *lsn = lp->lsn;
  305. /* If we switched log files, let our caller know where. */
  306. if (newfile)
  307. *old_lsnp = old_lsn;
  308. /* Actually put the record. */
  309. return (__log_putr(dblp, lsn, dbt, lp->lsn.offset - lp->len, hdr));
  310. }
  311. /*
  312.  * __log_flush_commit --
  313.  * Flush a record for which the DB_FLUSH flag to log_put has been set.
  314.  */
  315. static int
  316. __log_flush_commit(dbenv, lsnp, flags)
  317. DB_ENV *dbenv;
  318. const DB_LSN *lsnp;
  319. u_int32_t flags;
  320. {
  321. DB_LOG *dblp;
  322. DB_LSN flush_lsn;
  323. LOG *lp;
  324. int ret;
  325. u_int32_t op;
  326. dblp = dbenv->lg_handle;
  327. lp = dblp->reginfo.primary;
  328. flush_lsn = *lsnp;
  329. op = DB_OPFLAGS_MASK & flags;
  330. if ((ret = __log_flush_int(dblp, &flush_lsn, 1)) == 0)
  331. return (0);
  332. /*
  333.  * If a flush supporting a transaction commit fails, we must abort the
  334.  * transaction.  (If we aren't doing a commit, return the failure; if
  335.  * if the commit we care about made it to disk successfully, we just
  336.  * ignore the failure, because there's no way to undo the commit.)
  337.  */
  338. if (op != DB_COMMIT)
  339. return (ret);
  340. if (flush_lsn.file != lp->lsn.file || flush_lsn.offset < lp->w_off)
  341. return (0);
  342. /*
  343.  * Else, make sure that the commit record does not get out after we
  344.  * abort the transaction.  Do this by overwriting the commit record
  345.  * in the buffer.  (Note that other commits in this buffer will wait
  346.  * wait until a sucessful write happens, we do not wake them.)  We
  347.  * point at the right part of the buffer and write an abort record
  348.  * over the commit.  We must then try and flush the buffer again,
  349.  * since the interesting part of the buffer may have actually made
  350.  * it out to disk before there was a failure, we can't know for sure.
  351.  */
  352. if (__txn_force_abort(dbenv,
  353.     dblp->bufp + flush_lsn.offset - lp->w_off) == 0)
  354. (void)__log_flush_int(dblp, &flush_lsn, 0);
  355. return (ret);
  356. }
  357. /*
  358.  * __log_newfile --
  359.  * Initialize and switch to a new log file.  (Note that this is
  360.  * called both when no log yet exists and when we fill a log file.)
  361.  *
  362.  * PUBLIC: int __log_newfile __P((DB_LOG *, DB_LSN *));
  363.  */
  364. int
  365. __log_newfile(dblp, lsnp)
  366. DB_LOG *dblp;
  367. DB_LSN *lsnp;
  368. {
  369. DB_CIPHER *db_cipher;
  370. DB_ENV *dbenv;
  371. DB_LSN lsn;
  372. DBT t;
  373. HDR hdr;
  374. LOG *lp;
  375. int need_free, ret;
  376. u_int32_t lastoff;
  377. size_t tsize;
  378. u_int8_t *tmp;
  379. dbenv = dblp->dbenv;
  380. lp = dblp->reginfo.primary;
  381. /* If we're not at the beginning of a file already, start a new one. */
  382. if (lp->lsn.offset != 0) {
  383. /*
  384.  * Flush the log so this file is out and can be closed.  We
  385.  * cannot release the region lock here because we need to
  386.  * protect the end of the file while we switch.  In
  387.  * particular, a thread with a smaller record than ours
  388.  * could detect that there is space in the log. Even
  389.  * blocking that event by declaring the file full would
  390.  * require all threads to wait here so that the lsn.file
  391.  * can be moved ahead after the flush completes.  This
  392.  * probably can be changed if we had an lsn for the
  393.  * previous file and one for the curent, but it does not
  394.  * seem like this would get much more throughput, if any.
  395.  */
  396. if ((ret = __log_flush_int(dblp, NULL, 0)) != 0)
  397. return (ret);
  398. DB_ASSERT(lp->b_off == 0);
  399. /*
  400.  * Save the last known offset from the previous file, we'll
  401.  * need it to initialize the persistent header information.
  402.  */
  403. lastoff = lp->lsn.offset;
  404. /* Point the current LSN to the new file. */
  405. ++lp->lsn.file;
  406. lp->lsn.offset = 0;
  407. /* Reset the file write offset. */
  408. lp->w_off = 0;
  409. } else
  410. lastoff = 0;
  411. /*
  412.  * Insert persistent information as the first record in every file.
  413.  * Note that the previous length is wrong for the very first record
  414.  * of the log, but that's okay, we check for it during retrieval.
  415.  */
  416. DB_ASSERT(lp->b_off == 0);
  417. memset(&t, 0, sizeof(t));
  418. memset(&hdr, 0, sizeof(HDR));
  419. need_free = 0;
  420. tsize = sizeof(LOGP);
  421. db_cipher = dbenv->crypto_handle;
  422. if (CRYPTO_ON(dbenv))
  423. tsize += db_cipher->adj_size(tsize);
  424. if ((ret = __os_calloc(dbenv, 1, tsize, &tmp)) != 0)
  425. return (ret);
  426. lp->persist.log_size = lp->log_size = lp->log_nsize;
  427. memcpy(tmp, &lp->persist, sizeof(LOGP));
  428. t.data = tmp;
  429. t.size = (u_int32_t)tsize;
  430. need_free = 1;
  431. if ((ret =
  432.     __log_encrypt_record(dbenv, &t, &hdr, (u_int32_t)tsize)) != 0)
  433. goto err;
  434. __db_chksum(t.data, t.size,
  435.     (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
  436. lsn = lp->lsn;
  437. if ((ret = __log_putr(dblp, &lsn,
  438.     &t, lastoff == 0 ? 0 : lastoff - lp->len, &hdr)) != 0)
  439. goto err;
  440. /* Update the LSN information returned to the caller. */
  441. if (lsnp != NULL)
  442. *lsnp = lp->lsn;
  443. err:
  444. if (need_free)
  445. __os_free(dbenv, tmp);
  446. return (ret);
  447. }
  448. /*
  449.  * __log_putr --
  450.  * Actually put a record into the log.
  451.  */
  452. static int
  453. __log_putr(dblp, lsn, dbt, prev, h)
  454. DB_LOG *dblp;
  455. DB_LSN *lsn;
  456. const DBT *dbt;
  457. u_int32_t prev;
  458. HDR *h;
  459. {
  460. DB_CIPHER *db_cipher;
  461. DB_ENV *dbenv;
  462. DB_LSN f_lsn;
  463. LOG *lp;
  464. HDR tmp, *hdr;
  465. int ret, t_ret;
  466. size_t b_off, nr;
  467. u_int32_t w_off;
  468. dbenv = dblp->dbenv;
  469. lp = dblp->reginfo.primary;
  470. /*
  471.  * If we weren't given a header, use a local one.
  472.  */
  473. db_cipher = dbenv->crypto_handle;
  474. if (h == NULL) {
  475. hdr = &tmp;
  476. memset(hdr, 0, sizeof(HDR));
  477. if (CRYPTO_ON(dbenv))
  478. hdr->size = HDR_CRYPTO_SZ;
  479. else
  480. hdr->size = HDR_NORMAL_SZ;
  481. } else
  482. hdr = h;
  483. /* Save our position in case we fail. */
  484. b_off = lp->b_off;
  485. w_off = lp->w_off;
  486. f_lsn = lp->f_lsn;
  487. /*
  488.  * Initialize the header.  If we just switched files, lsn.offset will
  489.  * be 0, and what we really want is the offset of the previous record
  490.  * in the previous file.  Fortunately, prev holds the value we want.
  491.  */
  492. hdr->prev = prev;
  493. hdr->len = (u_int32_t)hdr->size + dbt->size;
  494. /*
  495.  * If we were passed in a nonzero checksum, our caller calculated
  496.  * the checksum before acquiring the log mutex, as an optimization.
  497.  *
  498.  * If our caller calculated a real checksum of 0, we'll needlessly
  499.  * recalculate it.  C'est la vie;  there's no out-of-bounds value
  500.  * here.
  501.  */
  502. if (hdr->chksum[0] == 0)
  503. __db_chksum(dbt->data, dbt->size,
  504.     (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL,
  505.     hdr->chksum);
  506. if ((ret = __log_fill(dblp, lsn, hdr, (u_int32_t)hdr->size)) != 0)
  507. goto err;
  508. if ((ret = __log_fill(dblp, lsn, dbt->data, dbt->size)) != 0)
  509. goto err;
  510. lp->len = (u_int32_t)(hdr->size + dbt->size);
  511. lp->lsn.offset += (u_int32_t)(hdr->size + dbt->size);
  512. return (0);
  513. err:
  514. /*
  515.  * If we wrote more than one buffer before failing, get the
  516.  * first one back.  The extra buffers will fail the checksums
  517.  * and be ignored.
  518.  */
  519. if (w_off + lp->buffer_size < lp->w_off) {
  520. if ((t_ret =
  521.     __os_seek(dbenv,
  522.     &dblp->lfh, 0, 0, w_off, 0, DB_OS_SEEK_SET)) != 0 ||
  523.     (t_ret = __os_read(dbenv, &dblp->lfh, dblp->bufp,
  524.     b_off, &nr)) != 0)
  525. return (__db_panic(dbenv, t_ret));
  526. if (nr != b_off) {
  527. __db_err(dbenv, "Short read while restoring log");
  528. return (__db_panic(dbenv, EIO));
  529. }
  530. }
  531. /* Reset to where we started. */
  532. lp->w_off = w_off;
  533. lp->b_off = b_off;
  534. lp->f_lsn = f_lsn;
  535. return (ret);
  536. }
  537. /*
  538.  * __log_flush --
  539.  * Write all records less than or equal to the specified LSN.
  540.  *
  541.  * PUBLIC: int __log_flush __P((DB_ENV *, const DB_LSN *));
  542.  */
  543. int
  544. __log_flush(dbenv, lsn)
  545. DB_ENV *dbenv;
  546. const DB_LSN *lsn;
  547. {
  548. DB_LOG *dblp;
  549. int ret;
  550. PANIC_CHECK(dbenv);
  551. ENV_REQUIRES_CONFIG(dbenv,
  552.     dbenv->lg_handle, "DB_ENV->log_flush", DB_INIT_LOG);
  553. dblp = dbenv->lg_handle;
  554. R_LOCK(dbenv, &dblp->reginfo);
  555. ret = __log_flush_int(dblp, lsn, 1);
  556. R_UNLOCK(dbenv, &dblp->reginfo);
  557. return (ret);
  558. }
  559. /*
  560.  * __log_flush_int --
  561.  * Write all records less than or equal to the specified LSN; internal
  562.  * version.
  563.  */
  564. static int
  565. __log_flush_int(dblp, lsnp, release)
  566. DB_LOG *dblp;
  567. const DB_LSN *lsnp;
  568. int release;
  569. {
  570. DB_ENV *dbenv;
  571. DB_LSN flush_lsn, f_lsn;
  572. DB_MUTEX *flush_mutexp;
  573. LOG *lp;
  574. int current, do_flush, first, ret;
  575. size_t b_off;
  576. struct __db_commit *commit;
  577. u_int32_t ncommit, w_off;
  578. ret = 0;
  579. ncommit = 0;
  580. dbenv = dblp->dbenv;
  581. lp = dblp->reginfo.primary;
  582. flush_mutexp = R_ADDR(&dblp->reginfo, lp->flush_mutex_off);
  583. /*
  584.  * If no LSN specified, flush the entire log by setting the flush LSN
  585.  * to the last LSN written in the log.  Otherwise, check that the LSN
  586.  * isn't a non-existent record for the log.
  587.  */
  588. if (lsnp == NULL) {
  589. flush_lsn.file = lp->lsn.file;
  590. flush_lsn.offset = lp->lsn.offset - lp->len;
  591. } else if (lsnp->file > lp->lsn.file ||
  592.     (lsnp->file == lp->lsn.file &&
  593.     lsnp->offset > lp->lsn.offset - lp->len)) {
  594. __db_err(dbenv,
  595.     "DB_ENV->log_flush: LSN past current end-of-log");
  596. return (EINVAL);
  597. } else {
  598. /*
  599.  * See if we need to wait.  s_lsn is not locked so some
  600.  * care is needed.  The sync point can only move forward.
  601.  * If the file we want is in the past we are done.
  602.  * If the file numbers are the same check the offset.
  603.  * If this fails check the file numbers again since the
  604.  * offset might have changed while we were looking.
  605.  * This all assumes we can read an integer in one
  606.  * state or the other, not in transition.
  607.  */
  608. if (lp->s_lsn.file > lsnp->file)
  609. return (0);
  610. if (lp->s_lsn.file == lsnp->file &&
  611.     lp->s_lsn.offset > lsnp->offset)
  612. return (0);
  613. if (lp->s_lsn.file > lsnp->file)
  614. return (0);
  615. flush_lsn = *lsnp;
  616. }
  617. /*
  618.  * If a flush is in progress and we're allowed to do so, drop
  619.  * the region lock and block waiting for the next flush.
  620.  */
  621. if (release && lp->in_flush != 0) {
  622. if ((commit = SH_TAILQ_FIRST(
  623.     &lp->free_commits, __db_commit)) == NULL) {
  624. if ((ret =
  625.     __db_shalloc(dblp->reginfo.addr,
  626.     sizeof(struct __db_commit),
  627.     MUTEX_ALIGN, &commit)) != 0)
  628. goto flush;
  629. memset(commit, 0, sizeof(*commit));
  630. if ((ret = __db_mutex_setup(dbenv, &dblp->reginfo,
  631.     &commit->mutex, MUTEX_SELF_BLOCK |
  632.     MUTEX_NO_RLOCK)) != 0) {
  633. __db_shalloc_free(dblp->reginfo.addr, commit);
  634. return (ret);
  635. }
  636. MUTEX_LOCK(dbenv, &commit->mutex);
  637. } else
  638. SH_TAILQ_REMOVE(
  639.     &lp->free_commits, commit, links, __db_commit);
  640. lp->ncommit++;
  641. /*
  642.  * Flushes may be requested out of LSN order;  be
  643.  * sure we only move lp->t_lsn forward.
  644.  */
  645. if (log_compare(&lp->t_lsn, &flush_lsn) < 0)
  646. lp->t_lsn = flush_lsn;
  647. commit->lsn = flush_lsn;
  648. SH_TAILQ_INSERT_HEAD(
  649.     &lp->commits, commit, links, __db_commit);
  650. R_UNLOCK(dbenv, &dblp->reginfo);
  651. /* Wait here for the in-progress flush to finish. */
  652. MUTEX_LOCK(dbenv, &commit->mutex);
  653. R_LOCK(dbenv, &dblp->reginfo);
  654. lp->ncommit--;
  655. /*
  656.  * Grab the flag before freeing the struct to see if
  657.  * we need to flush the log to commit.  If so,
  658.  * use the maximal lsn for any committing thread.
  659.  */
  660. do_flush = F_ISSET(commit, DB_COMMIT_FLUSH);
  661. F_CLR(commit, DB_COMMIT_FLUSH);
  662. SH_TAILQ_INSERT_HEAD(
  663.     &lp->free_commits, commit, links, __db_commit);
  664. if (do_flush) {
  665. lp->in_flush--;
  666. flush_lsn = lp->t_lsn;
  667. } else
  668. return (0);
  669. }
  670. /*
  671.  * Protect flushing with its own mutex so we can release
  672.  * the region lock except during file switches.
  673.  */
  674. flush: MUTEX_LOCK(dbenv, flush_mutexp);
  675. /*
  676.  * If the LSN is less than or equal to the last-sync'd LSN, we're done.
  677.  * Note, the last-sync LSN saved in s_lsn is the LSN of the first byte
  678.  * after the byte we absolutely know was written to disk, so the test
  679.  * is <, not <=.
  680.  */
  681. if (flush_lsn.file < lp->s_lsn.file ||
  682.     (flush_lsn.file == lp->s_lsn.file &&
  683.     flush_lsn.offset < lp->s_lsn.offset)) {
  684. MUTEX_UNLOCK(dbenv, flush_mutexp);
  685. goto done;
  686. }
  687. /*
  688.  * We may need to write the current buffer.  We have to write the
  689.  * current buffer if the flush LSN is greater than or equal to the
  690.  * buffer's starting LSN.
  691.  */
  692. current = 0;
  693. if (lp->b_off != 0 && log_compare(&flush_lsn, &lp->f_lsn) >= 0) {
  694. if ((ret = __log_write(dblp,
  695.     dblp->bufp, (u_int32_t)lp->b_off)) != 0) {
  696. MUTEX_UNLOCK(dbenv, flush_mutexp);
  697. goto done;
  698. }
  699. lp->b_off = 0;
  700. current = 1;
  701. }
  702. /*
  703.  * It's possible that this thread may never have written to this log
  704.  * file.  Acquire a file descriptor if we don't already have one.
  705.  * One last check -- if we're not writing anything from the current
  706.  * buffer, don't bother.  We have nothing to write and nothing to
  707.  * sync.
  708.  */
  709. if (!F_ISSET(&dblp->lfh, DB_FH_VALID) || dblp->lfname != lp->lsn.file)
  710. if (!current || (ret = __log_newfh(dblp)) != 0) {
  711. MUTEX_UNLOCK(dbenv, flush_mutexp);
  712. goto done;
  713. }
  714. /*
  715.  * We are going to flush, release the region.
  716.  * First get the current state of the buffer since
  717.  * another write may come in, but we may not flush it.
  718.  */
  719. b_off = lp->b_off;
  720. w_off = lp->w_off;
  721. f_lsn = lp->f_lsn;
  722. lp->in_flush++;
  723. if (release)
  724. R_UNLOCK(dbenv, &dblp->reginfo);
  725. /* Sync all writes to disk. */
  726. if ((ret = __os_fsync(dbenv, &dblp->lfh)) != 0) {
  727. MUTEX_UNLOCK(dbenv, flush_mutexp);
  728. if (release)
  729. R_LOCK(dbenv, &dblp->reginfo);
  730. ret = __db_panic(dbenv, ret);
  731. return (ret);
  732. }
  733. /*
  734.  * Set the last-synced LSN.
  735.  * This value must be set to the LSN past the last complete
  736.  * record that has been flushed.  This is at least the first
  737.  * lsn, f_lsn.  If the buffer is empty, b_off == 0, then
  738.  * we can move up to write point since the first lsn is not
  739.  * set for the new buffer.
  740.  */
  741. lp->s_lsn = f_lsn;
  742. if (b_off == 0)
  743. lp->s_lsn.offset = w_off;
  744. MUTEX_UNLOCK(dbenv, flush_mutexp);
  745. if (release)
  746. R_LOCK(dbenv, &dblp->reginfo);
  747. lp->in_flush--;
  748. ++lp->stat.st_scount;
  749. /*
  750.  * How many flush calls (usually commits) did this call actually sync?
  751.  * At least one, if it got here.
  752.  */
  753. ncommit = 1;
  754. done:
  755. if (lp->ncommit != 0) {
  756. first = 1;
  757. for (commit = SH_TAILQ_FIRST(&lp->commits, __db_commit);
  758.     commit != NULL;
  759.     commit = SH_TAILQ_NEXT(commit, links, __db_commit))
  760. if (log_compare(&lp->s_lsn, &commit->lsn) > 0) {
  761. MUTEX_UNLOCK(dbenv, &commit->mutex);
  762. SH_TAILQ_REMOVE(
  763.     &lp->commits, commit, links, __db_commit);
  764. ncommit++;
  765. } else if (first == 1) {
  766. F_SET(commit, DB_COMMIT_FLUSH);
  767. MUTEX_UNLOCK(dbenv, &commit->mutex);
  768. SH_TAILQ_REMOVE(
  769.     &lp->commits, commit, links, __db_commit);
  770. /*
  771.  * This thread will wake and flush.
  772.  * If another thread commits and flushes
  773.  * first we will waste a trip trough the
  774.  * mutex.
  775.  */
  776. lp->in_flush++;
  777. first = 0;
  778. }
  779. }
  780. if (lp->stat.st_maxcommitperflush < ncommit)
  781. lp->stat.st_maxcommitperflush = ncommit;
  782. if (lp->stat.st_mincommitperflush > ncommit ||
  783.     lp->stat.st_mincommitperflush == 0)
  784. lp->stat.st_mincommitperflush = ncommit;
  785. return (ret);
  786. }
  787. /*
  788.  * __log_fill --
  789.  * Write information into the log.
  790.  */
  791. static int
  792. __log_fill(dblp, lsn, addr, len)
  793. DB_LOG *dblp;
  794. DB_LSN *lsn;
  795. void *addr;
  796. u_int32_t len;
  797. {
  798. LOG *lp;
  799. u_int32_t bsize, nrec;
  800. size_t nw, remain;
  801. int ret;
  802. lp = dblp->reginfo.primary;
  803. bsize = lp->buffer_size;
  804. while (len > 0) { /* Copy out the data. */
  805. /*
  806.  * If we're beginning a new buffer, note the user LSN to which
  807.  * the first byte of the buffer belongs.  We have to know this
  808.  * when flushing the buffer so that we know if the in-memory
  809.  * buffer needs to be flushed.
  810.  */
  811. if (lp->b_off == 0)
  812. lp->f_lsn = *lsn;
  813. /*
  814.  * If we're on a buffer boundary and the data is big enough,
  815.  * copy as many records as we can directly from the data.
  816.  */
  817. if (lp->b_off == 0 && len >= bsize) {
  818. nrec = len / bsize;
  819. if ((ret = __log_write(dblp, addr, nrec * bsize)) != 0)
  820. return (ret);
  821. addr = (u_int8_t *)addr + nrec * bsize;
  822. len -= nrec * bsize;
  823. ++lp->stat.st_wcount_fill;
  824. continue;
  825. }
  826. /* Figure out how many bytes we can copy this time. */
  827. remain = bsize - lp->b_off;
  828. nw = remain > len ? len : remain;
  829. memcpy(dblp->bufp + lp->b_off, addr, nw);
  830. addr = (u_int8_t *)addr + nw;
  831. len -= (u_int32_t)nw;
  832. lp->b_off += nw;
  833. /* If we fill the buffer, flush it. */
  834. if (lp->b_off == bsize) {
  835. if ((ret = __log_write(dblp, dblp->bufp, bsize)) != 0)
  836. return (ret);
  837. lp->b_off = 0;
  838. ++lp->stat.st_wcount_fill;
  839. }
  840. }
  841. return (0);
  842. }
  843. /*
  844.  * __log_write --
  845.  * Write the log buffer to disk.
  846.  */
  847. static int
  848. __log_write(dblp, addr, len)
  849. DB_LOG *dblp;
  850. void *addr;
  851. u_int32_t len;
  852. {
  853. DB_ENV *dbenv;
  854. LOG *lp;
  855. size_t nw;
  856. int ret;
  857. dbenv = dblp->dbenv;
  858. lp = dblp->reginfo.primary;
  859. /*
  860.  * If we haven't opened the log file yet or the current one
  861.  * has changed, acquire a new log file.
  862.  */
  863. if (!F_ISSET(&dblp->lfh, DB_FH_VALID) || dblp->lfname != lp->lsn.file)
  864. if ((ret = __log_newfh(dblp)) != 0)
  865. return (ret);
  866. /*
  867.  * Seek to the offset in the file (someone may have written it
  868.  * since we last did).
  869.  */
  870. if ((ret =
  871.     __os_seek(dbenv,
  872.     &dblp->lfh, 0, 0, lp->w_off, 0, DB_OS_SEEK_SET)) != 0 ||
  873.     (ret = __os_write(dbenv, &dblp->lfh, addr, len, &nw)) != 0)
  874. return (ret);
  875. /* Reset the buffer offset and update the seek offset. */
  876. lp->w_off += len;
  877. /* Update written statistics. */
  878. if ((lp->stat.st_w_bytes += len) >= MEGABYTE) {
  879. lp->stat.st_w_bytes -= MEGABYTE;
  880. ++lp->stat.st_w_mbytes;
  881. }
  882. if ((lp->stat.st_wc_bytes += len) >= MEGABYTE) {
  883. lp->stat.st_wc_bytes -= MEGABYTE;
  884. ++lp->stat.st_wc_mbytes;
  885. }
  886. ++lp->stat.st_wcount;
  887. return (0);
  888. }
  889. /*
  890.  * __log_file --
  891.  * Map a DB_LSN to a file name.
  892.  *
  893.  * PUBLIC: int __log_file __P((DB_ENV *, const DB_LSN *, char *, size_t));
  894.  */
  895. int
  896. __log_file(dbenv, lsn, namep, len)
  897. DB_ENV *dbenv;
  898. const DB_LSN *lsn;
  899. char *namep;
  900. size_t len;
  901. {
  902. DB_LOG *dblp;
  903. int ret;
  904. char *name;
  905. PANIC_CHECK(dbenv);
  906. ENV_REQUIRES_CONFIG(dbenv,
  907.     dbenv->lg_handle, "DB_ENV->log_file", DB_INIT_LOG);
  908. dblp = dbenv->lg_handle;
  909. R_LOCK(dbenv, &dblp->reginfo);
  910. ret = __log_name(dblp, lsn->file, &name, NULL, 0);
  911. R_UNLOCK(dbenv, &dblp->reginfo);
  912. if (ret != 0)
  913. return (ret);
  914. /* Check to make sure there's enough room and copy the name. */
  915. if (len < strlen(name) + 1) {
  916. *namep = '';
  917. __db_err(dbenv, "DB_ENV->log_file: name buffer is too short");
  918. return (EINVAL);
  919. }
  920. (void)strcpy(namep, name);
  921. __os_free(dbenv, name);
  922. return (0);
  923. }
  924. /*
  925.  * __log_newfh --
  926.  * Acquire a file handle for the current log file.
  927.  */
  928. static int
  929. __log_newfh(dblp)
  930. DB_LOG *dblp;
  931. {
  932. DB_ENV *dbenv;
  933. LOG *lp;
  934. int ret;
  935. char *name;
  936. dbenv = dblp->dbenv;
  937. lp = dblp->reginfo.primary;
  938. /* Close any previous file descriptor. */
  939. if (F_ISSET(&dblp->lfh, DB_FH_VALID))
  940. (void)__os_closehandle(dbenv, &dblp->lfh);
  941. /*
  942.  * Get the path of the new file and open it.
  943.  *
  944.  * Adding DB_OSO_LOG to the flags may add additional platform-specific
  945.  * optimizations.  On WinNT, the logfile is preallocated, which may
  946.  * have a time penalty at startup, but have better overall throughput.
  947.  * We are not certain that this works reliably, so enable at your own
  948.  * risk.
  949.  *
  950.  * XXX:
  951.  * Initialize the log file size.  This is a hack to push the log's
  952.  * maximum size down into the Windows __os_open routine, because it
  953.  * wants to pre-allocate it.
  954.  */
  955. dblp->lfname = lp->lsn.file;
  956. dblp->lfh.log_size = lp->log_size;
  957. if ((ret = __log_name(dblp, dblp->lfname,
  958.     &name, &dblp->lfh,
  959.     DB_OSO_CREATE |/* DB_OSO_LOG |*/ DB_OSO_SEQ |
  960.     (F_ISSET(dbenv, DB_ENV_DIRECT_LOG) ? DB_OSO_DIRECT : 0))) != 0)
  961. __db_err(dbenv,
  962.     "DB_ENV->log_put: %s: %s", name, db_strerror(ret));
  963. __os_free(dbenv, name);
  964. return (ret);
  965. }
  966. /*
  967.  * __log_name --
  968.  * Return the log name for a particular file, and optionally open it.
  969.  *
  970.  * PUBLIC: int __log_name __P((DB_LOG *,
  971.  * PUBLIC:     u_int32_t, char **, DB_FH *, u_int32_t));
  972.  */
  973. int
  974. __log_name(dblp, filenumber, namep, fhp, flags)
  975. DB_LOG *dblp;
  976. u_int32_t filenumber, flags;
  977. char **namep;
  978. DB_FH *fhp;
  979. {
  980. DB_ENV *dbenv;
  981. LOG *lp;
  982. int ret;
  983. char *oname;
  984. char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20];
  985. dbenv = dblp->dbenv;
  986. lp = dblp->reginfo.primary;
  987. /*
  988.  * !!!
  989.  * The semantics of this routine are bizarre.
  990.  *
  991.  * The reason for all of this is that we need a place where we can
  992.  * intercept requests for log files, and, if appropriate, check for
  993.  * both the old-style and new-style log file names.  The trick is
  994.  * that all callers of this routine that are opening the log file
  995.  * read-only want to use an old-style file name if they can't find
  996.  * a match using a new-style name.  The only down-side is that some
  997.  * callers may check for the old-style when they really don't need
  998.  * to, but that shouldn't mess up anything, and we only check for
  999.  * the old-style name when we've already failed to find a new-style
  1000.  * one.
  1001.  *
  1002.  * Create a new-style file name, and if we're not going to open the
  1003.  * file, return regardless.
  1004.  */
  1005. (void)snprintf(new, sizeof(new), LFNAME, filenumber);
  1006. if ((ret = __db_appname(dbenv,
  1007.     DB_APP_LOG, new, 0, NULL, namep)) != 0 || fhp == NULL)
  1008. return (ret);
  1009. /* Open the new-style file -- if we succeed, we're done. */
  1010. if ((ret = __os_open(dbenv, *namep, flags, lp->persist.mode, fhp)) == 0)
  1011. return (0);
  1012. /*
  1013.  * The open failed... if the DB_RDONLY flag isn't set, we're done,
  1014.  * the caller isn't interested in old-style files.
  1015.  */
  1016. if (!LF_ISSET(DB_OSO_RDONLY)) {
  1017. __db_err(dbenv,
  1018.     "%s: log file open failed: %s", *namep, db_strerror(ret));
  1019. return (__db_panic(dbenv, ret));
  1020. }
  1021. /* Create an old-style file name. */
  1022. (void)snprintf(old, sizeof(old), LFNAME_V1, filenumber);
  1023. if ((ret = __db_appname(dbenv, DB_APP_LOG, old, 0, NULL, &oname)) != 0)
  1024. goto err;
  1025. /*
  1026.  * Open the old-style file -- if we succeed, we're done.  Free the
  1027.  * space allocated for the new-style name and return the old-style
  1028.  * name to the caller.
  1029.  */
  1030. if ((ret = __os_open(dbenv,
  1031.     oname, flags, lp->persist.mode, fhp)) == 0) {
  1032. __os_free(dbenv, *namep);
  1033. *namep = oname;
  1034. return (0);
  1035. }
  1036. /*
  1037.  * Couldn't find either style of name -- return the new-style name
  1038.  * for the caller's error message.  If it's an old-style name that's
  1039.  * actually missing we're going to confuse the user with the error
  1040.  * message, but that implies that not only were we looking for an
  1041.  * old-style name, but we expected it to exist and we weren't just
  1042.  * looking for any log file.  That's not a likely error.
  1043.  */
  1044. err: __os_free(dbenv, oname);
  1045. return (ret);
  1046. }
  1047. /*
  1048.  * __log_rep_put --
  1049.  * Short-circuit way for replication clients to put records into the
  1050.  * log.  Replication clients' logs need to be laid out exactly their masters'
  1051.  * are, so we let replication take responsibility for when the log gets
  1052.  * flushed, when log switches files, etc.  This is just a thin PUBLIC wrapper
  1053.  * for __log_putr with a slightly prettier interface.
  1054.  *
  1055.  * Note that the log region mutex should be held when this is called.
  1056.  *
  1057.  * PUBLIC: int __log_rep_put __P((DB_ENV *, DB_LSN *, const DBT *));
  1058.  */
  1059. int
  1060. __log_rep_put(dbenv, lsnp, rec)
  1061. DB_ENV *dbenv;
  1062. DB_LSN *lsnp;
  1063. const DBT *rec;
  1064. {
  1065. DB_CIPHER *db_cipher;
  1066. DB_LOG *dblp;
  1067. HDR hdr;
  1068. DBT *dbt, t;
  1069. LOG *lp;
  1070. int need_free, ret;
  1071. dblp = dbenv->lg_handle;
  1072. lp = dblp->reginfo.primary;
  1073. memset(&hdr, 0, sizeof(HDR));
  1074. t = *rec;
  1075. dbt = &t;
  1076. need_free = 0;
  1077. db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
  1078. if (CRYPTO_ON(dbenv))
  1079. t.size += db_cipher->adj_size(rec->size);
  1080. if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
  1081. goto err;
  1082. need_free = 1;
  1083. memcpy(t.data, rec->data, rec->size);
  1084. if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, rec->size)) != 0)
  1085. goto err;
  1086. __db_chksum(t.data, t.size,
  1087.     (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
  1088. DB_ASSERT(log_compare(lsnp, &lp->lsn) == 0);
  1089. ret = __log_putr(dblp, lsnp, dbt, lp->lsn.offset - lp->len, &hdr);
  1090. err:
  1091. if (need_free)
  1092. __os_free(dbenv, t.data);
  1093. return (ret);
  1094. }
  1095. static int
  1096. __log_encrypt_record(dbenv, dbt, hdr, orig)
  1097. DB_ENV *dbenv;
  1098. DBT *dbt;
  1099. HDR *hdr;
  1100. u_int32_t orig;
  1101. {
  1102. DB_CIPHER *db_cipher;
  1103. int ret;
  1104. if (CRYPTO_ON(dbenv)) {
  1105. db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
  1106. hdr->size = HDR_CRYPTO_SZ;
  1107. hdr->orig_size = orig;
  1108. if ((ret = db_cipher->encrypt(dbenv, db_cipher->data,
  1109.     hdr->iv, dbt->data, dbt->size)) != 0)
  1110. return (ret);
  1111. } else {
  1112. hdr->size = HDR_NORMAL_SZ;
  1113. }
  1114. return (0);
  1115. }