#include "db_config.h"
#ifndef lint
static const char revid[] = "$Id: log_put.c,v 1.2 2004/03/30 01:23:43 jtownsen Exp $";
#endif
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif
#include <stdio.h>
#include <string.h>
#endif
#include "db_int.h"
#include "dbinc/crypto.h"
#include "dbinc/hmac.h"
#include "dbinc/log.h"
#include "dbinc/txn.h"
static int __log_encrypt_record __P((DB_ENV *, DBT *, HDR *, u_int32_t));
static int __log_file __P((DB_ENV *, const DB_LSN *, char *, size_t));
static int __log_fill __P((DB_LOG *, DB_LSN *, void *, u_int32_t));
static int __log_flush_commit __P((DB_ENV *, const DB_LSN *, u_int32_t));
static int __log_newfh __P((DB_LOG *));
static int __log_put_next __P((DB_ENV *,
DB_LSN *, const DBT *, HDR *, DB_LSN *));
static int __log_putr __P((DB_LOG *,
DB_LSN *, const DBT *, u_int32_t, HDR *));
static int __log_write __P((DB_LOG *, void *, u_int32_t));
int
__log_put_pp(dbenv, lsnp, udbt, flags)
DB_ENV *dbenv;
DB_LSN *lsnp;
const DBT *udbt;
u_int32_t flags;
{
int rep_check, ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lg_handle, "DB_ENV->log_put", DB_INIT_LOG);
if ((ret = __db_fchk(dbenv, "DB_ENV->log_put", flags,
DB_LOG_CHKPNT | DB_LOG_COMMIT |
DB_FLUSH | DB_LOG_NOCOPY | DB_LOG_PERM | DB_LOG_WRNOSYNC)) != 0)
return (ret);
if (LF_ISSET(DB_LOG_WRNOSYNC) && LF_ISSET(DB_FLUSH))
return (__db_ferr(dbenv, "DB_ENV->log_put", 1));
if (IS_REP_CLIENT(dbenv)) {
__db_err(dbenv,
"DB_ENV->log_put is illegal on replication clients");
return (EINVAL);
}
rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
if (rep_check)
__env_rep_enter(dbenv);
ret = __log_put(dbenv, lsnp, udbt, flags);
if (rep_check)
__env_rep_exit(dbenv);
return (ret);
}
int
__log_put(dbenv, lsnp, udbt, flags)
DB_ENV *dbenv;
DB_LSN *lsnp;
const DBT *udbt;
u_int32_t flags;
{
DB_CIPHER *db_cipher;
DBT *dbt, t;
DB_LOG *dblp;
DB_LSN lsn, old_lsn;
HDR hdr;
LOG *lp;
int lock_held, need_free, ret;
u_int8_t *key;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
db_cipher = dbenv->crypto_handle;
dbt = &t;
t = *udbt;
lock_held = need_free = 0;
if (!LF_ISSET(DB_LOG_NOCOPY) || IS_REP_MASTER(dbenv)) {
if (CRYPTO_ON(dbenv))
t.size += db_cipher->adj_size(udbt->size);
if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
goto err;
need_free = 1;
memcpy(t.data, udbt->data, udbt->size);
}
if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, udbt->size)) != 0)
goto err;
if (CRYPTO_ON(dbenv))
key = db_cipher->mac_key;
else
key = NULL;
__db_chksum(dbt->data, dbt->size, key, hdr.chksum);
R_LOCK(dbenv, &dblp->reginfo);
lock_held = 1;
ZERO_LSN(old_lsn);
if ((ret = __log_put_next(dbenv, &lsn, dbt, &hdr, &old_lsn)) != 0)
goto panic_check;
if (IS_REP_MASTER(dbenv)) {
R_UNLOCK(dbenv, &dblp->reginfo);
lock_held = 0;
if (dbenv->rep_send == NULL) {
__db_err(dbenv, "%s %s",
"Non-replication DB_ENV handle attempting",
"to modify a replicated environment");
ret = EINVAL;
goto err;
}
if (!IS_ZERO_LSN(old_lsn))
(void)__rep_send_message(dbenv,
DB_EID_BROADCAST, REP_NEWFILE, &old_lsn, NULL, 0);
if ((__rep_send_message(dbenv,
DB_EID_BROADCAST, REP_LOG, &lsn, udbt, flags) != 0) &&
LF_ISSET(DB_LOG_PERM))
LF_SET(DB_FLUSH);
}
if (LF_ISSET(DB_FLUSH | DB_LOG_WRNOSYNC)) {
if (!lock_held) {
R_LOCK(dbenv, &dblp->reginfo);
lock_held = 1;
}
if ((ret = __log_flush_commit(dbenv, &lsn, flags)) != 0)
goto panic_check;
}
*lsnp = lsn;
if (LF_ISSET(DB_LOG_CHKPNT))
lp->stat.st_wc_bytes = lp->stat.st_wc_mbytes = 0;
if (0) {
panic_check:
if (ret != 0 && IS_REP_MASTER(dbenv))
ret = __db_panic(dbenv, ret);
}
err:
if (lock_held)
R_UNLOCK(dbenv, &dblp->reginfo);
if (need_free)
__os_free(dbenv, dbt->data);
if (ret == 0 &&
F_ISSET(dbenv, DB_ENV_LOG_AUTOREMOVE) && !IS_ZERO_LSN(old_lsn))
__log_autoremove(dbenv);
return (ret);
}
void
__log_txn_lsn(dbenv, lsnp, mbytesp, bytesp)
DB_ENV *dbenv;
DB_LSN *lsnp;
u_int32_t *mbytesp, *bytesp;
{
DB_LOG *dblp;
LOG *lp;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
R_LOCK(dbenv, &dblp->reginfo);
*lsnp = lp->lsn;
if (lp->lsn.offset > lp->len)
lsnp->offset -= lp->len;
if (mbytesp != NULL) {
*mbytesp = lp->stat.st_wc_mbytes;
*bytesp = (u_int32_t)(lp->stat.st_wc_bytes + lp->b_off);
}
R_UNLOCK(dbenv, &dblp->reginfo);
}
static int
__log_put_next(dbenv, lsn, dbt, hdr, old_lsnp)
DB_ENV *dbenv;
DB_LSN *lsn;
const DBT *dbt;
HDR *hdr;
DB_LSN *old_lsnp;
{
DB_LOG *dblp;
DB_LSN old_lsn;
LOG *lp;
int newfile, ret;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
old_lsn = lp->lsn;
newfile = 0;
if (lp->lsn.offset == 0 ||
lp->lsn.offset + hdr->size + dbt->size > lp->log_size) {
if (hdr->size + sizeof(LOGP) + dbt->size > lp->log_size) {
__db_err(dbenv,
"DB_ENV->log_put: record larger than maximum file size (%lu > %lu)",
(u_long)hdr->size + sizeof(LOGP) + dbt->size,
(u_long)lp->log_size);
return (EINVAL);
}
if ((ret = __log_newfile(dblp, NULL)) != 0)
return (ret);
newfile = 1;
}
*lsn = lp->lsn;
if (newfile)
*old_lsnp = old_lsn;
return (__log_putr(dblp, lsn, dbt, lp->lsn.offset - lp->len, hdr));
}
static int
__log_flush_commit(dbenv, lsnp, flags)
DB_ENV *dbenv;
const DB_LSN *lsnp;
u_int32_t flags;
{
DB_LOG *dblp;
DB_LSN flush_lsn;
LOG *lp;
int ret;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
flush_lsn = *lsnp;
ret = 0;
if (LF_ISSET(DB_FLUSH))
ret = __log_flush_int(dblp, &flush_lsn, 1);
else if (lp->b_off != 0)
if ((ret = __log_write(dblp,
dblp->bufp, (u_int32_t)lp->b_off)) == 0)
lp->b_off = 0;
if (ret == 0 || !LF_ISSET(DB_LOG_COMMIT))
return (ret);
if (flush_lsn.file != lp->lsn.file || flush_lsn.offset < lp->w_off)
return (0);
if (__txn_force_abort(dbenv,
dblp->bufp + flush_lsn.offset - lp->w_off) == 0)
(void)__log_flush_int(dblp, &flush_lsn, 0);
return (ret);
}
int
__log_newfile(dblp, lsnp)
DB_LOG *dblp;
DB_LSN *lsnp;
{
DB_CIPHER *db_cipher;
DB_ENV *dbenv;
DB_LSN lsn;
DBT t;
HDR hdr;
LOG *lp;
int need_free, ret;
u_int32_t lastoff;
size_t tsize;
u_int8_t *tmp;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
if (lp->lsn.offset != 0) {
if ((ret = __log_flush_int(dblp, NULL, 0)) != 0)
return (ret);
DB_ASSERT(lp->b_off == 0);
lastoff = lp->lsn.offset;
++lp->lsn.file;
lp->lsn.offset = 0;
lp->w_off = 0;
} else
lastoff = 0;
DB_ASSERT(lp->b_off == 0);
memset(&t, 0, sizeof(t));
memset(&hdr, 0, sizeof(HDR));
need_free = 0;
tsize = sizeof(LOGP);
db_cipher = dbenv->crypto_handle;
if (CRYPTO_ON(dbenv))
tsize += db_cipher->adj_size(tsize);
if ((ret = __os_calloc(dbenv, 1, tsize, &tmp)) != 0)
return (ret);
lp->persist.log_size = lp->log_size = lp->log_nsize;
memcpy(tmp, &lp->persist, sizeof(LOGP));
t.data = tmp;
t.size = (u_int32_t)tsize;
need_free = 1;
if ((ret =
__log_encrypt_record(dbenv, &t, &hdr, (u_int32_t)tsize)) != 0)
goto err;
__db_chksum(t.data, t.size,
(CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
lsn = lp->lsn;
if ((ret = __log_putr(dblp, &lsn,
&t, lastoff == 0 ? 0 : lastoff - lp->len, &hdr)) != 0)
goto err;
if (lsnp != NULL)
*lsnp = lp->lsn;
err:
if (need_free)
__os_free(dbenv, tmp);
return (ret);
}
static int
__log_putr(dblp, lsn, dbt, prev, h)
DB_LOG *dblp;
DB_LSN *lsn;
const DBT *dbt;
u_int32_t prev;
HDR *h;
{
DB_CIPHER *db_cipher;
DB_ENV *dbenv;
DB_LSN f_lsn;
LOG *lp;
HDR tmp, *hdr;
int ret, t_ret;
size_t b_off, nr;
u_int32_t w_off;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
db_cipher = dbenv->crypto_handle;
if (h == NULL) {
hdr = &tmp;
memset(hdr, 0, sizeof(HDR));
if (CRYPTO_ON(dbenv))
hdr->size = HDR_CRYPTO_SZ;
else
hdr->size = HDR_NORMAL_SZ;
} else
hdr = h;
b_off = lp->b_off;
w_off = lp->w_off;
f_lsn = lp->f_lsn;
hdr->prev = prev;
hdr->len = (u_int32_t)hdr->size + dbt->size;
if (hdr->chksum[0] == 0)
__db_chksum(dbt->data, dbt->size,
(CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL,
hdr->chksum);
if ((ret = __log_fill(dblp, lsn, hdr, (u_int32_t)hdr->size)) != 0)
goto err;
if ((ret = __log_fill(dblp, lsn, dbt->data, dbt->size)) != 0)
goto err;
lp->len = (u_int32_t)(hdr->size + dbt->size);
lp->lsn.offset += (u_int32_t)(hdr->size + dbt->size);
return (0);
err:
if (w_off + lp->buffer_size < lp->w_off) {
if ((t_ret = __os_seek(dbenv,
dblp->lfhp, 0, 0, w_off, 0, DB_OS_SEEK_SET)) != 0 ||
(t_ret = __os_read(dbenv, dblp->lfhp, dblp->bufp,
b_off, &nr)) != 0)
return (__db_panic(dbenv, t_ret));
if (nr != b_off) {
__db_err(dbenv, "Short read while restoring log");
return (__db_panic(dbenv, EIO));
}
}
lp->w_off = w_off;
lp->b_off = b_off;
lp->f_lsn = f_lsn;
return (ret);
}
int
__log_flush_pp(dbenv, lsn)
DB_ENV *dbenv;
const DB_LSN *lsn;
{
int rep_check, ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lg_handle, "DB_ENV->log_flush", DB_INIT_LOG);
rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
if (rep_check)
__env_rep_enter(dbenv);
ret = __log_flush(dbenv, lsn);
if (rep_check)
__env_rep_exit(dbenv);
return (ret);
}
int
__log_flush(dbenv, lsn)
DB_ENV *dbenv;
const DB_LSN *lsn;
{
DB_LOG *dblp;
int ret;
dblp = dbenv->lg_handle;
R_LOCK(dbenv, &dblp->reginfo);
ret = __log_flush_int(dblp, lsn, 1);
R_UNLOCK(dbenv, &dblp->reginfo);
return (ret);
}
int
__log_flush_int(dblp, lsnp, release)
DB_LOG *dblp;
const DB_LSN *lsnp;
int release;
{
struct __db_commit *commit;
DB_ENV *dbenv;
DB_LSN flush_lsn, f_lsn;
DB_MUTEX *flush_mutexp;
LOG *lp;
size_t b_off;
u_int32_t ncommit, w_off;
int do_flush, first, ret;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
flush_mutexp = R_ADDR(&dblp->reginfo, lp->flush_mutex_off);
ncommit = 0;
ret = 0;
if (lsnp == NULL) {
flush_lsn.file = lp->lsn.file;
flush_lsn.offset = lp->lsn.offset - lp->len;
} else if (lsnp->file > lp->lsn.file ||
(lsnp->file == lp->lsn.file &&
lsnp->offset > lp->lsn.offset - lp->len)) {
__db_err(dbenv,
"DB_ENV->log_flush: LSN of %lu/%lu past current end-of-log of %lu/%lu",
(u_long)lsnp->file, (u_long)lsnp->offset,
(u_long)lp->lsn.file, (u_long)lp->lsn.offset);
__db_err(dbenv, "%s %s %s",
"Database environment corrupt; the wrong log files may",
"have been removed or incompatible database files imported",
"from another environment");
return (EINVAL);
} else {
if (lp->s_lsn.file > lsnp->file)
return (0);
if (lp->s_lsn.file == lsnp->file &&
lp->s_lsn.offset > lsnp->offset)
return (0);
flush_lsn = *lsnp;
}
if (release && lp->in_flush != 0) {
if ((commit = SH_TAILQ_FIRST(
&lp->free_commits, __db_commit)) == NULL) {
if ((ret =
__db_shalloc(dblp->reginfo.addr,
sizeof(struct __db_commit),
MUTEX_ALIGN, &commit)) != 0)
goto flush;
memset(commit, 0, sizeof(*commit));
if ((ret = __db_mutex_setup(dbenv, &dblp->reginfo,
&commit->mutex, MUTEX_SELF_BLOCK |
MUTEX_NO_RLOCK)) != 0) {
__db_shalloc_free(dblp->reginfo.addr, commit);
return (ret);
}
MUTEX_LOCK(dbenv, &commit->mutex);
} else
SH_TAILQ_REMOVE(
&lp->free_commits, commit, links, __db_commit);
lp->ncommit++;
if (log_compare(&lp->t_lsn, &flush_lsn) < 0)
lp->t_lsn = flush_lsn;
commit->lsn = flush_lsn;
SH_TAILQ_INSERT_HEAD(
&lp->commits, commit, links, __db_commit);
R_UNLOCK(dbenv, &dblp->reginfo);
MUTEX_LOCK(dbenv, &commit->mutex);
R_LOCK(dbenv, &dblp->reginfo);
lp->ncommit--;
do_flush = F_ISSET(commit, DB_COMMIT_FLUSH);
F_CLR(commit, DB_COMMIT_FLUSH);
SH_TAILQ_INSERT_HEAD(
&lp->free_commits, commit, links, __db_commit);
if (do_flush) {
lp->in_flush--;
flush_lsn = lp->t_lsn;
} else
return (0);
}
flush: MUTEX_LOCK(dbenv, flush_mutexp);
if (flush_lsn.file < lp->s_lsn.file ||
(flush_lsn.file == lp->s_lsn.file &&
flush_lsn.offset < lp->s_lsn.offset)) {
MUTEX_UNLOCK(dbenv, flush_mutexp);
goto done;
}
if (lp->b_off != 0 && log_compare(&flush_lsn, &lp->f_lsn) >= 0) {
if ((ret = __log_write(dblp,
dblp->bufp, (u_int32_t)lp->b_off)) != 0) {
MUTEX_UNLOCK(dbenv, flush_mutexp);
goto done;
}
lp->b_off = 0;
}
if (dblp->lfhp == NULL || dblp->lfname != lp->lsn.file)
if ((ret = __log_newfh(dblp)) != 0) {
MUTEX_UNLOCK(dbenv, flush_mutexp);
goto done;
}
b_off = lp->b_off;
w_off = lp->w_off;
f_lsn = lp->f_lsn;
lp->in_flush++;
if (release)
R_UNLOCK(dbenv, &dblp->reginfo);
if ((ret = __os_fsync(dbenv, dblp->lfhp)) != 0) {
MUTEX_UNLOCK(dbenv, flush_mutexp);
if (release)
R_LOCK(dbenv, &dblp->reginfo);
ret = __db_panic(dbenv, ret);
return (ret);
}
lp->s_lsn = f_lsn;
if (b_off == 0)
lp->s_lsn.offset = w_off;
MUTEX_UNLOCK(dbenv, flush_mutexp);
if (release)
R_LOCK(dbenv, &dblp->reginfo);
lp->in_flush--;
++lp->stat.st_scount;
ncommit = 1;
done:
if (lp->ncommit != 0) {
first = 1;
for (commit = SH_TAILQ_FIRST(&lp->commits, __db_commit);
commit != NULL;
commit = SH_TAILQ_NEXT(commit, links, __db_commit))
if (log_compare(&lp->s_lsn, &commit->lsn) > 0) {
MUTEX_UNLOCK(dbenv, &commit->mutex);
SH_TAILQ_REMOVE(
&lp->commits, commit, links, __db_commit);
ncommit++;
} else if (first == 1) {
F_SET(commit, DB_COMMIT_FLUSH);
MUTEX_UNLOCK(dbenv, &commit->mutex);
SH_TAILQ_REMOVE(
&lp->commits, commit, links, __db_commit);
lp->in_flush++;
first = 0;
}
}
if (lp->stat.st_maxcommitperflush < ncommit)
lp->stat.st_maxcommitperflush = ncommit;
if (lp->stat.st_mincommitperflush > ncommit ||
lp->stat.st_mincommitperflush == 0)
lp->stat.st_mincommitperflush = ncommit;
return (ret);
}
static int
__log_fill(dblp, lsn, addr, len)
DB_LOG *dblp;
DB_LSN *lsn;
void *addr;
u_int32_t len;
{
LOG *lp;
u_int32_t bsize, nrec;
size_t nw, remain;
int ret;
lp = dblp->reginfo.primary;
bsize = lp->buffer_size;
while (len > 0) {
if (lp->b_off == 0)
lp->f_lsn = *lsn;
if (lp->b_off == 0 && len >= bsize) {
nrec = len / bsize;
if ((ret = __log_write(dblp, addr, nrec * bsize)) != 0)
return (ret);
addr = (u_int8_t *)addr + nrec * bsize;
len -= nrec * bsize;
++lp->stat.st_wcount_fill;
continue;
}
remain = bsize - lp->b_off;
nw = remain > len ? len : remain;
memcpy(dblp->bufp + lp->b_off, addr, nw);
addr = (u_int8_t *)addr + nw;
len -= (u_int32_t)nw;
lp->b_off += nw;
if (lp->b_off == bsize) {
if ((ret = __log_write(dblp, dblp->bufp, bsize)) != 0)
return (ret);
lp->b_off = 0;
++lp->stat.st_wcount_fill;
}
}
return (0);
}
static int
__log_write(dblp, addr, len)
DB_LOG *dblp;
void *addr;
u_int32_t len;
{
DB_ENV *dbenv;
LOG *lp;
size_t nw;
int ret;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
if (dblp->lfhp == NULL || dblp->lfname != lp->lsn.file)
if ((ret = __log_newfh(dblp)) != 0)
return (ret);
if ((ret = __os_seek(dbenv,
dblp->lfhp, 0, 0, lp->w_off, 0, DB_OS_SEEK_SET)) != 0 ||
(ret = __os_write(dbenv, dblp->lfhp, addr, len, &nw)) != 0)
return (ret);
lp->w_off += len;
if ((lp->stat.st_w_bytes += len) >= MEGABYTE) {
lp->stat.st_w_bytes -= MEGABYTE;
++lp->stat.st_w_mbytes;
}
if ((lp->stat.st_wc_bytes += len) >= MEGABYTE) {
lp->stat.st_wc_bytes -= MEGABYTE;
++lp->stat.st_wc_mbytes;
}
++lp->stat.st_wcount;
return (0);
}
int
__log_file_pp(dbenv, lsn, namep, len)
DB_ENV *dbenv;
const DB_LSN *lsn;
char *namep;
size_t len;
{
int rep_check, ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv,
dbenv->lg_handle, "DB_ENV->log_file", DB_INIT_LOG);
rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0;
if (rep_check)
__env_rep_enter(dbenv);
ret = __log_file(dbenv, lsn, namep, len);
if (rep_check)
__env_rep_exit(dbenv);
return (ret);
}
static int
__log_file(dbenv, lsn, namep, len)
DB_ENV *dbenv;
const DB_LSN *lsn;
char *namep;
size_t len;
{
DB_LOG *dblp;
int ret;
char *name;
dblp = dbenv->lg_handle;
R_LOCK(dbenv, &dblp->reginfo);
ret = __log_name(dblp, lsn->file, &name, NULL, 0);
R_UNLOCK(dbenv, &dblp->reginfo);
if (ret != 0)
return (ret);
if (len < strlen(name) + 1) {
*namep = '\0';
__db_err(dbenv, "DB_ENV->log_file: name buffer is too short");
return (EINVAL);
}
(void)strcpy(namep, name);
__os_free(dbenv, name);
return (0);
}
static int
__log_newfh(dblp)
DB_LOG *dblp;
{
DB_ENV *dbenv;
LOG *lp;
u_int32_t flags;
int ret;
logfile_validity status;
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
if (dblp->lfhp != NULL) {
(void)__os_closehandle(dbenv, dblp->lfhp);
dblp->lfhp = NULL;
}
flags = DB_OSO_CREATE | DB_OSO_SEQ |
(F_ISSET(dbenv, DB_ENV_DIRECT_LOG) ? DB_OSO_DIRECT : 0);
#ifdef SET_DB_OSO_LOG
LF_SET(DB_OSO_LOG);
#endif
dblp->lfname = lp->lsn.file;
if ((ret = __log_valid(dblp, dblp->lfname, 0, &dblp->lfhp,
flags, &status)) != 0)
__db_err(dbenv,
"DB_ENV->log_put: %d: %s", lp->lsn.file, db_strerror(ret));
else if (status != DB_LV_NORMAL && status != DB_LV_INCOMPLETE)
ret = DB_NOTFOUND;
return (ret);
}
int
__log_name(dblp, filenumber, namep, fhpp, flags)
DB_LOG *dblp;
u_int32_t filenumber, flags;
char **namep;
DB_FH **fhpp;
{
DB_ENV *dbenv;
LOG *lp;
int ret;
char *oname;
char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20];
dbenv = dblp->dbenv;
lp = dblp->reginfo.primary;
(void)snprintf(new, sizeof(new), LFNAME, filenumber);
if ((ret = __db_appname(dbenv,
DB_APP_LOG, new, 0, NULL, namep)) != 0 || fhpp == NULL)
return (ret);
if ((ret = __os_open_extend(dbenv,
*namep, lp->log_size, 0, flags, lp->persist.mode, fhpp)) == 0)
return (0);
if (!LF_ISSET(DB_OSO_RDONLY)) {
__db_err(dbenv,
"%s: log file open failed: %s", *namep, db_strerror(ret));
return (__db_panic(dbenv, ret));
}
(void)snprintf(old, sizeof(old), LFNAME_V1, filenumber);
if ((ret = __db_appname(dbenv, DB_APP_LOG, old, 0, NULL, &oname)) != 0)
goto err;
if ((ret =
__os_open(dbenv, oname, flags, lp->persist.mode, fhpp)) == 0) {
__os_free(dbenv, *namep);
*namep = oname;
return (0);
}
err: __os_free(dbenv, oname);
return (ret);
}
int
__log_rep_put(dbenv, lsnp, rec)
DB_ENV *dbenv;
DB_LSN *lsnp;
const DBT *rec;
{
DB_CIPHER *db_cipher;
DB_LOG *dblp;
HDR hdr;
DBT *dbt, t;
LOG *lp;
int need_free, ret;
dblp = dbenv->lg_handle;
lp = dblp->reginfo.primary;
R_LOCK(dbenv, &dblp->reginfo);
memset(&hdr, 0, sizeof(HDR));
t = *rec;
dbt = &t;
need_free = 0;
db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
if (CRYPTO_ON(dbenv))
t.size += db_cipher->adj_size(rec->size);
if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0)
goto err;
need_free = 1;
memcpy(t.data, rec->data, rec->size);
if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, rec->size)) != 0)
goto err;
__db_chksum(t.data, t.size,
(CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum);
DB_ASSERT(log_compare(lsnp, &lp->lsn) == 0);
ret = __log_putr(dblp, lsnp, dbt, lp->lsn.offset - lp->len, &hdr);
err:
lp->ready_lsn = lp->lsn;
R_UNLOCK(dbenv, &dblp->reginfo);
if (need_free)
__os_free(dbenv, t.data);
return (ret);
}
static int
__log_encrypt_record(dbenv, dbt, hdr, orig)
DB_ENV *dbenv;
DBT *dbt;
HDR *hdr;
u_int32_t orig;
{
DB_CIPHER *db_cipher;
int ret;
if (CRYPTO_ON(dbenv)) {
db_cipher = (DB_CIPHER *)dbenv->crypto_handle;
hdr->size = HDR_CRYPTO_SZ;
hdr->orig_size = orig;
if ((ret = db_cipher->encrypt(dbenv, db_cipher->data,
hdr->iv, dbt->data, dbt->size)) != 0)
return (ret);
} else {
hdr->size = HDR_NORMAL_SZ;
}
return (0);
}