#include "sam.h" static flush(); static setcache(); Buffer * Bopen(dd) Discdesc *dd; { register Buffer *b; b=new(Buffer, 1); b->disc=Dopen(dd); strinit(&b->cache); return b; } Bclose(b) register Buffer *b; { Dclose(b->disc); strclose(&b->cache); free((uchar *)b); } int Bread(b, addr, n, p0) register Buffer *b; uchar *addr; int n; Posn p0; { register m; if(b->c2>b->disc->nbytes || b->c1>b->disc->nbytes) panic("bread cache"); if(p0<0) panic("Bread p0<0"); if(p0+n>b->nbytes){ n=b->nbytes-p0; if(n<0) panic("Bread<0"); } if(!incache(b, p0, p0+n)){ flush(b); if(n>=BLOCKSIZE/2) return Dread(b->disc, addr, n, p0); else{ Posn minp; if(b->nbytes-p0>BLOCKSIZE/2) m=BLOCKSIZE/2; else m=b->nbytes-p0; if(m<n) m=n; minp=p0-BLOCKSIZE/2; if(minp<0) minp=0; m+=p0-minp; strinsure(&b->cache, (ulong)m); if(Dread(b->disc, b->cache.s, m, minp)!=m) panic("Bread"); b->cache.n=m; b->c1=minp; b->c2=minp+m; b->dirty=FALSE; } } bcopy(&b->cache.s[p0-b->c1], &b->cache.s[p0-b->c1+n], addr, 1); return n; } Binsert(b, s, p0) register Buffer *b; String *s; Posn p0; { if(b->c2>b->disc->nbytes || b->c1>b->disc->nbytes) panic("binsert cache"); if(p0<0) panic("Binsert p0<0"); if(s->n==0) return; if(incache(b, p0, p0)){ strinsert(&b->cache, s, p0-b->c1); b->dirty=TRUE; if(b->cache.n>BLOCKSIZE){ b->nbytes+=s->n; flush(b); b->cache.n-=BLOCKSIZE; b->c2=b->c1+b->cache.n; return; } }else{ flush(b); if(s->n>=BLOCKSIZE/2){ b->cache.n=0; b->c1=b->c2=0; Dinsert(b->disc, s->s, s->n, p0); }else{ register m; Posn minp; if(b->nbytes-p0>BLOCKSIZE/2) m=BLOCKSIZE/2; else m=b->nbytes-p0; minp=p0-BLOCKSIZE/2; if(minp<0) minp=0; m+=p0-minp; strinsure(&b->cache, (ulong)m); if(Dread(b->disc, b->cache.s, m, minp)!=m) panic("Bread"); b->cache.n=m; b->c1=minp; b->c2=minp+m; strinsert(&b->cache, s, p0-b->c1); b->dirty=TRUE; } } b->nbytes+=s->n; } Bdelete(b, p1, p2) register Buffer *b; Posn p1, p2; { if(p1<0 || p2<0) panic("Bdelete p<0"); if(b->c2>b->disc->nbytes || b->c1>b->disc->nbytes) panic("bdelete cache"); if(p1==p2) return; if(incache(b, p1, p2)){ strdelete(&b->cache, p1-b->c1, p2-b->c1); b->dirty=TRUE; }else{ flush(b); Ddelete(b->disc, p1, p2); b->cache.n=0; b->c1=b->c2=0; } b->nbytes-=(p2-p1); } static flush(b) register Buffer *b; { if(b->dirty){ Dreplace(b->disc, b->c1, b->c2, b->cache.s, b->cache.n); b->c2=b->c1+b->cache.n; b->dirty=FALSE; if(b->nbytes!=b->disc->nbytes) panic("flush"); } } int hits, misses; incache(b, p1, p2) Buffer *b; Posn p1, p2; { if(b->c1<=p1 && p2<=b->c1+b->cache.n)hits++; else misses++; return b->c1<=p1 && p2<=b->c1+b->cache.n; } static setcache(b, s, p0) register Buffer *b; String *s; Posn p0; { strdelete(&b->cache, (long)0, (long)b->cache.n); strinsert(&b->cache, s, (long)0); b->c1=p0; b->c2=p0+s->n; b->dirty=FALSE; }