diff options
author | Russ Cox <rsc@swtch.com> | 2009-05-25 02:11:27 -0700 |
---|---|---|
committer | Russ Cox <rsc@swtch.com> | 2009-05-25 02:11:27 -0700 |
commit | 75d048884cfcb7cc4404b384da50923e22224365 (patch) | |
tree | b918a6a957b1f322ebb2f84c16092e103f91acda /src/libventi/cache.c | |
parent | 33b446b8bbfea80552d462296d27ad4114fbd3fb (diff) | |
download | plan9port-75d048884cfcb7cc4404b384da50923e22224365.tar.gz plan9port-75d048884cfcb7cc4404b384da50923e22224365.tar.bz2 plan9port-75d048884cfcb7cc4404b384da50923e22224365.zip |
venti: 32-bit extensions to data structures
Diffstat (limited to 'src/libventi/cache.c')
-rw-r--r-- | src/libventi/cache.c | 110 |
1 files changed, 78 insertions, 32 deletions
diff --git a/src/libventi/cache.c b/src/libventi/cache.c index 636a6ea7..030efb0a 100644 --- a/src/libventi/cache.c +++ b/src/libventi/cache.c @@ -32,7 +32,6 @@ struct VtCache { QLock lk; VtConn *z; - u32int blocksize; u32int now; /* ticks for usage time stamps */ VtBlock **hash; /* hash table for finding addresses */ int nhash; @@ -40,41 +39,45 @@ struct VtCache int nheap; VtBlock *block; /* all allocated blocks */ int nblock; - uchar *mem; /* memory for all blocks and data */ int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int); + VtBlock *dead; /* blocks we don't have memory for */ + ulong mem; + ulong maxmem; }; static void cachecheck(VtCache*); VtCache* -vtcachealloc(VtConn *z, int blocksize, ulong nblock) +vtcachealloc(VtConn *z, ulong maxmem) { - uchar *p; VtCache *c; int i; + int nblock; VtBlock *b; + ulong maxmem0; + maxmem0 = maxmem; c = vtmallocz(sizeof(VtCache)); - + nblock = maxmem/100/(sizeof(VtBlock)+2*sizeof(VtBlock*)); c->z = z; - c->blocksize = (blocksize + 127) & ~127; c->nblock = nblock; c->nhash = nblock; c->hash = vtmallocz(nblock*sizeof(VtBlock*)); c->heap = vtmallocz(nblock*sizeof(VtBlock*)); c->block = vtmallocz(nblock*sizeof(VtBlock)); - c->mem = vtmallocz(nblock*c->blocksize); c->write = vtwrite; + maxmem -= nblock*(sizeof(VtBlock) + 2*sizeof(VtBlock*)); + maxmem -= sizeof(VtCache); + if((long)maxmem < 0) + sysfatal("cache size far too small: %lud", maxmem0); + c->mem = maxmem; - p = c->mem; for(i=0; i<nblock; i++){ b = &c->block[i]; b->addr = NilBlock; b->c = c; - b->data = p; b->heap = i; c->heap[i] = b; - p += c->blocksize; } c->nheap = nblock; cachecheck(c); @@ -102,13 +105,14 @@ vtcachefree(VtCache *c) qlock(&c->lk); cachecheck(c); - for(i=0; i<c->nblock; i++) + for(i=0; i<c->nblock; i++) { assert(c->block[i].ref == 0); + vtfree(c->block[i].data); + } vtfree(c->hash); vtfree(c->heap); vtfree(c->block); - vtfree(c->mem); vtfree(c); } @@ -128,11 +132,10 @@ vtcachedump(VtCache *c) static void cachecheck(VtCache *c) { - u32int size, now; + u32int now; int i, k, refed; VtBlock *b; - size = c->blocksize; now = c->now; for(i = 0; i < c->nheap; i++){ @@ -151,8 +154,6 @@ cachecheck(VtCache *c) refed = 0; for(i = 0; i < c->nblock; i++){ b = &c->block[i]; - if(b->data != &c->mem[i * size]) - sysfatal("mis-blocked at %d", i); if(b->ref && b->heap == BadHeap) refed++; else if(b->addr != NilBlock) @@ -299,6 +300,57 @@ if(0)fprint(2, "droping %x:%V\n", b->addr, b->score); } /* + * evict blocks until there is enough memory for size bytes. + */ +static VtBlock* +vtcacheevict(VtCache *c, ulong size) +{ + VtBlock *b; + + /* + * If we were out of memory and put some blocks + * to the side but now we have memory, grab one. + */ + if(c->mem >= size && c->dead) { + b = c->dead; + c->dead = b->next; + b->next = nil; + goto alloc; + } + + /* + * Otherwise, evict until we have memory. + */ + for(;;) { + b = vtcachebumpblock(c); + if(c->mem+b->size >= size) + break; + /* + * chain b onto dead list + */ + free(b->data); + b->data = nil; + c->mem += b->size; + b->size = 0; + b->next = c->dead; + c->dead = b; + } + + /* + * Allocate memory for block. + */ +alloc: + if(size > b->size || size <= b->size/2) { + free(b->data); + c->mem += b->size; + c->mem -= size; + b->size = size; + b->data = vtmalloc(size); + } + return b; +} + +/* * fetch a local block from the memory cache. * if it's not there, load it, bumping some other Block. * if we're out of free blocks, we're screwed. @@ -332,16 +384,16 @@ vtcachelocal(VtCache *c, u32int addr, int type) } VtBlock* -vtcacheallocblock(VtCache *c, int type) +vtcacheallocblock(VtCache *c, int type, ulong size) { VtBlock *b; qlock(&c->lk); - b = vtcachebumpblock(c); + b = vtcacheevict(c, size); b->iostate = BioLocal; b->type = type; b->addr = (b - c->block)+1; - vtzeroextend(type, b->data, 0, c->blocksize); + vtzeroextend(type, b->data, 0, size); vtlocaltoglobal(b->addr, b->score); qunlock(&c->lk); @@ -356,7 +408,7 @@ vtcacheallocblock(VtCache *c, int type) * if it's not there, load it, bumping some other block. */ VtBlock* -vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type) +vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type, ulong size) { VtBlock *b; ulong h; @@ -409,7 +461,7 @@ vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type) /* * not found */ - b = vtcachebumpblock(c); + b = vtcacheevict(c, size); b->addr = NilBlock; b->type = type; memmove(b->score, score, VtScoreSize); @@ -435,7 +487,7 @@ vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type) qunlock(&c->lk); vtcachenread++; - n = vtread(c->z, score, type, b->data, c->blocksize); + n = vtread(c->z, score, type, b->data, size); if(n < 0){ if(chattyventi) fprint(2, "read %V: %r\n", score); @@ -445,7 +497,7 @@ vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type) vtblockput(b); return nil; } - vtzeroextend(type, b->data, n, c->blocksize); + vtzeroextend(type, b->data, n, size); b->iostate = BioVenti; b->nlock = 1; if(vttracelevel) @@ -534,7 +586,7 @@ vtblockwrite(VtBlock *b) } c = b->c; - n = vtzerotruncate(b->type, b->data, c->blocksize); + n = vtzerotruncate(b->type, b->data, b->size); vtcachenwrite++; if(c->write(c->z, score, b->type, b->data, n) < 0) return -1; @@ -554,24 +606,18 @@ vtblockwrite(VtBlock *b) return 0; } -uint -vtcacheblocksize(VtCache *c) -{ - return c->blocksize; -} - VtBlock* vtblockcopy(VtBlock *b) { VtBlock *bb; vtcachencopy++; - bb = vtcacheallocblock(b->c, b->type); + bb = vtcacheallocblock(b->c, b->type, b->size); if(bb == nil){ vtblockput(b); return nil; } - memmove(bb->data, b->data, b->c->blocksize); + memmove(bb->data, b->data, b->size); vtblockput(b); bb->pc = getcallerpc(&b); return bb; |