]> err.no Git - varnish/commitdiff
Mostly finish the LRU code and its integration:
authordes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 27 Jun 2007 12:56:04 +0000 (12:56 +0000)
committerdes <des@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 27 Jun 2007 12:56:04 +0000 (12:56 +0000)
 - Wrap the storage code so we don't need to duplicate the "toss out some old
   crap and try again" logic everywhere.  This will also help when / if we
   decide to add support for multiple concurrent storage arenas.

 - While I'm at it, implement sma_trim().

 - Rework the interaction between the LRU and expiry code.  Instead of placing
   objects retired by the LRU on death row, immediately terminate them.

 - Give the LRU code its own fake session and worker so we don't have to pass
   it a session pointer.

 - Rework the LRU API, and add LRU_DiscardOne() which discards a single
   object.  This is what the stevedore code uses.

Known or suspected issues:

 - The LRU and expiry code should use the same mutex, and / or the possiblity
   for races between them should be examined closely.

 - LRU_Init() needs to be looked at and possibly moved.

 - LRU_DiscardSpace() and LRU_DiscardTime() are unused and quite possibly useless.

 - Logging and statistics related to the LRU need more attention.

 - The stevedore API can probably be improved.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1586 d4fa192b-c00b-0410-8231-f00ffab90ce4

12 files changed:
varnish-cache/bin/varnishd/Makefile.am
varnish-cache/bin/varnishd/cache.h
varnish-cache/bin/varnishd/cache_expire.c
varnish-cache/bin/varnishd/cache_fetch.c
varnish-cache/bin/varnishd/cache_hash.c
varnish-cache/bin/varnishd/cache_lru.c
varnish-cache/bin/varnishd/cache_synthetic.c
varnish-cache/bin/varnishd/stevedore.c [new file with mode: 0644]
varnish-cache/bin/varnishd/stevedore.h
varnish-cache/bin/varnishd/storage_file.c
varnish-cache/bin/varnishd/storage_malloc.c
varnish-cache/include/shmlog_tags.h

index c0e3eb568231a2bb4bf63eb3a9ae511f1a787fc3..e9f8c87eeb825a51b3239a9795db9c5a27d4f210 100644 (file)
@@ -42,6 +42,7 @@ varnishd_SOURCES = \
        mgt_vcc.c \
        rfc2616.c \
        shmlog.c \
+       stevedore.c \
        storage_file.c \
        storage_malloc.c \
        tcp.c \
index 52fe1dc8d3e4e90c4f9dd4478b83b2023554e392..3617b3f6952284b20f83e54572da2e8ac71b0d79 100644 (file)
@@ -375,7 +375,7 @@ void CLI_Init(void);
 void EXP_Insert(struct object *o);
 void EXP_Init(void);
 void EXP_TTLchange(struct object *o);
-void EXP_Retire(struct object *o);
+void EXP_Terminate(struct object *o);
 
 /* cache_fetch.c */
 int Fetch(struct sess *sp);
@@ -478,10 +478,12 @@ void VCL_Rel(struct VCL_conf **vcc);
 void VCL_Get(struct VCL_conf **vcc);
 
 /* cache_lru.c */
+// void LRU_Init(void);
 void LRU_Enter(struct object *o, time_t stamp);
 void LRU_Remove(struct object *o);
-void LRU_DiscardSpace(struct sess *sp, uint64_t quota);
-void LRU_DiscardTime(struct sess *sp, time_t cutoff);
+int LRU_DiscardOne(void);
+int LRU_DiscardSpace(int64_t quota);
+int LRU_DiscardTime(time_t cutoff);
 
 #define VCL_RET_MAC(l,u,b,n)
 #define VCL_MET_MAC(l,u,b) void VCL_##l##_method(struct sess *);
index 4ffe636ddf51fca5dc29da66736e30b8a3d0aea2..5b090d9102c73243c69f97b88199f3410365db76 100644 (file)
@@ -74,13 +74,25 @@ EXP_TTLchange(struct object *o)
        UNLOCK(&exp_mtx);
 }
 
+/*
+ * Immediately destroy an object.  Do not wait for it to expire or trickle
+ * through death row; yank it
+ */
 void
