]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/upas/fs/cache.c
upas/fs: fix infinite loop in putcache (again)
[plan9front.git] / sys / src / cmd / upas / fs / cache.c
index ec2cfb9b716c4b1d8af6eb5a829e424d39c2cb2b..f7442e80c3bb872fe3b4c49af89c31056e92c154 100644 (file)
@@ -2,73 +2,26 @@
 #include <libsec.h>
 #include "dat.h"
 
-int
-findcache(Mcache *c, Message *m)
-{
-       int i;
-
-       for(i = 0; i < c->ntab; i++)
-               if(c->ctab[i] == m)
-                       return i;
-       return -1;
-}
-
-static void
-prcache(Mcache *c, char *prefix)
-{
-       int j;
-       Message *m;
-
-       if(!debug)
-               return;
-       for(j = 0; j < c->ntab; j++){
-               m = c->ctab[j];
-               dprint("%s%d/%s\t%p\t%d\t%ld\n", prefix, j, m->name, m, m->refs, m->csize);
-       }
-}
-
-/* debugging only */
 static void
-dupchk(Mcache *c)
+addlru(Mcache *c, Message *m)
 {
-       int i, j;
+       Message *l, **ll;
 
-       if(!debug)
+       if((m->cstate & (Cheader|Cbody)) == 0)
                return;
-       for(i = 0; i < c->ntab; i++)
-               for(j = i + 1; j < c->ntab; j++)
-                       if(c->ctab[i] == c->ctab[j])
-                               goto lose;
-       return;
-lose:
-       for(j = 0; j < c->ntab; j++)
-               dprint("%d\t%p  %d\t%ld\n", j, c->ctab[j], c->ctab[j]->refs, c->ctab[j]->size);
-       abort();
-}
-       
-int
-addcache(Mcache *c, Message *m)
-{
-       int i;
 
-       if((i = findcache(c, m)) < 0){
-               if(c->ntab + 1 == nelem(c->ctab))
-                       abort();
-               i = c->ntab++;
-       }else{
-               /* rotate */
-               if(i == c->ntab - 1)
-                       return i;               /* silly shortcut to prevent excessive printage. */
-               dprint("addcache rotate %d %d\n", i, c->ntab);
-               prcache(c, "");
-               memmove(c->ctab + i, c->ctab + i + 1, (c->ntab - i - 1)*sizeof c->ctab[0]);
-               i = c->ntab - 1;
-c->ctab[i] = m;
-dupchk(c);
+       c->nlru++;
+       ll = &c->lru;
+       while((l = *ll) != nil){
+               if(l == m){
+                       c->nlru--;
+                       *ll = m->lru;
+               } else {
+                       ll = &l->lru;
+               }
        }
-       dprint("addcache %d %d  %p\n", i, c->ntab, m);
-       c->ctab[i] = m;
-       return i;
+       m->lru = nil;
+       *ll = m;
 }
 
 static void
@@ -78,20 +31,32 @@ notecache(Mailbox *mb, Message *m, long sz)
        assert(sz >= 0 && sz <= Maxmsg);
        m->csize += sz;
        mb->cached += sz;
-       addcache(mb, m);
+       addlru(mb, m);
 }
 
-static long
-cachefree0(Mailbox *mb, Message *m, int force)
+void
+cachefree(Mailbox *mb, Message *m, int force)
 {
-       long sz, i;
-       Message *s;
-
-       if(!force && !mb->fetch)
-               return 0;
+       long i;
+       Message *s, **ll;
+
+       if(Topmsg(mb, m)){
+               for(ll = &mb->lru; *ll != nil; ll = &((*ll)->lru)){
+                       if(*ll == m){
+                               mb->nlru--;
+                               *ll = m->lru;
+                               m->lru = nil;
+                               break;
+                       }
+               }
+               if(mb->decache)
+                       mb->decache(mb, m);
+               mb->cached -= m->csize;
+       }
        for(s = m->part; s; s = s->next)
                cachefree(mb, s, force);
-       dprint("cachefree: %D   %p,     %p\n", m->fileid, m, m->start);
+       if(!force && mb->fetch == nil)
+               return;
        if(m->mallocd){
                free(m->start);
                m->mallocd = 0;
@@ -108,7 +73,6 @@ cachefree0(Mailbox *mb, Message *m, int force)
                free(m->references[i]);
                m->references[i] = 0;
        }
-       sz = m->csize;
        m->csize = 0;
        m->start = 0;
        m->end = 0;
@@ -119,134 +83,28 @@ cachefree0(Mailbox *mb, Message *m, int force)
        m->bend = 0;
        m->mheader = 0;
        m->mhend = 0;
-       if(mb->decache)
-               mb->decache(mb, m);
        m->decoded = 0;
        m->converted = 0;
        m->badchars = 0;
        m->cstate &= ~(Cheader|Cbody);
-       if(Topmsg(mb, m))
-               mb->cached -= sz;
-       return sz;
 }
 
