#include "db_config.h"
#include "db_int.h"
#include "dbinc/log.h"
#include "dbinc/mp.h"
static int __memp_reset_lru __P((ENV *, REGINFO *));
int
__memp_fput_pp(dbmfp, pgaddr, priority, flags)
DB_MPOOLFILE *dbmfp;
void *pgaddr;
DB_CACHE_PRIORITY priority;
u_int32_t flags;
{
DB_THREAD_INFO *ip;
ENV *env;
int ret, t_ret;
env = dbmfp->env;
if (flags != 0)
return (__db_ferr(env, "DB_MPOOLFILE->put", 0));
MPF_ILLEGAL_BEFORE_OPEN(dbmfp, "DB_MPOOLFILE->put");
ENV_ENTER(env, ip);
ret = __memp_fput(dbmfp, ip, pgaddr, priority);
if (IS_ENV_REPLICATED(env) &&
(t_ret = __op_rep_exit(env)) != 0 && ret == 0)
ret = t_ret;
ENV_LEAVE(env, ip);
return (ret);
}
int
__memp_fput(dbmfp, ip, pgaddr, priority)
DB_MPOOLFILE *dbmfp;
DB_THREAD_INFO *ip;
void *pgaddr;
DB_CACHE_PRIORITY priority;
{
BH *bhp;
DB_ENV *dbenv;
DB_MPOOL *dbmp;
DB_MPOOL_HASH *hp;
ENV *env;
MPOOL *c_mp;
MPOOLFILE *mfp;
PIN_LIST *list, *lp;
REGINFO *infop, *reginfo;
roff_t b_ref;
int region;
int adjust, pfactor, ret, t_ret;
char buf[DB_THREADID_STRLEN];
env = dbmfp->env;
dbenv = env->dbenv;
dbmp = env->mp_handle;
mfp = dbmfp->mfp;
bhp = (BH *)((u_int8_t *)pgaddr - SSZA(BH, buf));
ret = 0;
if (F_ISSET(dbmfp, MP_DUMMY))
goto unpin;
if (dbmfp->addr != NULL && pgaddr >= dbmfp->addr &&
(u_int8_t *)pgaddr <= (u_int8_t *)dbmfp->addr + dbmfp->len)
return (0);
DB_ASSERT(env, IS_RECOVERING(env) || bhp->pgno <= mfp->last_pgno ||
F_ISSET(bhp, BH_FREED) || !SH_CHAIN_SINGLETON(bhp, vc));
#ifdef DIAGNOSTIC
MPOOL_SYSTEM_LOCK(env);
if (dbmfp->pinref == 0) {
MPOOL_SYSTEM_UNLOCK(env);
__db_errx(env, DB_STR_A("3011",
"%s: more pages returned than retrieved", "%s"),
__memp_fn(dbmfp));
return (__env_panic(env, EACCES));
}
--dbmfp->pinref;
MPOOL_SYSTEM_UNLOCK(env);
#endif
unpin:
infop = &dbmp->reginfo[bhp->region];
c_mp = infop->primary;
hp = R_ADDR(infop, c_mp->htab);
hp = &hp[bhp->bucket];
if (atomic_read(&bhp->ref) == 0) {
__db_errx(env, DB_STR_A("3012",
"%s: page %lu: unpinned page returned", "%s %lu"),
__memp_fn(dbmfp), (u_long)bhp->pgno);
DB_ASSERT(env, atomic_read(&bhp->ref) != 0);
return (__env_panic(env, EACCES));
}
++c_mp->put_counter;
if (ip != NULL) {
reginfo = env->reginfo;
list = R_ADDR(reginfo, ip->dbth_pinlist);
region = (int)(infop - dbmp->reginfo);
b_ref = R_OFFSET(infop, bhp);
for (lp = list; lp < &list[ip->dbth_pinmax]; lp++)
if (lp->b_ref == b_ref && lp->region == region)
break;
if (lp == &list[ip->dbth_pinmax]) {
__db_errx(env, DB_STR_A("3013",
"__memp_fput: pinned buffer not found for thread %s",
"%s"), dbenv->thread_id_string(dbenv,
ip->dbth_pid, ip->dbth_tid, buf));
return (__env_panic(env, EINVAL));
}
lp->b_ref = INVALID_ROFF;
ip->dbth_pincount--;
}
if (F_ISSET(bhp, BH_EXCLUSIVE) && F_ISSET(bhp, BH_DIRTY)) {
DB_ASSERT(env, atomic_read(&hp->hash_page_dirty) > 0);
mfp->file_written = 1;
}
DB_ASSERT(env, atomic_read(&bhp->ref) != 0);
if (atomic_dec(env, &bhp->ref) > 1 || (atomic_read(&bhp->ref) == 1 &&
!F_ISSET(bhp, BH_DIRTY))) {
if (F_ISSET(bhp, BH_EXCLUSIVE))
F_CLR(bhp, BH_EXCLUSIVE);
MUTEX_UNLOCK(env, bhp->mtx_buf);
return (0);
}
#ifdef DIAG_MVCC
MUTEX_LOCK(env, hp->mtx_hash);
if (BH_REFCOUNT(bhp) == 0)
MVCC_MPROTECT(bhp->buf, mfp->pagesize, 0);
MUTEX_UNLOCK(env, hp->mtx_hash);
#endif
if (priority == DB_PRIORITY_VERY_LOW ||
mfp->priority == MPOOL_PRI_VERY_LOW)
bhp->priority = 0;
else {
bhp->priority = c_mp->lru_priority;
switch (priority) {
default:
case DB_PRIORITY_UNCHANGED:
pfactor = mfp->priority;
break;
case DB_PRIORITY_VERY_LOW:
pfactor = MPOOL_PRI_VERY_LOW;
break;
case DB_PRIORITY_LOW:
pfactor = MPOOL_PRI_LOW;
break;
case DB_PRIORITY_DEFAULT:
pfactor = MPOOL_PRI_DEFAULT;
break;
case DB_PRIORITY_HIGH:
pfactor = MPOOL_PRI_HIGH;
break;
case DB_PRIORITY_VERY_HIGH:
pfactor = MPOOL_PRI_VERY_HIGH;
break;
}
adjust = 0;
if (pfactor != 0)
adjust = (int)c_mp->pages / pfactor;
if (F_ISSET(bhp, BH_DIRTY))
adjust += (int)c_mp->pages / MPOOL_PRI_DIRTY;
if (adjust > 0) {
if (MPOOL_LRU_REDZONE - bhp->priority >=
(u_int32_t)adjust)
bhp->priority += adjust;
} else if (adjust < 0)
if (bhp->priority > (u_int32_t)-adjust)
bhp->priority += adjust;
}
if (F_ISSET(bhp, BH_EXCLUSIVE))
F_CLR(bhp, BH_EXCLUSIVE);
MUTEX_UNLOCK(env, bhp->mtx_buf);
if (++c_mp->lru_priority >= MPOOL_LRU_REDZONE &&
(t_ret = __memp_reset_lru(env, infop)) != 0 && ret == 0)
ret = t_ret;
return (ret);
}
static int
__memp_reset_lru(env, infop)
ENV *env;
REGINFO *infop;
{
BH *bhp, *tbhp;
DB_MPOOL_HASH *hp;
MPOOL *c_mp;
u_int32_t bucket;
int reset;
c_mp = infop->primary;
MPOOL_REGION_LOCK(env, infop);
reset = c_mp->lru_priority >= MPOOL_LRU_DECREMENT;
if (reset) {
c_mp->lru_priority -= MPOOL_LRU_DECREMENT;
c_mp->lru_generation++;
}
MPOOL_REGION_UNLOCK(env, infop);
if (!reset)
return (0);
for (hp = R_ADDR(infop, c_mp->htab),
bucket = 0; bucket < c_mp->htab_buckets; ++hp, ++bucket) {
if (SH_TAILQ_FIRST(&hp->hash_bucket, __bh) == NULL)
continue;
MUTEX_LOCK(env, hp->mtx_hash);
SH_TAILQ_FOREACH(bhp, &hp->hash_bucket, hq, __bh) {
for (tbhp = bhp; tbhp != NULL;
tbhp = SH_CHAIN_PREV(tbhp, vc, __bh)) {
if (tbhp->priority > MPOOL_LRU_DECREMENT)
tbhp->priority -= MPOOL_LRU_DECREMENT;
else
tbhp->priority = 0;
}
}
MUTEX_UNLOCK(env, hp->mtx_hash);
}
COMPQUIET(env, NULL);
return (0);
}
int
__memp_unpin_buffers(env, ip)
ENV *env;
DB_THREAD_INFO *ip;
{
BH *bhp;
DB_MPOOL *dbmp;
DB_MPOOLFILE dbmf;
PIN_LIST *list, *lp;
REGINFO *rinfop, *reginfo;
int ret;
memset(&dbmf, 0, sizeof(dbmf));
dbmf.env = env;
dbmf.flags = MP_DUMMY;
dbmp = env->mp_handle;
reginfo = env->reginfo;
list = R_ADDR(reginfo, ip->dbth_pinlist);
for (lp = list; lp < &list[ip->dbth_pinmax]; lp++) {
if (lp->b_ref == INVALID_ROFF)
continue;
rinfop = &dbmp->reginfo[lp->region];
bhp = R_ADDR(rinfop, lp->b_ref);
dbmf.mfp = R_ADDR(dbmp->reginfo, bhp->mf_offset);
if ((ret = __memp_fput(&dbmf, ip,
(u_int8_t *)bhp + SSZA(BH, buf),
DB_PRIORITY_UNCHANGED)) != 0)
return (ret);
}
return (0);
}