-EXP_Retire(struct object *o)
+EXP_Terminate(struct object *o)
 {
        LOCK(&exp_mtx);
-       TAILQ_INSERT_TAIL(&exp_deathrow, o, deathrow);
-       VSL_stats->n_deathrow++;
+       if (o->lru_stamp)
+               LRU_Remove(o);
+       if (o->heap_idx)
+               binheap_delete(exp_heap, o->heap_idx);
+       if (o->deathrow.tqe_next) {
+               TAILQ_REMOVE(&exp_deathrow, o, deathrow);
+               VSL_stats->n_deathrow--;
+       }
        UNLOCK(&exp_mtx);
+       VSL(SLT_Terminate, 0, "%u", o->xid);
+       HSH_Deref(o);
 }
 
 /*--------------------------------------------------------------------
@@ -183,7 +195,10 @@ exp_prefetch(void *arg)
                VCL_timeout_method(sp);
 
                if (sp->handling == VCL_RET_DISCARD) {
-                       EXP_Retire(o);
+                       LOCK(&exp_mtx);
+                       TAILQ_INSERT_TAIL(&exp_deathrow, o, deathrow);
+                       VSL_stats->n_deathrow++;
+                       UNLOCK(&exp_mtx);
                        continue;
                }
                assert(sp->handling == VCL_RET_DISCARD);
index 44d3570d8b59206f24fe81d7d0d74e7a22678dc3..d9f73a8f05079e4adb7a991510f57c5ba43acb67 100644 (file)
@@ -59,8 +59,7 @@ fetch_straight(const struct sess *sp, int fd, struct http *hp, char *b)
        if (cl == 0)
                return (0);
 
-       st = stevedore->alloc(stevedore, cl);
-       XXXAN(st->stevedore);
+       st = STV_alloc(cl);
        TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
        st->len = cl;
        sp->obj->len = cl;
@@ -147,11 +146,9 @@ fetch_chunked(const struct sess *sp, int fd, struct http *hp)
                        /* Get some storage if we don't have any */
                        if (st == NULL || st->len == st->space) {
                                v = u;
-                               if (u < params->fetch_chunksize * 1024 &&
-                                   stevedore->trim != NULL)
+                               if (u < params->fetch_chunksize * 1024)
                                        v = params->fetch_chunksize * 1024;
-                               st = stevedore->alloc(stevedore, v);
-                               XXXAN(st->stevedore);
+                               st = STV_alloc(v);
                                TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
                        }
                        v = st->space - st->len;
@@ -198,9 +195,9 @@ fetch_chunked(const struct sess *sp, int fd, struct http *hp)
 
        if (st != NULL && st->len == 0) {
                TAILQ_REMOVE(&sp->obj->store, st, list);
-               stevedore->free(st);
-       } else if (st != NULL && stevedore->trim != NULL)
-               stevedore->trim(st, st->len);
+               STV_free(st);
+       } else if (st != NULL)
+               STV_trim(st, st->len);
        return (0);
 }
 
@@ -226,9 +223,7 @@ fetch_eof(const struct sess *sp, int fd, struct http *hp)
        st = NULL;
        while (1) {
                if (v == 0) {
-                       st = stevedore->alloc(stevedore,
-                           params->fetch_chunksize * 1024);
-                       XXXAN(st->stevedore);
+                       st = STV_alloc(params->fetch_chunksize * 1024);
                        TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
                        p = st->ptr + st->len;
                        v = st->space - st->len;
@@ -248,9 +243,9 @@ fetch_eof(const struct sess *sp, int fd, struct http *hp)
 
        if (st->len == 0) {
                TAILQ_REMOVE(&sp->obj->store, st, list);
-               stevedore->free(st);
-       } else if (stevedore->trim != NULL)
-               stevedore->trim(st, st->len);
+               STV_free(st);
+       } else
+               STV_trim(st, st->len);
 
        return (1);
 }
@@ -345,7 +340,7 @@ Fetch(struct sess *sp)
                while (!TAILQ_EMPTY(&sp->obj->store)) {
                        st = TAILQ_FIRST(&sp->obj->store);
                        TAILQ_REMOVE(&sp->obj->store, st, list);
-                       stevedore->free(st);
+                       STV_free(st);
                }
                close(vc->fd);
                VBE_ClosedFd(sp->wrk, vc, 1);
index 0fde92fad62065c7db4e36c7ca120be156437fd2..aa4e715f2f764618e49dab9077d45bef255243b4 100644 (file)
@@ -104,7 +104,7 @@ HSH_Freestore(struct object *o)
        TAILQ_FOREACH_SAFE(st, &o->store, list, stn) {
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
                TAILQ_REMOVE(&o->store, st, list);
-               st->stevedore->free(st);
+               STV_free(st);
        }
 }
 
@@ -260,7 +260,6 @@ HSH_Deref(struct object *o)
                free(o->vary);
 
        HSH_Freestore(o);
-       LRU_Remove(o);
        FREE_OBJ(o);
        VSL_stats->n_object--;
 
index 00368b77576ffc1f500d79eaed760278374313b1..9a86183bb0d7bcb49ba1ad9648473cf96386e1c6 100644 (file)
  */
 #define LRU_DELAY 2
 
+TAILQ_HEAD(lru_head, object);
+
+static struct lru_head lru_list = TAILQ_HEAD_INITIALIZER(lru_list);
 static pthread_mutex_t lru_mtx = PTHREAD_MUTEX_INITIALIZER;
-static TAILQ_HEAD(lru_head, object) lru_list;
+static struct sess *lru_session;
+static struct worker lru_worker;
+
+/*
+ * Initialize the LRU data structures.
+ */
+static inline void
+LRU_Init(void)
+{
+       if (lru_session == NULL) {
+               lru_session = SES_New(NULL, 0);
+               XXXAN(lru_session);
+               lru_session->wrk = &lru_worker;
+               lru_worker.magic = WORKER_MAGIC;
+               lru_worker.wlp = lru_worker.wlog;
+               lru_worker.wle = lru_worker.wlog + sizeof lru_worker.wlog;
+               VCL_Get(&lru_session->vcl);
+       } else {
+               VCL_Refresh(&lru_session->vcl);
+       }
+}
 
 /*
  * Enter an object into the LRU list, or move it to the head of the list
@@ -55,12 +78,12 @@ LRU_Enter(struct object *o, time_t stamp)
        assert(stamp > 0);
        if (o->lru_stamp < stamp - LRU_DELAY && o != lru_list.tqh_first) {
                // VSL(SLT_LRU_enter, 0, "%u %u %u", o->xid, o->lru_stamp, stamp);
-               pthread_mutex_lock(&lru_mtx);
+               LOCK(&lru_mtx);
                if (o->lru_stamp != 0)
                        TAILQ_REMOVE(&lru_list, o, lru);
                TAILQ_INSERT_HEAD(&lru_list, o, lru);
                o->lru_stamp = stamp;
-               pthread_mutex_unlock(&lru_mtx);
+               UNLOCK(&lru_mtx);
        }
 }
 
@@ -74,74 +97,123 @@ LRU_Remove(struct object *o)
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
        if (o->lru_stamp != 0) {
                // VSL(SLT_LRU_remove, 0, "%u", o->xid);
-               pthread_mutex_lock(&lru_mtx);
+               LOCK(&lru_mtx);
                TAILQ_REMOVE(&lru_list, o, lru);
-               pthread_mutex_unlock(&lru_mtx);
+               UNLOCK(&lru_mtx);
        }
 }
 
+/*
+ * With the LRU lock held, call VCL_discard().  Depending on the result,
+ * either insert the object at the head of the list or dereference it.
+ */
+static int
+LRU_DiscardLocked(struct object *o)
+{
+       struct object *so;
+
+       if (o->busy)
+               return (0);
+
+       /* XXX this is a really bad place to do this */
+       LRU_Init();
+
+       CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
+       TAILQ_REMOVE(&lru_list, o, lru);
+
+       lru_session->obj = o;
+       VCL_discard_method(lru_session);
+
+       if (lru_session->handling == VCL_RET_DISCARD) {
+               /* discard: release object */
+               VSL(SLT_ExpKill, 0, "%u %d", o->xid, o->lru_stamp);
+               o->lru_stamp = 0;
+               EXP_Terminate(o);
+               return (1);
+       } else {
+               /* keep: move to front of list */
+               if ((so = TAILQ_FIRST(&lru_list)))
+                       o->lru_stamp = so->lru_stamp;
+               TAILQ_INSERT_HEAD(&lru_list, o, lru);
+               return (0);
+       }
+}
+
+/*
+ * Walk through the LRU list, starting at the back, and check each object
+ * until we find one that can be retired.  Return the number of objects
+ * that were discarded.
+ */
+int
+LRU_DiscardOne(void)
+{
+       struct object *first = TAILQ_FIRST(&lru_list);
+       struct object *o;
+       int count = 0;
+
+       LOCK(&lru_mtx);
+       while (!count && (o = TAILQ_LAST(&lru_list, lru_head))) {
+               if (LRU_DiscardLocked(o))
+                       ++count;
+               if (o == first) {
+                       /* full circle */
+                       break;
+               }
+       }
+       UNLOCK(&lru_mtx);
+       return (0);
+}
+
 /*
  * Walk through the LRU list, starting at the back, and retire objects
- * until our quota is reached or we run out of objects to retire.
+ * until our quota is reached or we run out of objects to retire.  Return
+ * the number of objects that were discarded.
  */
