#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
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;
free(m->references[i]);
m->references[i] = 0;
}
- sz = m->csize;
m->csize = 0;
m->start = 0;
m->end = 0;
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
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);
"idx",
"stale",
"header",
- "body"
+ "body",
+ "new",
};
char*
}
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);
}
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; ){
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)){
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
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;
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);
{
if(m->cstate & Cidx)
return 0;
- if(cachebody(mb, m) == -1)
+ if(cachebody(mb, m) < 0)
return -1;
m->cstate |= Cidxstale|Cidx;
return 0;
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;