-long
-cachefree(Mailbox *mb, Message *m, int force)
-{
-       long sz, i;
-
-       sz = cachefree0(mb, m, force);
-       for(i = 0; i < mb->ntab; i++)
-               if(m == mb->ctab[i]){
-                       mb->ntab--;
-                       memmove(mb->ctab + i, mb->ctab + i + 1, sizeof m*mb->ntab - i);
-                       dupchk(mb);
-                       break;
-               }
-       return sz;
-}
-
-enum{
-       Maxntab = nelem(mbl->ctab) - 10,
-};
-
-vlong
-sumcache(Mcache *c)
-{
-       int i;
-       vlong sz;
-
-       sz = 0;
-       for(i = 0; i < c->ntab; i++)
-               sz += c->ctab[i]->csize;
-       return sz;
-}
-
-int
-scancache(Mcache *c)
-{
-       int i;
-
-       for(i = 0; i < c->ntab; i++)
-               if(c->ctab[i]->csize > Maxmsg)
-                       return -1;
-       return 0;
-}
-
-/* debugging only */
-static void
-chkcsize(Mailbox *mb, vlong sz, vlong sz0)
-{
-       int j;
-       Mcache *c;
-       Message *m;
-
-       if(sumcache(mb) == mb->cached)
-       if(scancache(mb) == 0)
-               return;
-       eprint("sz0 %lld sz %lld sum %lld sumca %lld\n", sz0, sz, sumcache(mb), mb->cached);
-       eprint("%lld\n", sumcache(mb));
-       c = mb;
-       for(j = 0; j < c->ntab; j++){
-               m = c->ctab[j];
-               eprint("%d      %p      %d      %ld     %ld\n", j, m, m->refs, m->csize, m->size);
-       }
-       abort();
-}
-
-/*
- * strategy: start with i = 0. while cache exceeds limits,
- * find j so that all the [i:j] elements have refs == 0.
- * uncache all the [i:j], reduce ntab by i-j.  the tail
- * [j+1:ntab] is shifted to [i:ntab], and finally i = i+1.
- * we may safely skip the new i, since the condition
- * that stopped our scan there still holds.
- */
 void
 putcache(Mailbox *mb, Message *m)
 {
-       int i, j, k;
-       vlong sz, sz0;
-       Message **p;
+       int n;
 
-       p = mb->ctab;
-       sz0 = mb->cached;
-       dupchk(mb);
-       for(i = 0;; i++){
-               sz = mb->cached;
-               for(j = i;; j++){
-                       if(j >= mb->ntab ||
-                       sz < cachetarg && mb->ntab - (j - i) < Maxntab){
-                               if(j != i)
-                                       break;
-chkcsize(mb, sz, sz0);
+       while(!Topmsg(mb, m)) m = m->whole;
+       addlru(mb, m);
+       while(mb->lru != nil && (mb->cached > cachetarg || mb->nlru > 10)){
+               n = 0;
+               while(mb->lru->refs > 0){
+                       if(++n >= mb->nlru)
                                return;
-                       }
-                       if(p[j]->refs > 0)
-                               break;
-                       sz -= p[j]->csize;
+                       addlru(mb, mb->lru);
                }
-               if(sz == mb->cached){
-                       if(i >= mb->ntab)
-                               break;
-                       continue;
-               }
-               for(k = i; k < j; k++)
-                       cachefree0(mb, p[k], 0);
-               mb->ntab -= j - i;
-               memmove(p + i, p + j, (mb->ntab - i)*sizeof *p);
+               cachefree(mb, mb->lru, 0);
        }
-chkcsize(mb, sz, sz0);
-       k = 0;
-       for(i = 0; i < mb->ntab; i++)
-               k += p[i]->refs > 0;
-       if((mb->ntab > 1 || k != mb->ntab) && Topmsg(mb, m))
-               eprint("cache overflow: %D %llud bytes; %d entries\n", 
-                       m? m->fileid: 1ll, mb->cached, mb->ntab);
-       if(k == mb->ntab)
-               return;
-       debug = 1; prcache(mb, "");
-       abort();
 }
 
 static int
@@ -361,6 +219,9 @@ top:
 void
 cachehash(Mailbox *mb, Message *m)
 {
+       assert(mb->refs >= 0);
+       if(mb->refs == 0)
+               return;
        if(m->whole == m->whole->whole)
                henter(PATH(mb->id, Qmbox), m->name,
                        (Qid){PATH(m->id, Qdir), 0, QTDIR}, m, mb);
@@ -375,7 +236,8 @@ static char *itab[] = {
        "idx",
        "stale",
        "header",
-       "body"
+       "body",
+       "new",
 };
 
 char*
@@ -412,7 +274,8 @@ middlecache(Mailbox *mb, Message *m)
        }
        if(y == 0)
                return 0;
-       dprint("middlecache %d [%D] %lud %lud\n", m->id, m->fileid, (ulong)(m->end - m->start), m->size);
+       dprint("middlecache %lud [%D] %lud %lud\n",
+               m->id, m->fileid, (ulong)(m->end - m->start), m->size);
        return cachebody(mb, m);
 }
 
@@ -427,7 +290,7 @@ cacheheaders(Mailbox *mb, Message *m)
                return 0;
        if(!Topmsg(mb, m))
                return middlecache(mb, m);
-       dprint("cacheheaders %d %D\n", m->id, m->fileid);
+       dprint("cacheheaders %lud %D\n", m->id, m->fileid);
        if(m->size < 10000)
                r = fetch(mb, m, 0, m->size);
        else for(r = 0; (o = m->end - m->start) < m->size; ){
@@ -454,7 +317,7 @@ found:
 void
 digestmessage(Mailbox *mb, Message *m)
 {
-       assert(m->digest == 0);
+       assert(m->digest == nil);
        m->digest = emalloc(SHA1dlen);
        sha1((uchar*)m->start, m->end - m->start, m->digest, nil);
        if(mtreeisdup(mb, m)){
@@ -462,7 +325,7 @@ digestmessage(Mailbox *mb, Message *m)
                m->deleted = Dup;       /* no dups allowed */
        }else
                mtreeadd(mb, m);
-       dprint("%d %#A\n", m->id, m->digest);
+       dprint("%lud %#A\n", m->id, m->digest);
 }
 
 int
@@ -472,10 +335,10 @@ cachebody(Mailbox *mb, Message *m)
 
        while(!Topmsg(mb, m))
                m = m->whole;
-       if(!mb->fetch || m->cstate&Cbody)
+       if(mb->fetch == nil || m->cstate&Cbody)
                return 0;
        o = m->end - m->start;
-       dprint("cachebody %d [%D] %lud %lud %s", m->id, m->fileid, o, m->size, cstate(m));
+       dprint("cachebody %lud [%D] %lud %lud %s", m->id, m->fileid, o, m->size, cstate(m));
        if(o < m->size)
        if(fetch(mb, m, o, m->size - o) < 0)
                return -1;
@@ -486,7 +349,7 @@ cachebody(Mailbox *mb, Message *m)
                m->size -= m->badchars;         /* sneaky */
                m->ibadchars = m->badchars;
        }
-       if(m->digest == 0)
+       if(m->digest == nil)
                digestmessage(mb, m);
        if(m->lines == 0)
                m->lines = countlines(m);
@@ -500,7 +363,7 @@ cacheidx(Mailbox *mb, Message *m)
 {
        if(m->cstate & Cidx)
                return 0;
-       if(cachebody(mb, m) == -1)
+       if(cachebody(mb, m) < 0)
                return -1;
        m->cstate |= Cidxstale|Cidx;
        return 0;
@@ -522,16 +385,16 @@ countparts(Message *m)
 int
 insurecache(Mailbox *mb, Message *m)
 {
-       if(m->deleted || !m->inmbox)
+       if((m->deleted & ~Deleted) != 0 || !m->inmbox)
                return -1;
-       msgincref(m);
+       msgincref(mb, m);
        cacheidx(mb, m);
        if((m->cstate & Cidx) == 0){
                logmsg(m, "%s: can't cache: %s: %r", mb->path, m->name);
                msgdecref(mb, m);
                return -1;
        }
-       if(m->digest == 0)
+       if(m->digest == nil)
                sysfatal("digest?");
        countparts(m);
        return 0;