00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #if TIME_WITH_SYS_TIME
00016 #include <sys/time.h>
00017 #include <time.h>
00018 #else
00019 #if HAVE_SYS_TIME_H
00020 #include <sys/time.h>
00021 #else
00022 #include <time.h>
00023 #endif
00024 #endif
00025
00026 #include <stdio.h>
00027 #include <string.h>
00028 #endif
00029
00030 #include "db_int.h"
00031 #include "dbinc/crypto.h"
00032 #include "dbinc/hmac.h"
00033 #include "dbinc/log.h"
00034 #include "dbinc/txn.h"
00035
00036 static int __log_encrypt_record __P((DB_ENV *, DBT *, HDR *, u_int32_t));
00037 static int __log_file __P((DB_ENV *, const DB_LSN *, char *, size_t));
00038 static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t));
00039 static int __log_flush_commit __P((DB_ENV *, const DB_LSN *, u_int32_t));
00040 static int __log_newfh __P((DB_LOG *, int));
00041 static int __log_put_next __P((DB_ENV *,
00042 DB_LSN *, const DBT *, HDR *, DB_LSN *));
00043 static int __log_putr __P((DB_LOG *,
00044 DB_LSN *, const DBT *, u_int32_t, HDR *));
00045 static int __log_write __P((DB_LOG *, void *, u_int32_t));
00046
00047
00048
00049
00050
00051
00052
00053 int
00054 __log_put_pp(dbenv, lsnp, udbt, flags)
00055 DB_ENV *dbenv;
00056 DB_LSN *lsnp;
00057 const DBT *udbt;
00058 u_int32_t flags;
00059 {
00060 DB_THREAD_INFO *ip;
00061 int ret;
00062
00063 PANIC_CHECK(dbenv);
00064 ENV_REQUIRES_CONFIG(dbenv,
00065 dbenv->lg_handle, "DB_ENV->log_put", DB_INIT_LOG);
00066
00067
00068 if ((ret = __db_fchk(dbenv, "DB_ENV->log_put", flags,
00069 DB_LOG_CHKPNT | DB_LOG_COMMIT |
00070 DB_FLUSH | DB_LOG_NOCOPY | DB_LOG_PERM | DB_LOG_WRNOSYNC)) != 0)
00071 return (ret);
00072
00073
00074 if (LF_ISSET(DB_LOG_WRNOSYNC) && LF_ISSET(DB_FLUSH))
00075 return (__db_ferr(dbenv, "DB_ENV->log_put", 1));
00076
00077
00078 if (IS_REP_CLIENT(dbenv)) {
00079 __db_err(dbenv,
00080 "DB_ENV->log_put is illegal on replication clients");
00081 return (EINVAL);
00082 }
00083
00084 ENV_ENTER(dbenv, ip);
00085 REPLICATION_WRAP(dbenv, (__log_put(dbenv, lsnp, udbt, flags)), ret);
00086 ENV_LEAVE(dbenv, ip);
00087 return (ret);
00088 }
00089
00090
00091
00092
00093
00094
00095
00096 int
00097 __log_put(dbenv, lsnp, udbt, flags)
00098 DB_ENV *dbenv;
00099 DB_LSN *lsnp;
00100 const DBT *udbt;
00101 u_int32_t flags;
00102 {
00103 DB_CIPHER *db_cipher;
00104 DBT *dbt, t;
00105 DB_LOG *dblp;
00106 DB_LSN lsn, old_lsn;
00107 DB_REP *db_rep;
00108 HDR hdr;
00109 LOG *lp;
00110 REP *rep;
00111 REP_BULK bulk;
00112 int lock_held, need_free, ret;
00113 u_int8_t *key;
00114
00115 dblp = dbenv->lg_handle;
00116 lp = dblp->reginfo.primary;
00117 db_cipher = dbenv->crypto_handle;
00118 db_rep = dbenv->rep_handle;
00119 if (db_rep != NULL)
00120 rep = db_rep->region;
00121 else
00122 rep = NULL;
00123
00124 dbt = &t;
00125 t = *udbt;
00126 lock_held = need_free = 0;
00127 ZERO_LSN(old_lsn);
00128
00129
00130
00131
00132
00133 if (IS_REP_MASTER(dbenv) && dbenv->rep_send == NULL) {
00134 __db_err(dbenv, "%s %s",
00135 "Non-replication DB_ENV handle attempting",
00136 "to modify a replicated environment");
00137 return (EINVAL);
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 if (!LF_ISSET(DB_LOG_NOCOPY) || IS_REP_MASTER(dbenv)) {
00151 if (CRYPTO_ON(dbenv))
00152 t.size += db_cipher->adj_size(udbt->size);
00153 if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
00154 goto err;
00155 need_free = 1;
00156 memcpy(t.data, udbt->data, udbt->size);
00157 }
00158 if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, udbt->size)) != 0)
00159 goto err;
00160 if (CRYPTO_ON(dbenv))
00161 key = db_cipher->mac_key;
00162 else
00163 key = NULL;
00164
00165
00166 __db_chksum(dbt->data, dbt->size, key, hdr.chksum);
00167
00168 LOG_SYSTEM_LOCK(dbenv);
00169 lock_held = 1;
00170
00171 if ((ret = __log_put_next(dbenv, &lsn, dbt, &hdr, &old_lsn)) != 0)
00172 goto panic_check;
00173
00174
00175
00176
00177
00178
00179 *lsnp = lsn;
00180
00181 if (IS_REP_MASTER(dbenv)) {
00182
00183
00184
00185
00186 LOG_SYSTEM_UNLOCK(dbenv);
00187 lock_held = 0;
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 if (!IS_ZERO_LSN(old_lsn))
00200 (void)__rep_send_message(dbenv, DB_EID_BROADCAST,
00201 REP_NEWFILE, &old_lsn, NULL, 0, 0);
00202
00203
00204
00205
00206 ret = 0;
00207 if (FLD_ISSET(rep->config, REP_C_BULK)) {
00208
00209
00210
00211
00212 if (db_rep->bulk == NULL)
00213 db_rep->bulk = R_ADDR(&dblp->reginfo,
00214 lp->bulk_buf);
00215 memset(&bulk, 0, sizeof(bulk));
00216 bulk.addr = db_rep->bulk;
00217 bulk.offp = &lp->bulk_off;
00218 bulk.len = lp->bulk_len;
00219 bulk.type = REP_BULK_LOG;
00220 bulk.eid = DB_EID_BROADCAST;
00221 bulk.flagsp = &lp->bulk_flags;
00222 ret = __rep_bulk_message(dbenv, &bulk, NULL,
00223 &lsn, udbt, flags);
00224 }
00225 if (!FLD_ISSET(rep->config, REP_C_BULK) ||
00226 ret == DB_REP_BULKOVF) {
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 ret = __rep_send_message(dbenv, DB_EID_BROADCAST,
00237 REP_LOG, &lsn, udbt, flags, 0);
00238 }
00239
00240
00241
00242
00243
00244
00245
00246 if (ret != 0 && LF_ISSET(DB_LOG_PERM))
00247 LF_SET(DB_FLUSH);
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258 if (LF_ISSET(DB_FLUSH | DB_LOG_WRNOSYNC)) {
00259 if (!lock_held) {
00260 LOG_SYSTEM_LOCK(dbenv);
00261 lock_held = 1;
00262 }
00263 if ((ret = __log_flush_commit(dbenv, &lsn, flags)) != 0)
00264 goto panic_check;
00265 }
00266
00267
00268
00269
00270
00271 if (LF_ISSET(DB_LOG_CHKPNT))
00272 lp->stat.st_wc_bytes = lp->stat.st_wc_mbytes = 0;
00273
00274
00275 ++lp->stat.st_record;
00276
00277 if (0) {
00278 panic_check:
00279
00280
00281
00282
00283
00284
00285 if (ret != 0 && IS_REP_MASTER(dbenv))
00286 ret = __db_panic(dbenv, ret);
00287 }
00288
00289 err: if (lock_held)
00290 LOG_SYSTEM_UNLOCK(dbenv);
00291 if (need_free)
00292 __os_free(dbenv, dbt->data);
00293
00294
00295
00296
00297
00298 if (ret == 0 && !IS_ZERO_LSN(old_lsn) && lp->db_log_autoremove)
00299 __log_autoremove(dbenv);
00300
00301 return (ret);
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311 int
00312 __log_current_lsn(dbenv, lsnp, mbytesp, bytesp)
00313 DB_ENV *dbenv;
00314 DB_LSN *lsnp;
00315 u_int32_t *mbytesp, *bytesp;
00316 {
00317 DB_LOG *dblp;
00318 LOG *lp;
00319
00320 dblp = dbenv->lg_handle;
00321 lp = dblp->reginfo.primary;
00322
00323 LOG_SYSTEM_LOCK(dbenv);
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 *lsnp = lp->lsn;
00340 if (lp->lsn.offset > lp->len)
00341 lsnp->offset -= lp->len;
00342
00343
00344
00345
00346
00347
00348
00349
00350 if (mbytesp != NULL) {
00351 *mbytesp = lp->stat.st_wc_mbytes;
00352 *bytesp = (u_int32_t)(lp->stat.st_wc_bytes + lp->b_off);
00353 }
00354
00355 LOG_SYSTEM_UNLOCK(dbenv);
00356
00357 return (0);
00358 }
00359
00360
00361
00362
00363
00364
00365 static int
00366 __log_put_next(dbenv, lsn, dbt, hdr, old_lsnp)
00367 DB_ENV *dbenv;
00368 DB_LSN *lsn;
00369 const DBT *dbt;
00370 HDR *hdr;
00371 DB_LSN *old_lsnp;
00372 {
00373 DB_LOG *dblp;
00374 DB_LSN old_lsn;
00375 LOG *lp;
00376 int newfile, ret;
00377
00378 dblp = dbenv->lg_handle;
00379 lp = dblp->reginfo.primary;
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 old_lsn = lp->lsn;
00390 newfile = 0;
00391
00392
00393
00394
00395
00396
00397 if (lp->lsn.offset == 0 ||
00398 lp->lsn.offset + hdr->size + dbt->size > lp->log_size) {
00399 if (hdr->size + sizeof(LOGP) + dbt->size > lp->log_size) {
00400 __db_err(dbenv,
00401 "DB_ENV->log_put: record larger than maximum file size (%lu > %lu)",
00402 (u_long)hdr->size + sizeof(LOGP) + dbt->size,
00403 (u_long)lp->log_size);
00404 return (EINVAL);
00405 }
00406
00407 if ((ret = __log_newfile(dblp, NULL, 0)) != 0)
00408 return (ret);
00409
00410
00411
00412
00413
00414
00415
00416
00417 newfile = 1;
00418 }
00419
00420
00421
00422
00423
00424 *lsn = lp->lsn;
00425
00426
00427 if (newfile)
00428 *old_lsnp = old_lsn;
00429
00430
00431 return (__log_putr(dblp, lsn, dbt, lp->lsn.offset - lp->len, hdr));
00432 }
00433
00434
00435
00436
00437
00438 static int
00439 __log_flush_commit(dbenv, lsnp, flags)
00440 DB_ENV *dbenv;
00441 const DB_LSN *lsnp;
00442 u_int32_t flags;
00443 {
00444 DB_LOG *dblp;
00445 DB_LSN flush_lsn;
00446 LOG *lp;
00447 int ret;
00448
00449 dblp = dbenv->lg_handle;
00450 lp = dblp->reginfo.primary;
00451 flush_lsn = *lsnp;
00452
00453 ret = 0;
00454
00455
00456
00457
00458
00459
00460
00461
00462 if (LF_ISSET(DB_FLUSH))
00463 ret = __log_flush_int(dblp, &flush_lsn, 1);
00464 else if (!lp->db_log_inmemory && lp->b_off != 0)
00465 if ((ret = __log_write(dblp,
00466 dblp->bufp, (u_int32_t)lp->b_off)) == 0)
00467 lp->b_off = 0;
00468
00469
00470
00471
00472
00473
00474
00475 if (ret == 0 || !LF_ISSET(DB_LOG_COMMIT))
00476 return (ret);
00477
00478 if (flush_lsn.file != lp->lsn.file || flush_lsn.offset < lp->w_off)
00479 return (0);
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491 if (__txn_force_abort(dbenv,
00492 dblp->bufp + flush_lsn.offset - lp->w_off) == 0)
00493 (void)__log_flush_int(dblp, &flush_lsn, 0);
00494
00495 return (ret);
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505 int
00506 __log_newfile(dblp, lsnp, logfile)
00507 DB_LOG *dblp;
00508 DB_LSN *lsnp;
00509 u_int32_t logfile;
00510 {
00511 DB_CIPHER *db_cipher;
00512 DB_ENV *dbenv;
00513 DB_LSN lsn;
00514 DBT t;
00515 HDR hdr;
00516 LOG *lp;
00517 int need_free, ret;
00518 u_int32_t lastoff;
00519 size_t tsize;
00520 u_int8_t *tmp;
00521
00522 dbenv = dblp->dbenv;
00523 lp = dblp->reginfo.primary;
00524
00525
00526
00527
00528
00529 if (logfile == 0 && lp->lsn.offset != 0) {
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 if ((ret = __log_flush_int(dblp, NULL, 0)) != 0)
00544 return (ret);
00545
00546
00547
00548
00549
00550 lastoff = lp->lsn.offset;
00551
00552
00553 ++lp->lsn.file;
00554 lp->lsn.offset = 0;
00555
00556
00557 lp->w_off = 0;
00558 } else
00559 lastoff = 0;
00560
00561
00562
00563
00564
00565
00566 if (logfile != 0) {
00567 lp->lsn.file = logfile;
00568 lp->lsn.offset = 0;
00569 lp->w_off = 0;
00570 if ((ret = __log_newfh(dblp, 1)) != 0)
00571 return (ret);
00572 }
00573
00574 DB_ASSERT(lp->db_log_inmemory || lp->b_off == 0);
00575 if (lp->db_log_inmemory &&
00576 (ret = __log_inmem_newfile(dblp, lp->lsn.file)) != 0)
00577 return (ret);
00578
00579
00580
00581
00582
00583
00584 memset(&t, 0, sizeof(t));
00585 memset(&hdr, 0, sizeof(HDR));
00586
00587 need_free = 0;
00588 tsize = sizeof(LOGP);
00589 db_cipher = dbenv->crypto_handle;
00590 if (CRYPTO_ON(dbenv))
00591 tsize += db_cipher->adj_size(tsize);
00592 if ((ret = __os_calloc(dbenv, 1, tsize, &tmp)) != 0)
00593 return (ret);
00594 lp->persist.log_size = lp->log_size = lp->log_nsize;
00595 memcpy(tmp, &lp->persist, sizeof(LOGP));
00596 t.data = tmp;
00597 t.size = (u_int32_t)tsize;
00598 need_free = 1;
00599
00600 if ((ret =
00601 __log_encrypt_record(dbenv, &t, &hdr, (u_int32_t)tsize)) != 0)
00602 goto err;
00603 __db_chksum(t.data, t.size,
00604 (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
00605 lsn = lp->lsn;
00606 if ((ret = __log_putr(dblp, &lsn,
00607 &t, lastoff == 0 ? 0 : lastoff - lp->len, &hdr)) != 0)
00608 goto err;
00609
00610
00611 if (lsnp != NULL)
00612 *lsnp = lp->lsn;
00613
00614 err: if (need_free)
00615 __os_free(dbenv, tmp);
00616 return (ret);
00617 }
00618
00619
00620
00621
00622
00623 static int
00624 __log_putr(dblp, lsn, dbt, prev, h)
00625 DB_LOG *dblp;
00626 DB_LSN *lsn;
00627 const DBT *dbt;
00628 u_int32_t prev;
00629 HDR *h;
00630 {
00631 DB_CIPHER *db_cipher;
00632 DB_ENV *dbenv;
00633 DB_LSN f_lsn;
00634 LOG *lp;
00635 HDR tmp, *hdr;
00636 int ret, t_ret;
00637 size_t b_off, nr;
00638 u_int32_t w_off;
00639
00640 dbenv = dblp->dbenv;
00641 lp = dblp->reginfo.primary;
00642
00643
00644
00645
00646 db_cipher = dbenv->crypto_handle;
00647 if (h == NULL) {
00648 hdr = &tmp;
00649 memset(hdr, 0, sizeof(HDR));
00650 if (CRYPTO_ON(dbenv))
00651 hdr->size = HDR_CRYPTO_SZ;
00652 else
00653 hdr->size = HDR_NORMAL_SZ;
00654 } else
00655 hdr = h;
00656
00657
00658 b_off = lp->b_off;
00659 w_off = lp->w_off;
00660 f_lsn = lp->f_lsn;
00661
00662
00663
00664
00665
00666
00667 hdr->prev = prev;
00668 hdr->len = (u_int32_t)hdr->size + dbt->size;
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 if (hdr->chksum[0] == 0)
00679 __db_chksum(dbt->data, dbt->size,
00680 (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL,
00681 hdr->chksum);
00682
00683 if (lp->db_log_inmemory && (ret = __log_inmem_chkspace(dblp,
00684 (u_int32_t)hdr->size + dbt->size)) != 0)
00685 goto err;
00686
00687 if ((ret = __log_fill(dblp, lsn, hdr, (u_int32_t)hdr->size)) != 0)
00688 goto err;
00689
00690 if ((ret = __log_fill(dblp, lsn, dbt->data, dbt->size)) != 0)
00691 goto err;
00692
00693 lp->len = (u_int32_t)(hdr->size + dbt->size);
00694 lp->lsn.offset += (u_int32_t)(hdr->size + dbt->size);
00695 return (0);
00696 err:
00697
00698
00699
00700
00701
00702 if (w_off + lp->buffer_size < lp->w_off) {
00703 DB_ASSERT(!lp->db_log_inmemory);
00704 if ((t_ret = __os_seek(dbenv,
00705 dblp->lfhp, 0, 0, w_off, 0, DB_OS_SEEK_SET)) != 0 ||
00706 (t_ret = __os_read(dbenv, dblp->lfhp, dblp->bufp,
00707 b_off, &nr)) != 0)
00708 return (__db_panic(dbenv, t_ret));
00709 if (nr != b_off) {
00710 __db_err(dbenv, "Short read while restoring log");
00711 return (__db_panic(dbenv, EIO));
00712 }
00713 }
00714
00715
00716 lp->w_off = w_off;
00717 lp->b_off = b_off;
00718 lp->f_lsn = f_lsn;
00719
00720 return (ret);
00721 }
00722
00723
00724
00725
00726
00727
00728
00729 int
00730 __log_flush_pp(dbenv, lsn)
00731 DB_ENV *dbenv;
00732 const DB_LSN *lsn;
00733 {
00734 DB_THREAD_INFO *ip;
00735 int ret;
00736
00737 PANIC_CHECK(dbenv);
00738 ENV_REQUIRES_CONFIG(dbenv,
00739 dbenv->lg_handle, "DB_ENV->log_flush", DB_INIT_LOG);
00740
00741 ENV_ENTER(dbenv, ip);
00742 REPLICATION_WRAP(dbenv, (__log_flush(dbenv, lsn)), ret);
00743 ENV_LEAVE(dbenv, ip);
00744 return (ret);
00745 }
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755 #define ALREADY_FLUSHED(lp, lsnp) \
00756 (((lp)->s_lsn.file > (lsnp)->file) || \
00757 ((lp)->s_lsn.file == (lsnp)->file && \
00758 (lp)->s_lsn.offset > (lsnp)->offset))
00759
00760
00761
00762
00763
00764
00765
00766 int
00767 __log_flush(dbenv, lsn)
00768 DB_ENV *dbenv;
00769 const DB_LSN *lsn;
00770 {
00771 DB_LOG *dblp;
00772 LOG *lp;
00773 int ret;
00774
00775 dblp = dbenv->lg_handle;
00776 lp = dblp->reginfo.primary;
00777 if (lsn != NULL && ALREADY_FLUSHED(lp, lsn))
00778 return (0);
00779 LOG_SYSTEM_LOCK(dbenv);
00780 ret = __log_flush_int(dblp, lsn, 1);
00781 LOG_SYSTEM_UNLOCK(dbenv);
00782 return (ret);
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792 int
00793 __log_flush_int(dblp, lsnp, release)
00794 DB_LOG *dblp;
00795 const DB_LSN *lsnp;
00796 int release;
00797 {
00798 struct __db_commit *commit;
00799 DB_ENV *dbenv;
00800 DB_LSN flush_lsn, f_lsn;
00801 LOG *lp;
00802 size_t b_off;
00803 u_int32_t ncommit, w_off;
00804 int do_flush, first, ret;
00805
00806 dbenv = dblp->dbenv;
00807 lp = dblp->reginfo.primary;
00808 ncommit = 0;
00809 ret = 0;
00810
00811 if (lp->db_log_inmemory) {
00812 lp->s_lsn = lp->lsn;
00813 ++lp->stat.st_scount;
00814 return (0);
00815 }
00816
00817
00818
00819
00820
00821
00822 if (lsnp == NULL) {
00823 flush_lsn.file = lp->lsn.file;
00824 flush_lsn.offset = lp->lsn.offset - lp->len;
00825 } else if (lsnp->file > lp->lsn.file ||
00826 (lsnp->file == lp->lsn.file &&
00827 lsnp->offset > lp->lsn.offset - lp->len)) {
00828 __db_err(dbenv,
00829 "DB_ENV->log_flush: LSN of %lu/%lu past current end-of-log of %lu/%lu",
00830 (u_long)lsnp->file, (u_long)lsnp->offset,
00831 (u_long)lp->lsn.file, (u_long)lp->lsn.offset);
00832 __db_err(dbenv, "%s %s %s",
00833 "Database environment corrupt; the wrong log files may",
00834 "have been removed or incompatible database files imported",
00835 "from another environment");
00836 return (__db_panic(dbenv, DB_RUNRECOVERY));
00837 } else {
00838 if (ALREADY_FLUSHED(lp, lsnp))
00839 return (0);
00840 flush_lsn = *lsnp;
00841 }
00842
00843
00844
00845
00846
00847 if (release && lp->in_flush != 0) {
00848 if ((commit = SH_TAILQ_FIRST(
00849 &lp->free_commits, __db_commit)) == NULL) {
00850 if ((ret = __db_shalloc(&dblp->reginfo,
00851 sizeof(struct __db_commit), 0, &commit)) != 0)
00852 goto flush;
00853 memset(commit, 0, sizeof(*commit));
00854 if ((ret = __mutex_alloc(dbenv, MTX_TXN_COMMIT,
00855 DB_MUTEX_SELF_BLOCK, &commit->mtx_txnwait)) != 0) {
00856 __db_shalloc_free(&dblp->reginfo, commit);
00857 return (ret);
00858 }
00859 MUTEX_LOCK(dbenv, commit->mtx_txnwait);
00860 } else
00861 SH_TAILQ_REMOVE(
00862 &lp->free_commits, commit, links, __db_commit);
00863
00864 lp->ncommit++;
00865
00866
00867
00868
00869
00870 if (log_compare(&lp->t_lsn, &flush_lsn) < 0)
00871 lp->t_lsn = flush_lsn;
00872
00873 commit->lsn = flush_lsn;
00874 SH_TAILQ_INSERT_HEAD(
00875 &lp->commits, commit, links, __db_commit);
00876 LOG_SYSTEM_UNLOCK(dbenv);
00877
00878 MUTEX_LOCK(dbenv, commit->mtx_txnwait);
00879 LOG_SYSTEM_LOCK(dbenv);
00880
00881 lp->ncommit--;
00882
00883
00884
00885
00886
00887 do_flush = F_ISSET(commit, DB_COMMIT_FLUSH);
00888 F_CLR(commit, DB_COMMIT_FLUSH);
00889 SH_TAILQ_INSERT_HEAD(
00890 &lp->free_commits, commit, links, __db_commit);
00891 if (do_flush) {
00892 lp->in_flush--;
00893 flush_lsn = lp->t_lsn;
00894 } else
00895 return (0);
00896 }
00897
00898
00899
00900
00901
00902 flush: MUTEX_LOCK(dbenv, lp->mtx_flush);
00903
00904
00905
00906
00907
00908
00909
00910 if (flush_lsn.file < lp->s_lsn.file ||
00911 (flush_lsn.file == lp->s_lsn.file &&
00912 flush_lsn.offset < lp->s_lsn.offset)) {
00913 MUTEX_UNLOCK(dbenv, lp->mtx_flush);
00914 goto done;
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926 if (lp->b_off != 0 && log_compare(&flush_lsn, &lp->f_lsn) >= 0) {
00927 if ((ret = __log_write(dblp,
00928 dblp->bufp, (u_int32_t)lp->b_off)) != 0) {
00929 MUTEX_UNLOCK(dbenv, lp->mtx_flush);
00930 goto done;
00931 }
00932
00933 lp->b_off = 0;
00934 } else if (dblp->lfhp == NULL || dblp->lfname != lp->lsn.file)
00935 if ((ret = __log_newfh(dblp, 0)) != 0) {
00936 MUTEX_UNLOCK(dbenv, lp->mtx_flush);
00937 goto done;
00938 }
00939
00940
00941
00942
00943
00944
00945 b_off = lp->b_off;
00946 w_off = lp->w_off;
00947 f_lsn = lp->f_lsn;
00948 lp->in_flush++;
00949 if (release)
00950 LOG_SYSTEM_UNLOCK(dbenv);
00951
00952
00953 if ((ret = __os_fsync(dbenv, dblp->lfhp)) != 0) {
00954 MUTEX_UNLOCK(dbenv, lp->mtx_flush);
00955 if (release)
00956 LOG_SYSTEM_LOCK(dbenv);
00957 ret = __db_panic(dbenv, ret);
00958 return (ret);
00959 }
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969 lp->s_lsn = f_lsn;
00970 if (b_off == 0)
00971 lp->s_lsn.offset = w_off;
00972
00973 MUTEX_UNLOCK(dbenv, lp->mtx_flush);
00974 if (release)
00975 LOG_SYSTEM_LOCK(dbenv);
00976
00977 lp->in_flush--;
00978 ++lp->stat.st_scount;
00979
00980
00981
00982
00983
00984 ncommit = 1;
00985 done:
00986 if (lp->ncommit != 0) {
00987 first = 1;
00988 for (commit = SH_TAILQ_FIRST(&lp->commits, __db_commit);
00989 commit != NULL;
00990 commit = SH_TAILQ_NEXT(commit, links, __db_commit))
00991 if (log_compare(&lp->s_lsn, &commit->lsn) > 0) {
00992 MUTEX_UNLOCK(dbenv, commit->mtx_txnwait);
00993 SH_TAILQ_REMOVE(
00994 &lp->commits, commit, links, __db_commit);
00995 ncommit++;
00996 } else if (first == 1) {
00997 F_SET(commit, DB_COMMIT_FLUSH);
00998 MUTEX_UNLOCK(dbenv, commit->mtx_txnwait);
00999 SH_TAILQ_REMOVE(
01000 &lp->commits, commit, links, __db_commit);
01001
01002
01003
01004
01005
01006
01007 lp->in_flush++;
01008 first = 0;
01009 }
01010 }
01011 if (lp->stat.st_maxcommitperflush < ncommit)
01012 lp->stat.st_maxcommitperflush = ncommit;
01013 if (lp->stat.st_mincommitperflush > ncommit ||
01014 lp->stat.st_mincommitperflush == 0)
01015 lp->stat.st_mincommitperflush = ncommit;
01016
01017 return (ret);
01018 }
01019
01020
01021
01022
01023
01024 static int
01025 __log_fill(dblp, lsn, addr, len)
01026 DB_LOG *dblp;
01027 DB_LSN *lsn;
01028 void *addr;
01029 u_int32_t len;
01030 {
01031 LOG *lp;
01032 u_int32_t bsize, nrec;
01033 size_t nw, remain;
01034 int ret;
01035
01036 lp = dblp->reginfo.primary;
01037 bsize = lp->buffer_size;
01038
01039 if (lp->db_log_inmemory) {
01040 __log_inmem_copyin(dblp, lp->b_off, addr, len);
01041 lp->b_off = (lp->b_off + len) % lp->buffer_size;
01042 return (0);
01043 }
01044
01045 while (len > 0) {
01046
01047
01048
01049
01050
01051
01052 if (lp->b_off == 0)
01053 lp->f_lsn = *lsn;
01054
01055
01056
01057
01058
01059 if (lp->b_off == 0 && len >= bsize) {
01060 nrec = len / bsize;
01061 if ((ret = __log_write(dblp, addr, nrec * bsize)) != 0)
01062 return (ret);
01063 addr = (u_int8_t *)addr + nrec * bsize;
01064 len -= nrec * bsize;
01065 ++lp->stat.st_wcount_fill;
01066 continue;
01067 }
01068
01069
01070 remain = bsize - lp->b_off;
01071 nw = remain > len ? len : remain;
01072 memcpy(dblp->bufp + lp->b_off, addr, nw);
01073 addr = (u_int8_t *)addr + nw;
01074 len -= (u_int32_t)nw;
01075 lp->b_off += nw;
01076
01077
01078 if (lp->b_off == bsize) {
01079 if ((ret = __log_write(dblp, dblp->bufp, bsize)) != 0)
01080 return (ret);
01081 lp->b_off = 0;
01082 ++lp->stat.st_wcount_fill;
01083 }
01084 }
01085 return (0);
01086 }
01087
01088
01089
01090
01091
01092 static int
01093 __log_write(dblp, addr, len)
01094 DB_LOG *dblp;
01095 void *addr;
01096 u_int32_t len;
01097 {
01098 DB_ENV *dbenv;
01099 LOG *lp;
01100 size_t nw;
01101 int ret;
01102
01103 dbenv = dblp->dbenv;
01104 lp = dblp->reginfo.primary;
01105
01106 DB_ASSERT(!lp->db_log_inmemory);
01107
01108
01109
01110
01111
01112
01113
01114 if (dblp->lfhp == NULL || dblp->lfname != lp->lsn.file)
01115 if ((ret = __log_newfh(dblp, lp->w_off == 0)) != 0)
01116 return (ret);
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127 #ifdef HAVE_FILESYSTEM_NOTZERO
01128 if (lp->w_off == 0 && !__os_fs_notzero())
01129 #else
01130 if (lp->w_off == 0)
01131 #endif
01132 (void)__db_file_extend(dbenv, dblp->lfhp, lp->log_size);
01133
01134
01135
01136
01137
01138 if ((ret = __os_seek(dbenv,
01139 dblp->lfhp, 0, 0, lp->w_off, 0, DB_OS_SEEK_SET)) != 0 ||
01140 (ret = __os_write(dbenv, dblp->lfhp, addr, len, &nw)) != 0)
01141 return (ret);
01142
01143
01144 lp->w_off += len;
01145
01146
01147 if ((lp->stat.st_w_bytes += len) >= MEGABYTE) {
01148 lp->stat.st_w_bytes -= MEGABYTE;
01149 ++lp->stat.st_w_mbytes;
01150 }
01151 if ((lp->stat.st_wc_bytes += len) >= MEGABYTE) {
01152 lp->stat.st_wc_bytes -= MEGABYTE;
01153 ++lp->stat.st_wc_mbytes;
01154 }
01155 ++lp->stat.st_wcount;
01156
01157 return (0);
01158 }
01159
01160
01161
01162
01163
01164
01165
01166 int
01167 __log_file_pp(dbenv, lsn, namep, len)
01168 DB_ENV *dbenv;
01169 const DB_LSN *lsn;
01170 char *namep;
01171 size_t len;
01172 {
01173 DB_THREAD_INFO *ip;
01174 int ret;
01175
01176 PANIC_CHECK(dbenv);
01177 ENV_REQUIRES_CONFIG(dbenv,
01178 dbenv->lg_handle, "DB_ENV->log_file", DB_INIT_LOG);
01179
01180 if (F_ISSET(dbenv, DB_ENV_LOG_INMEMORY)) {
01181 __db_err(dbenv,
01182 "DB_ENV->log_file is illegal with in-memory logs.");
01183 return (EINVAL);
01184 }
01185
01186 ENV_ENTER(dbenv, ip);
01187 REPLICATION_WRAP(dbenv, (__log_file(dbenv, lsn, namep, len)), ret);
01188 ENV_LEAVE(dbenv, ip);
01189 return (ret);
01190 }
01191
01192
01193
01194
01195
01196 static int
01197 __log_file(dbenv, lsn, namep, len)
01198 DB_ENV *dbenv;
01199 const DB_LSN *lsn;
01200 char *namep;
01201 size_t len;
01202 {
01203 DB_LOG *dblp;
01204 int ret;
01205 char *name;
01206
01207 dblp = dbenv->lg_handle;
01208 LOG_SYSTEM_LOCK(dbenv);
01209 ret = __log_name(dblp, lsn->file, &name, NULL, 0);
01210 LOG_SYSTEM_UNLOCK(dbenv);
01211 if (ret != 0)
01212 return (ret);
01213
01214
01215 if (len < strlen(name) + 1) {
01216 *namep = '\0';
01217 __db_err(dbenv, "DB_ENV->log_file: name buffer is too short");
01218 return (EINVAL);
01219 }
01220 (void)strcpy(namep, name);
01221 __os_free(dbenv, name);
01222
01223 return (0);
01224 }
01225
01226
01227
01228
01229
01230 static int
01231 __log_newfh(dblp, create)
01232 DB_LOG *dblp;
01233 int create;
01234 {
01235 DB_ENV *dbenv;
01236 LOG *lp;
01237 u_int32_t flags;
01238 int ret;
01239 logfile_validity status;
01240
01241 dbenv = dblp->dbenv;
01242 lp = dblp->reginfo.primary;
01243
01244
01245 if (dblp->lfhp != NULL) {
01246 (void)__os_closehandle(dbenv, dblp->lfhp);
01247 dblp->lfhp = NULL;
01248 }
01249
01250 flags = DB_OSO_SEQ |
01251 (create ? DB_OSO_CREATE : 0) |
01252 (F_ISSET(dbenv, DB_ENV_DIRECT_LOG) ? DB_OSO_DIRECT : 0) |
01253 (F_ISSET(dbenv, DB_ENV_DSYNC_LOG) ? DB_OSO_DSYNC : 0);
01254
01255
01256 dblp->lfname = lp->lsn.file;
01257 if ((ret = __log_valid(dblp, dblp->lfname, 0, &dblp->lfhp,
01258 flags, &status)) != 0)
01259 __db_err(dbenv,
01260 "DB_ENV->log_put: %d: %s", lp->lsn.file, db_strerror(ret));
01261 else if (status != DB_LV_NORMAL && status != DB_LV_INCOMPLETE)
01262 ret = DB_NOTFOUND;
01263
01264 return (ret);
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274 int
01275 __log_name(dblp, filenumber, namep, fhpp, flags)
01276 DB_LOG *dblp;
01277 u_int32_t filenumber, flags;
01278 char **namep;
01279 DB_FH **fhpp;
01280 {
01281 DB_ENV *dbenv;
01282 LOG *lp;
01283 int mode, ret;
01284 char *oname;
01285 char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20];
01286
01287 dbenv = dblp->dbenv;
01288 lp = dblp->reginfo.primary;
01289
01290 DB_ASSERT(!lp->db_log_inmemory);
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310 (void)snprintf(new, sizeof(new), LFNAME, filenumber);
01311 if ((ret = __db_appname(dbenv,
01312 DB_APP_LOG, new, 0, NULL, namep)) != 0 || fhpp == NULL)
01313 return (ret);
01314
01315
01316 if (lp->filemode == 0)
01317 mode = dbenv->db_mode;
01318 else {
01319 LF_SET(DB_OSO_ABSMODE);
01320 mode = lp->filemode;
01321 }
01322
01323
01324 if ((ret = __os_open_extend(dbenv, *namep, 0, flags, mode, fhpp)) == 0)
01325 return (0);
01326
01327
01328
01329
01330
01331
01332 if (ret != ENOENT) {
01333 __db_err(dbenv,
01334 "%s: log file unreadable: %s", *namep, db_strerror(ret));
01335 return (__db_panic(dbenv, ret));
01336 }
01337
01338
01339
01340
01341
01342 if (!LF_ISSET(DB_OSO_RDONLY)) {
01343 __db_err(dbenv,
01344 "%s: log file open failed: %s", *namep, db_strerror(ret));
01345 return (__db_panic(dbenv, ret));
01346 }
01347
01348
01349 (void)snprintf(old, sizeof(old), LFNAME_V1, filenumber);
01350 if ((ret = __db_appname(dbenv, DB_APP_LOG, old, 0, NULL, &oname)) != 0)
01351 goto err;
01352
01353
01354
01355
01356
01357
01358 if ((ret = __os_open(dbenv, oname, flags, mode, fhpp)) == 0) {
01359 __os_free(dbenv, *namep);
01360 *namep = oname;
01361 return (0);
01362 }
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 err: __os_free(dbenv, oname);
01373 return (ret);
01374 }
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389 int
01390 __log_rep_put(dbenv, lsnp, rec)
01391 DB_ENV *dbenv;
01392 DB_LSN *lsnp;
01393 const DBT *rec;
01394 {
01395 DB_CIPHER *db_cipher;
01396 DB_LOG *dblp;
01397 HDR hdr;
01398 DBT *dbt, t;
01399 LOG *lp;
01400 int need_free, ret;
01401
01402 dblp = dbenv->lg_handle;
01403 lp = dblp->reginfo.primary;
01404
01405 LOG_SYSTEM_LOCK(dbenv);
01406 memset(&hdr, 0, sizeof(HDR));
01407 t = *rec;
01408 dbt = &t;
01409 need_free = 0;
01410 db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
01411 if (CRYPTO_ON(dbenv))
01412 t.size += db_cipher->adj_size(rec->size);
01413 if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
01414 goto err;
01415 need_free = 1;
01416 memcpy(t.data, rec->data, rec->size);
01417
01418 if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, rec->size)) != 0)
01419 goto err;
01420 __db_chksum(t.data, t.size,
01421 (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
01422
01423 DB_ASSERT(log_compare(lsnp, &lp->lsn) == 0);
01424 ret = __log_putr(dblp, lsnp, dbt, lp->lsn.offset - lp->len, &hdr);
01425 err:
01426
01427
01428
01429 lp->ready_lsn = lp->lsn;
01430 LOG_SYSTEM_UNLOCK(dbenv);
01431 if (need_free)
01432 __os_free(dbenv, t.data);
01433 return (ret);
01434 }
01435
01436 static int
01437 __log_encrypt_record(dbenv, dbt, hdr, orig)
01438 DB_ENV *dbenv;
01439 DBT *dbt;
01440 HDR *hdr;
01441 u_int32_t orig;
01442 {
01443 DB_CIPHER *db_cipher;
01444 int ret;
01445
01446 if (CRYPTO_ON(dbenv)) {
01447 db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
01448 hdr->size = HDR_CRYPTO_SZ;
01449 hdr->orig_size = orig;
01450 if ((ret = db_cipher->encrypt(dbenv, db_cipher->data,
01451 hdr->iv, dbt->data, dbt->size)) != 0)
01452 return (ret);
01453 } else {
01454 hdr->size = HDR_NORMAL_SZ;
01455 }
01456 return (0);
01457 }