Commit 99b35c5f authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Counter-intuitively change the LRU list from a VTAILQ to a VLIST.

The cruical difference is that we can remove from a VLIST without
having the head of the VLIST, which comes handy when expiring a
non-instantiated object from a -spersistent stevedore.

We flip the LRU list around, so that the frontmost element has not
been accessed for the longest time, and simulate tail-inserts by
putting a senteniel on the tail of the list.

Presently the senteniel is a full objcore, which is a non-issue with
few machines having more than a handful of stevedores, but once the
persistent stevedore moves to per-segment LRU lists, this needs to
be addressed, probably by wrapping the LRU linkage in a separate
structure.


git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@4211 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 30dd8521
......@@ -290,7 +290,7 @@ struct objcore {
#define OC_F_PERSISTENT (1<<3)
unsigned timer_idx;
VTAILQ_ENTRY(objcore) list;
VTAILQ_ENTRY(objcore) lru_list;
VLIST_ENTRY(objcore) lru_list;
VTAILQ_ENTRY(objcore) ban_list;
struct smp_seg *smp_seg;
struct ban *ban;
......@@ -488,11 +488,11 @@ extern pthread_t cli_thread;
/* cache_expiry.c */
void EXP_Insert(struct object *o);
void EXP_Inject(struct objcore *oc, struct objcore_head *lru, double ttl);
void EXP_Inject(struct objcore *oc, struct objcore *lrut, double ttl);
void EXP_Init(void);
void EXP_Rearm(const struct object *o);
int EXP_Touch(const struct object *o);
int EXP_NukeOne(struct sess *sp, struct objcore_head *lru);
int EXP_NukeOne(struct sess *sp, const struct objcore_head *lru);
/* cache_fetch.c */
int FetchHdr(struct sess *sp);
......
......@@ -97,7 +97,7 @@ update_object_when(const struct object *o)
*/
void
EXP_Inject(struct objcore *oc, struct objcore_head *lru, double ttl)
EXP_Inject(struct objcore *oc, struct objcore *lrut, double ttl)
{
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
......@@ -107,10 +107,8 @@ EXP_Inject(struct objcore *oc, struct objcore_head *lru, double ttl)
oc->timer_when = ttl;
binheap_insert(exp_heap, oc);
assert(oc->timer_idx != BINHEAP_NOIDX);
if (lru != NULL) {
VTAILQ_INSERT_TAIL(lru, oc, lru_list);
oc->flags |= OC_F_ONLRU;
}
VLIST_INSERT_BEFORE(lrut, oc, lru_list);
oc->flags |= OC_F_ONLRU;
Lck_Unlock(&exp_mtx);
}
......@@ -124,8 +122,7 @@ EXP_Inject(struct objcore *oc, struct objcore_head *lru, double ttl)
void
EXP_Insert(struct object *o)
{
struct objcore *oc;
struct objcore_head *lru;
struct objcore *oc, *lrut;
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
......@@ -136,14 +133,15 @@ EXP_Insert(struct object *o)
assert(o->entered != 0 && !isnan(o->entered));
o->last_lru = o->entered;
lrut = STV_lru(o->objstore);
Lck_Lock(&exp_mtx);
assert(oc->timer_idx == BINHEAP_NOIDX);
(void)update_object_when(o);
binheap_insert(exp_heap, oc);
assert(oc->timer_idx != BINHEAP_NOIDX);
lru = STV_lru(o->objstore);
if (lru != NULL) {
VTAILQ_INSERT_TAIL(lru, oc, lru_list);
if (o->objstore != NULL) {
CHECK_OBJ_NOTNULL(lrut, OBJCORE_MAGIC);
VLIST_INSERT_BEFORE(lrut, oc, lru_list);
oc->flags |= OC_F_ONLRU;
}
Lck_Unlock(&exp_mtx);
......@@ -163,24 +161,25 @@ EXP_Insert(struct object *o)
int
EXP_Touch(const struct object *o)
{
struct objcore *oc;
int retval = 0;
struct objcore_head *lru;
struct objcore *oc, *lrut;
CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
oc = o->objcore;
if (oc == NULL)
return (retval);
lru = STV_lru(o->objstore);
if (lru == NULL)
return (retval);
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
/* We must have an objhead, otherwise we have no business on a LRU */
CHECK_OBJ_NOTNULL(oc->objhead, OBJHEAD_MAGIC);
if (o->objstore == NULL) /* XXX ?? */
return (retval);
lrut = STV_lru(o->objstore);
CHECK_OBJ_NOTNULL(lrut, OBJCORE_MAGIC);
if (Lck_Trylock(&exp_mtx))
return (retval);
if (oc->flags & OC_F_ONLRU) {
VTAILQ_REMOVE(lru, oc, lru_list);
VTAILQ_INSERT_TAIL(lru, oc, lru_list);
if (oc->flags & OC_F_ONLRU) { /* XXX ?? */
VLIST_REMOVE(oc, lru_list);
VLIST_INSERT_BEFORE(lrut, oc, lru_list);
VSL_stats->n_lru_moved++;
retval = 1;
}
......@@ -243,7 +242,6 @@ exp_timer(struct sess *sp, void *priv)
struct objcore *oc;
struct object *o;
double t;
struct objcore_head *lru;
(void)priv;
VCL_Get(&sp->vcl);
......@@ -273,16 +271,9 @@ exp_timer(struct sess *sp, void *priv)
/* And from LRU */
if (oc->flags & OC_F_ONLRU) {
assert(!(oc->flags & OC_F_PERSISTENT));
o = oc->obj;
lru = STV_lru(o->objstore);
AN(lru);
VTAILQ_REMOVE(lru, o->objcore, lru_list);
VLIST_REMOVE(oc, lru_list);
oc->flags &= ~OC_F_ONLRU;
} else {
o = NULL;
assert(oc->flags & OC_F_PERSISTENT);
}
}
VSL_stats->n_expired++;
......@@ -296,8 +287,8 @@ exp_timer(struct sess *sp, void *priv)
o->xid, (int)(o->ttl - t));
HSH_Deref(sp->wrk, &o);
} else {
WSL(sp->wrk, SLT_ExpKill, 1, "%u %d",
o, (int)(oc->timer_when - t));
WSL(sp->wrk, SLT_ExpKill, 1, "-1 %d",
(int)(oc->timer_when - t));
sp->objhead = oc->objhead;
sp->objcore = oc;
HSH_DerefObjCore(sp);
......@@ -312,7 +303,7 @@ exp_timer(struct sess *sp, void *priv)
*/
int
EXP_NukeOne(struct sess *sp, struct objcore_head *lru)
EXP_NukeOne(struct sess *sp, const struct objcore_head *lru)
{
struct objcore *oc;
......@@ -327,7 +318,7 @@ EXP_NukeOne(struct sess *sp, struct objcore_head *lru)
*
*/
Lck_Lock(&exp_mtx);
VTAILQ_FOREACH(oc, lru, lru_list) {
VLIST_FOREACH(oc, lru, lru_list) {
CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
if (oc->timer_idx == BINHEAP_NOIDX) /* exp_timer has it */
continue;
......@@ -335,7 +326,7 @@ EXP_NukeOne(struct sess *sp, struct objcore_head *lru)
break;
}
if (oc != NULL) {
VTAILQ_REMOVE(lru, oc, lru_list);
VLIST_REMOVE(oc, lru_list);
oc->flags &= ~OC_F_ONLRU;
binheap_delete(exp_heap, oc->timer_idx);
assert(oc->timer_idx == BINHEAP_NOIDX);
......
......@@ -67,5 +67,5 @@ struct choice {
/* Sort of hack-ish... */
struct objcore;
VTAILQ_HEAD(objcore_head, objcore);
VLIST_HEAD(objcore_head, objcore);
......@@ -124,7 +124,9 @@ STV_add(const struct stevedore *stv2, int ac, char * const *av)
*stv = *stv2;
AN(stv->name);
AN(stv->alloc);
VTAILQ_INIT(&stv->lru);
ALLOC_OBJ(stv->lru_tail, OBJCORE_MAGIC);
VLIST_INIT(&stv->lru);
VLIST_INSERT_HEAD(&stv->lru, stv->lru_tail, lru_list);
if (stv->init != NULL)
stv->init(stv, ac, av);
......@@ -159,14 +161,12 @@ STV_close(void)
}
}
struct objcore_head *
struct objcore *
STV_lru(struct storage *st)
{
if (st == NULL)
return (NULL);
CHECK_OBJ(st, STORAGE_MAGIC);
CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
return (&st->stevedore->lru);
return (st->stevedore->lru_tail);
}
const struct choice STV_choice[] = {
......
......@@ -55,6 +55,7 @@ struct stevedore {
storage_close_f *close;
struct objcore_head lru;
struct objcore *lru_tail;
/* private fields */
void *priv;
......@@ -68,7 +69,8 @@ void STV_free(struct storage *st);
void STV_add(const struct stevedore *stv, int ac, char * const *av);
void STV_open(void);
void STV_close(void);
struct objcore_head *STV_lru(struct storage *st);
struct objcore *STV_lru(struct storage *st);
int STV_GetFile(const char *fn, int *fdp, const char **fnp, const char *ctx);
uintmax_t STV_FileSize(int fd, const char *size, unsigned *granularity, const char *ctx);
......
......@@ -113,6 +113,7 @@ VTAILQ_HEAD(smp_seghead, smp_seg);
struct smp_sc {
unsigned magic;
#define SMP_SC_MAGIC 0x7b73af0a
struct stevedore *parent;
unsigned flags;
#define SMP_F_LOADED (1 << 0)
......@@ -519,6 +520,7 @@ smp_init(struct stevedore *parent, int ac, char * const *av)
/* Allocate softc */
ALLOC_OBJ(sc, SMP_SC_MAGIC);
XXXAN(sc);
sc->parent = parent;
sc->fd = -1;
VTAILQ_INIT(&sc->segments);
......@@ -834,7 +836,7 @@ smp_load_seg(struct sess *sp, const struct smp_sc *sc, struct smp_seg *sg)
oc->ban = BAN_RefBan(oc, so->ban, sc->tailban);
memcpy(sp->wrk->nobjhead->digest, so->hash, SHA256_LEN);
(void)HSH_Insert(sp);
EXP_Inject(oc, NULL, so->ttl);
EXP_Inject(oc, sc->parent->lru_tail, so->ttl);
sg->nalloc++;
}
WRK_SumStat(sp->wrk);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment