summaryrefslogtreecommitdiffstats
path: root/src/cmd/vac/source.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-11-23 17:55:34 +0000
committerrsc <devnull@localhost>2003-11-23 17:55:34 +0000
commit7763a61a3582ef330bca54f225e8ec5325fbd35e (patch)
tree952957eef4d70ecbd30c58e3a0dacd6b3a753a54 /src/cmd/vac/source.c
parent7a4ee46d253e291044bba2d0c54b818b67ac013c (diff)
downloadplan9port-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.c390
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);
+}