123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- #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, "%s: bad flags %#ux %V\n", argv0, 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, "%s: depth == 0! size = %ulld\n", argv0, 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, "%s: sourceOpen: %V:%d: %lud\n", argv0, 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, "%s: sourceGetLump: %V:%d %lud\n", argv0, 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);
- }
|