diff options
| author | rsc <devnull@localhost> | 2003-11-23 17:55:34 +0000 |
|---|---|---|
| committer | rsc <devnull@localhost> | 2003-11-23 17:55:34 +0000 |
| commit | 7763a61a3582ef330bca54f225e8ec5325fbd35e (patch) | |
| tree | 952957eef4d70ecbd30c58e3a0dacd6b3a753a54 /src/cmd/vac/source.c | |
| parent | 7a4ee46d253e291044bba2d0c54b818b67ac013c (diff) | |
| download | plan9port-7763a61a3582ef330bca54f225e8ec5325fbd35e.tar.gz plan9port-7763a61a3582ef330bca54f225e8ec5325fbd35e.zip | |
start thinking about vac -- doesn't build yet
Diffstat (limited to 'src/cmd/vac/source.c')
| -rw-r--r-- | src/cmd/vac/source.c | 390 |
1 files changed, 390 insertions, 0 deletions
diff --git a/src/cmd/vac/source.c b/src/cmd/vac/source.c new file mode 100644 index 00000000..e7245a2f --- /dev/null +++ b/src/cmd/vac/source.c @@ -0,0 +1,390 @@ +#include "stdinc.h" +#include "vac.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +static int sizeToDepth(uvlong s, int psize, int dsize); + +static int +sizeToDepth(uvlong s, int psize, int dsize) +{ + int np; + int d; + + /* determine pointer depth */ + np = psize/VtScoreSize; + s = (s + dsize - 1)/dsize; + for(d = 0; s > 1; d++) + s = (s + np - 1)/np; + return d; +} + +/* assumes u is lock? */ +Source * +sourceAlloc(Cache *c, Lump *u, ulong block, int entry, int readOnly) +{ + Source *r; + VtEntry d; + + if(u->asize < (entry+1)*VtEntrySize) { + vtSetError(ENoDir); + return nil; + } + + if(!vtEntryUnpack(&d, u->data, entry)) + return nil; + + if(!(d.flags & VtEntryActive)) { +fprint(2, "bad flags %#ux %V\n", d.flags, d.score); + vtSetError(ENoDir); + return nil; + } + + /* HACK for backwards compatiblity - should go away at some point */ + if(d.depth == 0) { +if(d.size > d.dsize) fprint(2, "depth == 0! size = %ulld\n", d.size); + d.depth = sizeToDepth(d.size, d.psize, d.dsize); + } + + if(d.depth < sizeToDepth(d.size, d.psize, d.dsize)) { + vtSetError(EBadDir); + return nil; + } + + r = vtMemAllocZ(sizeof(Source)); + r->lk = vtLockAlloc(); + r->cache = c; + r->readOnly = readOnly; + r->lump = lumpIncRef(u); + r->block = block; + r->entry = entry; + r->gen = d.gen; + r->dir = (d.flags & VtEntryDir) != 0; + r->depth = d.depth; + r->psize = d.psize; + r->dsize = d.dsize; + r->size = d.size; + + r->epb = r->dsize/VtEntrySize; + + return r; +} + +Source * +sourceOpen(Source *r, ulong entry, int readOnly) +{ + ulong bn; + Lump *u; + +if(0)fprint(2, "sourceOpen: %V:%d: %lud\n", r->lump->score, r->entry, entry); + if(r->readOnly && !readOnly) { + vtSetError(EReadOnly); + return nil; + } + + bn = entry/r->epb; + + u = sourceGetLump(r, bn, readOnly, 1); + if(u == nil) + return nil; + + r = sourceAlloc(r->cache, u, bn, entry%r->epb, readOnly); + lumpDecRef(u, 1); + return r; +} + +Source * +sourceCreate(Source *r, int psize, int dsize, int isdir, ulong entry) +{ + Source *rr; + int i; + Lump *u; + ulong bn; + VtEntry dir; + + if(r->readOnly) { + vtSetError(EReadOnly); + return nil; + } + + if(entry == 0) { + /* + * look at a random block to see if we can find an empty entry + */ + entry = sourceGetDirSize(r); + entry = r->epb*lnrand(entry/r->epb+1); + } + + /* + * need to loop since multiple threads could be trying to allocate + */ + for(;;) { + bn = entry/r->epb; + sourceSetDepth(r, (uvlong)(bn+1)*r->dsize); + u = sourceGetLump(r, bn, 0, 1); + if(u == nil) + return nil; + for(i=entry%r->epb; i<r->epb; i++) { + vtEntryUnpack(&dir, u->data, i); + if((dir.flags&VtEntryActive) == 0 && dir.gen != ~0) + goto Found; + } + lumpDecRef(u, 1); + entry = sourceGetDirSize(r); + } +Found: + /* found an entry */ + dir.psize = psize; + dir.dsize = dsize; + dir.flags = VtEntryActive; + if(isdir) + dir.flags |= VtEntryDir; + dir.depth = 0; + dir.size = 0; + memmove(dir.score, vtZeroScore, VtScoreSize); + vtEntryPack(&dir, u->data, i); + + sourceSetDirSize(r, bn*r->epb + i + 1); + rr = sourceAlloc(r->cache, u, bn, i, 0); + + lumpDecRef(u, 1); + return rr; +} + +void +sourceRemove(Source *r) +{ + lumpFreeEntry(r->lump, r->entry); + sourceFree(r); +} + +int +sourceSetDepth(Source *r, uvlong size) +{ + Lump *u, *v; + VtEntry dir; + int depth; + + if(r->readOnly){ + vtSetError(EReadOnly); + return 0; + } + + depth = sizeToDepth(size, r->psize, r->dsize); + + assert(depth >= 0); + + if(depth > VtPointerDepth) { + vtSetError(ETooBig); + return 0; + } + + vtLock(r->lk); + + if(r->depth >= depth) { + vtUnlock(r->lk); + return 1; + } + + u = r->lump; + vtLock(u->lk); + if(!vtEntryUnpack(&dir, u->data, r->entry)) { + vtUnlock(u->lk); + vtUnlock(r->lk); + return 0; + } + while(dir.depth < depth) { + v = cacheAllocLump(r->cache, VtPointerType0+r->depth, r->psize, r->dir); + if(v == nil) + break; + memmove(v->data, dir.score, VtScoreSize); + memmove(dir.score, v->score, VtScoreSize); + dir.depth++; + vtUnlock(v->lk); + } + vtEntryPack(&dir, u->data, r->entry); + vtUnlock(u->lk); + + r->depth = dir.depth; + vtUnlock(r->lk); + + return dir.depth == depth; +} + +int +sourceGetVtEntry(Source *r, VtEntry *dir) +{ + Lump *u; + + u = r->lump; + vtLock(u->lk); + if(!vtEntryUnpack(dir, u->data, r->entry)) { + vtUnlock(u->lk); + return 0; + } + vtUnlock(u->lk); + return 1; +} + +uvlong +sourceGetSize(Source *r) +{ + uvlong size; + + vtLock(r->lk); + size = r->size; + vtUnlock(r->lk); + + return size; +} + + +int +sourceSetSize(Source *r, uvlong size) +{ + Lump *u; + VtEntry dir; + int depth; + + if(r->readOnly) { + vtSetError(EReadOnly); + return 0; + } + + if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize) { + vtSetError(ETooBig); + return 0; + } + + vtLock(r->lk); + depth = sizeToDepth(size, r->psize, r->dsize); + if(size < r->size) { + vtUnlock(r->lk); + return 1; + } + if(depth > r->depth) { + vtSetError(EBadDir); + vtUnlock(r->lk); + return 0; + } + + u = r->lump; + vtLock(u->lk); + vtEntryUnpack(&dir, u->data, r->entry); + dir.size = size; + vtEntryPack(&dir, u->data, r->entry); + vtUnlock(u->lk); + r->size = size; + vtUnlock(r->lk); + return 1; +} + +int +sourceSetDirSize(Source *r, ulong ds) +{ + uvlong size; + + size = (uvlong)r->dsize*(ds/r->epb); + size += VtEntrySize*(ds%r->epb); + return sourceSetSize(r, size); +} + +ulong +sourceGetDirSize(Source *r) +{ + ulong ds; + uvlong size; + + size = sourceGetSize(r); + ds = r->epb*(size/r->dsize); + ds += (size%r->dsize)/VtEntrySize; + return ds; +} + +ulong +sourceGetNumBlocks(Source *r) +{ + return (sourceGetSize(r)+r->dsize-1)/r->dsize; +} + +Lump * +sourceWalk(Source *r, ulong block, int readOnly, int *off) +{ + int depth; + int i, np; + Lump *u, *v; + int elem[VtPointerDepth+1]; + ulong b; + + if(r->readOnly && !readOnly) { + vtSetError(EReadOnly); + return nil; + } + + vtLock(r->lk); + np = r->psize/VtScoreSize; + b = block; + for(i=0; i<r->depth; i++) { + elem[i] = b % np; + b /= np; + } + if(b != 0) { + vtUnlock(r->lk); + vtSetError(EBadOffset); + return nil; + } + elem[i] = r->entry; + u = lumpIncRef(r->lump); + depth = r->depth; + *off = elem[0]; + vtUnlock(r->lk); + + for(i=depth; i>0; i--) { + v = lumpWalk(u, elem[i], VtPointerType0+i-1, r->psize, readOnly, 0); + lumpDecRef(u, 0); + if(v == nil) + return nil; + u = v; + } + + return u; +} + +Lump * +sourceGetLump(Source *r, ulong block, int readOnly, int lock) +{ + int type, off; + Lump *u, *v; + + if(r->readOnly && !readOnly) { + vtSetError(EReadOnly); + return nil; + } + if(block == NilBlock) { + vtSetError(ENilBlock); + return nil; + } +if(0)fprint(2, "sourceGetLump: %V:%d %lud\n", r->lump->score, r->entry, block); + u = sourceWalk(r, block, readOnly, &off); + if(u == nil) + return nil; + if(r->dir) + type = VtDirType; + else + type = VtDataType; + v = lumpWalk(u, off, type, r->dsize, readOnly, lock); + lumpDecRef(u, 0); + return v; +} + +void +sourceFree(Source *k) +{ + if(k == nil) + return; + lumpDecRef(k->lump, 0); + vtLockFree(k->lk); + memset(k, ~0, sizeof(*k)); + vtMemFree(k); +} |