-void
-LRU_DiscardSpace(struct sess *sp, uint64_t quota)
+int
+LRU_DiscardSpace(int64_t quota)
 {
-       struct object *o, *so;
+       struct object *first = TAILQ_FIRST(&lru_list);
+       struct object *o;
+       unsigned int len;
+       int count = 0;
 
-       pthread_mutex_lock(&lru_mtx);
-       while ((o = TAILQ_LAST(&lru_list, lru_head))) {
-               TAILQ_REMOVE(&lru_list, o, lru);
-               so = sp->obj;
-               sp->obj = o;
-               VCL_discard_method(sp);
-               sp->obj = so;
-               if (sp->handling == VCL_RET_DISCARD) {
-                       /* discard: place on deathrow */
-                       EXP_Retire(o);
-                       o->lru_stamp = 0;
-                       if (o->len > quota)
-                               break;
-                       quota -= o->len;
-               } else {
-                       /* keep: move to front of list */
-                       if ((so = TAILQ_FIRST(&lru_list)))
-                               o->lru_stamp = so->lru_stamp;
-                       TAILQ_INSERT_HEAD(&lru_list, o, lru);
+       LOCK(&lru_mtx);
+       while (quota > 0 && (o = TAILQ_LAST(&lru_list, lru_head))) {
+               len = o->len;
+               if (LRU_DiscardLocked(o)) {
+                       quota -= len;
+                       ++count;
+               }
+               if (o == first) {
+                       /* full circle */
+                       break;
                }
        }
-       pthread_mutex_unlock(&lru_mtx);
+       UNLOCK(&lru_mtx);
+       return (count);
 }
 
 /*
  * Walk through the LRU list, starting at the back, and retire objects
- * that haven't been accessed since the specified cutoff date.
+ * that haven't been accessed since the specified cutoff date.  Return the
+ * number of objects that were discarded.
  */
-void
-LRU_DiscardTime(struct sess *sp, time_t cutoff)
+int
+LRU_DiscardTime(time_t cutoff)
 {
-       struct object *o, *so;
+       struct object *first = TAILQ_FIRST(&lru_list);
+       struct object *o;
+       int count = 0;
 
-       pthread_mutex_lock(&lru_mtx);
-       while ((o = TAILQ_LAST(&lru_list, lru_head))) {
-               if (o->lru_stamp >= cutoff)
+       LOCK(&lru_mtx);
+       while ((o = TAILQ_LAST(&lru_list, lru_head)) && o->lru_stamp <= cutoff) {
+               if (LRU_DiscardLocked(o))
+                       ++count;
+               if (o == first) {
+                       /* full circle */
                        break;
-               TAILQ_REMOVE(&lru_list, o, lru);
-               so = sp->obj;
-               sp->obj = o;
-               VCL_discard_method(sp);
-               sp->obj = so;
-               if (sp->handling == VCL_RET_DISCARD) {
-                       /* discard: place on deathrow */
-                       EXP_Retire(o);
-               } else {
-                       /* keep: move to front of list */
-                       if ((so = TAILQ_FIRST(&lru_list)) && so->lru_stamp > cutoff)
-                               o->lru_stamp = so->lru_stamp;
-                       else
-                               o->lru_stamp = cutoff;
-                       TAILQ_INSERT_HEAD(&lru_list, o, lru);
                }
        }
-       pthread_mutex_unlock(&lru_mtx);
+       UNLOCK(&lru_mtx);
+       return (count);
 }
index aa039ad739a81bed3d8beecf06625e217600b36b..64f19d155f1d7250840841f37b27079294aa9326 100644 (file)
@@ -90,7 +90,7 @@ SYN_ErrorPage(struct sess *sp, int status, const char *reason, int ttl)
 
        /* allocate space for body */
        /* XXX what if the object already has a body? */
-       st = stevedore->alloc(stevedore, 1024);
+       st = STV_alloc(1024);
        XXXAN(st->stevedore);
        TAILQ_INSERT_TAIL(&sp->obj->store, st, list);
 
diff --git a/varnish-cache/bin/varnishd/stevedore.c b/varnish-cache/bin/varnishd/stevedore.c
new file mode 100644 (file)
index 0000000..55bb3f4
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2007 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Dag-Erling Smørgav <des@linpro.no>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id$
+ */
+
+#include "cache.h"
+
+struct storage *
+STV_alloc(size_t size)
+{
+       struct storage *st;
+
+       AN(stevedore);
+       AN(stevedore->alloc);
+       do {
+               if ((st = stevedore->alloc(stevedore, size)) == NULL)
+                       LRU_DiscardOne();
+       } while (st == NULL);
+       return (st);
+}
+
+void
+STV_trim(struct storage *st, size_t size)
+{
+
+       AN(st->stevedore);
+       if (st->stevedore->trim)
+               st->stevedore->trim(st, size);
+}
+
+void
+STV_free(struct storage *st)
+{
+
+       AN(st->stevedore);
+       AN(stevedore->free);
+       st->stevedore->free(st);
+}
index 3267aa101a2d6f4525f8e84049e5f54eebd836f3..f88c11c91f2c0d7e91d8c42f7ae39fbf6ce64f93 100644 (file)
@@ -50,3 +50,7 @@ struct stevedore {
        /* private fields */
        void                    *priv;
 };
+
+struct storage *STV_alloc(size_t size);
+void STV_trim(struct storage *st, size_t size);
+void STV_free(struct storage *st);
index b1d24c1ef92f225b6213089cf5913a860d27c016..06b8b8bcd333db51f37d0a79b4c771847604b181 100644 (file)
@@ -631,6 +631,10 @@ smf_alloc(struct stevedore *st, size_t size)
        LOCK(&sc->mtx);
        VSL_stats->sm_nreq++;
        smf = alloc_smf(sc, size);
+       if (smf == NULL) {
+               UNLOCK(&sc->mtx);
+               return (NULL);
+       }
        CHECK_OBJ_NOTNULL(smf, SMF_MAGIC);
        VSL_stats->sm_nobj++;
        VSL_stats->sm_balloc += smf->size;
index 40afd92dcaa324dac690a6b3b69fa947305ad480..e7a2fbb4de9957ccb315592220024448564f69cb 100644 (file)
@@ -49,7 +49,8 @@ sma_alloc(struct stevedore *st, size_t size)
 
        VSL_stats->sm_nreq++;
        sma = calloc(sizeof *sma, 1);
-       XXXAN(sma);
+       if (sma == NULL)
+               return (NULL);
        sma->s.priv = sma;
        sma->s.ptr = malloc(size);
        XXXAN(sma->s.ptr);
@@ -68,6 +69,7 @@ sma_free(struct storage *s)
 {
        struct sma *sma;
 
+       CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
        sma = s->priv;
        VSL_stats->sm_nobj--;
        VSL_stats->sm_balloc -= sma->s.space;
@@ -75,8 +77,25 @@ sma_free(struct storage *s)
        free(sma);
 }
 
+static void
+sma_trim(struct storage *s, size_t size)
+{
+       struct sma *sma;
+       void *p;
+
+       CHECK_OBJ_NOTNULL(s, STORAGE_MAGIC);
+       sma = s->priv;
+       if ((p = realloc(sma->s.ptr, size)) != NULL) {
+               VSL_stats->sm_balloc -= sma->s.space;
+               sma->s.ptr = p;
+               sma->s.space = size;
+               VSL_stats->sm_balloc += sma->s.space;
+       }
+}
+
 struct stevedore sma_stevedore = {
        .name =         "malloc",
        .alloc =        sma_alloc,
-       .free =         sma_free
+       .free =         sma_free,
+       .trim =         sma_trim,
 };
index 020b3d61429e3cc0409e3c592e75020f461cdb3c..91f86ae15225b59a6236326abf0527678b17ac22 100644 (file)
@@ -92,3 +92,4 @@ SLTM(ExpBan)
 SLTM(ExpPick)
 SLTM(ExpKill)
 SLTM(WorkThread)
+SLTM(Terminate)