#include "db_config.h"
#include "db_int.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
#include "dbinc/txn.h"
int
__txn_checkpoint_pp(dbenv, kbytes, minutes, flags)
DB_ENV *dbenv;
u_int32_t kbytes, minutes, flags;
{
DB_THREAD_INFO *ip;
ENV *env;
int ret;
env = dbenv->env;
ENV_REQUIRES_CONFIG(env,
env->tx_handle, "txn_checkpoint", DB_INIT_TXN);
if (IS_REP_CLIENT(env))
return (0);
ENV_ENTER(env, ip);
REPLICATION_WRAP(env,
(__txn_checkpoint(env, kbytes, minutes, flags)), 0, ret);
ENV_LEAVE(env, ip);
return (ret);
}
int
__txn_checkpoint(env, kbytes, minutes, flags)
ENV *env;
u_int32_t kbytes, minutes, flags;
{
DB_LOG *dblp;
DB_LSN ckp_lsn, last_ckp, msg_lsn;
DB_TXNMGR *mgr;
DB_TXNREGION *region;
LOG *lp;
REGENV *renv;
REGINFO *infop;
time_t last_ckp_time, now;
u_int32_t bytes, id, logflags, mbytes, op;
int ret;
ret = 0;
if (IS_REP_CLIENT(env)) {
if (MPOOL_ON(env) &&
(ret = __memp_sync(env, DB_SYNC_CHECKPOINT, NULL)) != 0) {
__db_err(env, ret, DB_STR("4518",
"txn_checkpoint: failed to flush the buffer cache"));
return (ret);
}
return (0);
}
dblp = env->lg_handle;
lp = dblp->reginfo.primary;
mgr = env->tx_handle;
region = mgr->reginfo.primary;
infop = env->reginfo;
renv = infop->primary;
id = renv->envid;
MUTEX_LOCK(env, region->mtx_ckp);
if ((ret = __log_current_lsn_int(env, &ckp_lsn, &mbytes, &bytes)) != 0)
goto err;
msg_lsn = ckp_lsn;
if (!LF_ISSET(DB_FORCE)) {
if (bytes == 0 && mbytes == 0)
goto err;
if (kbytes != 0 &&
mbytes * 1024 + bytes / 1024 >= (u_int32_t)kbytes)
goto do_ckp;
if (minutes != 0) {
(void)time(&now);
TXN_SYSTEM_LOCK(env);
last_ckp_time = region->time_ckp;
TXN_SYSTEM_UNLOCK(env);
if (now - last_ckp_time >= (time_t)(minutes * 60))
goto do_ckp;
}
if (minutes != 0 || kbytes != 0)
goto err;
}
do_ckp:
if ((ret = __txn_getactive(env, &ckp_lsn)) != 0)
goto err;
if (LOGGING_ON(env) && IS_REP_MASTER(env)) {
#ifdef HAVE_REPLICATION_THREADS
if (env->rep_handle->send == NULL &&
F_ISSET(env, ENV_THREAD) && APP_IS_REPMGR(env) &&
(ret = __repmgr_autostart(env)) != 0)
goto err;
#endif
if (env->rep_handle->send != NULL)
(void)__rep_send_message(env, DB_EID_BROADCAST,
REP_START_SYNC, &msg_lsn, NULL, 0, 0);
}
if (MPOOL_ON(env) &&
(ret = __memp_sync_int(
env, NULL, 0, DB_SYNC_CHECKPOINT, NULL, NULL)) != 0) {
__db_err(env, ret, DB_STR("4519",
"txn_checkpoint: failed to flush the buffer cache"));
goto err;
}
#ifndef CONFIG_TEST
if (LOGGING_ON(env) &&
IS_REP_MASTER(env) && env->rep_handle->send != NULL &&
!LF_ISSET(DB_CKP_INTERNAL) &&
env->rep_handle->region->chkpt_delay != 0)
__os_yield(env, 0, env->rep_handle->region->chkpt_delay);
#endif
if (LOGGING_ON(env)) {
TXN_SYSTEM_LOCK(env);
last_ckp = region->last_ckp;
TXN_SYSTEM_UNLOCK(env);
logflags = DB_LOG_CHKPNT;
op = DBREG_CHKPNT;
if (!IS_RECOVERING(env))
logflags |= DB_FLUSH;
else if (region->stat.st_nrestores == 0)
op = DBREG_RCLOSE;
if ((ret = __dbreg_log_files(env, op)) != 0 ||
(ret = __txn_ckp_log(env, NULL, &ckp_lsn, logflags,
&ckp_lsn, &last_ckp, (int32_t)time(NULL), id, 0)) != 0) {
__db_err(env, ret, DB_STR_A("4520",
"txn_checkpoint: log failed at LSN [%ld %ld]",
"%ld %ld"),
(long)ckp_lsn.file, (long)ckp_lsn.offset);
goto err;
}
if ((ret = __txn_updateckp(env, &ckp_lsn)) != 0)
goto err;
}
err: MUTEX_UNLOCK(env, region->mtx_ckp);
if (ret == 0 && lp->db_log_autoremove)
__log_autoremove(env);
return (ret);
}
int
__txn_getactive(env, lsnp)
ENV *env;
DB_LSN *lsnp;
{
DB_TXNMGR *mgr;
DB_TXNREGION *region;
TXN_DETAIL *td;
mgr = env->tx_handle;
region = mgr->reginfo.primary;
TXN_SYSTEM_LOCK(env);
SH_TAILQ_FOREACH(td, ®ion->active_txn, links, __txn_detail)
if (td->begin_lsn.file != 0 &&
td->begin_lsn.offset != 0 &&
LOG_COMPARE(&td->begin_lsn, lsnp) < 0)
*lsnp = td->begin_lsn;
TXN_SYSTEM_UNLOCK(env);
return (0);
}
int
__txn_getckp(env, lsnp)
ENV *env;
DB_LSN *lsnp;
{
DB_LSN lsn;
DB_TXNMGR *mgr;
DB_TXNREGION *region;
mgr = env->tx_handle;
region = mgr->reginfo.primary;
TXN_SYSTEM_LOCK(env);
lsn = region->last_ckp;
TXN_SYSTEM_UNLOCK(env);
if (IS_ZERO_LSN(lsn))
return (DB_NOTFOUND);
*lsnp = lsn;
return (0);
}
int
__txn_updateckp(env, lsnp)
ENV *env;
DB_LSN *lsnp;
{
DB_TXNMGR *mgr;
DB_TXNREGION *region;
mgr = env->tx_handle;
region = mgr->reginfo.primary;
TXN_SYSTEM_LOCK(env);
if (LOG_COMPARE(®ion->last_ckp, lsnp) < 0) {
region->last_ckp = *lsnp;
(void)time(®ion->time_ckp);
}
TXN_SYSTEM_UNLOCK(env);
return (0);
}