V9/jtools/src/sam/buffer.c

#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;
}