aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/venti/clump.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2003-11-23 17:54:58 +0000
committerrsc <devnull@localhost>2003-11-23 17:54:58 +0000
commit7a4ee46d253e291044bba2d0c54b818b67ac013c (patch)
tree7bdcaf69a15ecd24c057a697936b67bbde93e00b /src/cmd/venti/clump.c
parent4fbfdd7acd4bf4fc71b1329230e05fc761907566 (diff)
downloadplan9port-7a4ee46d253e291044bba2d0c54b818b67ac013c.tar.gz
plan9port-7a4ee46d253e291044bba2d0c54b818b67ac013c.tar.bz2
plan9port-7a4ee46d253e291044bba2d0c54b818b67ac013c.zip
Initial stab at Venti.
Diffstat (limited to 'src/cmd/venti/clump.c')
-rw-r--r--src/cmd/venti/clump.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/cmd/venti/clump.c b/src/cmd/venti/clump.c
new file mode 100644
index 00000000..272d7aec
--- /dev/null
+++ b/src/cmd/venti/clump.c
@@ -0,0 +1,200 @@
+#include "stdinc.h"
+#include "dat.h"
+#include "fns.h"
+#include "whack.h"
+
+/*
+ * writes a lump to disk
+ * returns the address in amap of the clump
+ */
+int
+storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
+{
+ ZBlock *cb;
+ Clump cl;
+ u64int a;
+ u8int bh[VtScoreSize];
+ int size, dsize;
+
+if(0)print("storeclump %08x %p\n", mainindex->arenas[0], &cl);
+ size = zb->len;
+ if(size > VtMaxLumpSize){
+ seterr(EStrange, "lump too large");
+ return -1;
+ }
+ if(vttypevalid(type) < 0){
+ seterr(EStrange, "invalid lump type");
+ return -1;
+ }
+
+ if(1){
+ scoremem(bh, zb->data, size);
+ if(scorecmp(sc, bh) != 0){
+ seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
+ return -1;
+ }
+ }
+
+ cb = alloczblock(size + ClumpSize, 0);
+ if(cb == nil)
+ return -1;
+
+ cl.info.type = type;
+ cl.info.uncsize = size;
+ cl.creator = creator;
+ cl.time = now();
+ scorecp(cl.info.score, sc);
+
+if(0)print("whackblock %08x %p\n", mainindex->arenas[0], &cl);
+ dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
+if(0)print("whackedblock %08x %p\n", mainindex->arenas[0], &cl);
+ if(dsize > 0 && dsize < size){
+ cl.encoding = ClumpECompress;
+ }else{
+ cl.encoding = ClumpENone;
+ dsize = size;
+ memmove(&cb->data[ClumpSize], zb->data, size);
+ }
+ cl.info.size = dsize;
+
+ a = writeiclump(ix, &cl, cb->data);
+
+ freezblock(cb);
+ if(a == 0)
+ return -1;
+
+ qlock(&stats.lock);
+ stats.clumpwrites++;
+ stats.clumpbwrites += size;
+ stats.clumpbcomp += dsize;
+ qunlock(&stats.lock);
+
+ ia->addr = a;
+ ia->type = type;
+ ia->size = size;
+ ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
+
+ return 0;
+}
+
+u32int
+clumpmagic(Arena *arena, u64int aa)
+{
+ u8int buf[U32Size];
+
+ if(readarena(arena, aa, buf, U32Size) < 0)
+ return TWID32;
+ return unpackmagic(buf);
+}
+
+/*
+ * fetch a block based at addr.
+ * score is filled in with the block's score.
+ * blocks is roughly the length of the clump on disk;
+ * if zero, the length is unknown.
+ */
+ZBlock*
+loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
+{
+ Unwhack uw;
+ ZBlock *zb, *cb;
+ u8int bh[VtScoreSize], *buf;
+ u32int n;
+ int nunc;
+
+ qlock(&stats.lock);
+ stats.clumpreads++;
+ qunlock(&stats.lock);
+
+ if(blocks <= 0)
+ blocks = 1;
+
+ cb = alloczblock(blocks << ABlockLog, 0);
+ if(cb == nil)
+ return nil;
+ n = readarena(arena, aa, cb->data, blocks << ABlockLog);
+ if(n < ClumpSize){
+ if(n != 0)
+ seterr(ECorrupt, "loadclump read less than a header");
+ freezblock(cb);
+ return nil;
+ }
+ if(unpackclump(cl, cb->data) < 0){
+ freezblock(cb);
+ return nil;
+ }
+ n -= ClumpSize;
+ if(n < cl->info.size){
+ freezblock(cb);
+ n = cl->info.size;
+ cb = alloczblock(n, 0);
+ if(cb == nil)
+ return nil;
+ if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
+ seterr(ECorrupt, "loadclump read too little data");
+ freezblock(cb);
+ return nil;
+ }
+ buf = cb->data;
+ }else
+ buf = cb->data + ClumpSize;
+
+ scorecp(score, cl->info.score);
+
+ zb = alloczblock(cl->info.uncsize, 0);
+ if(zb == nil){
+ freezblock(cb);
+ return nil;
+ }
+ switch(cl->encoding){
+ case ClumpECompress:
+ unwhackinit(&uw);
+ nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
+ if(nunc != cl->info.uncsize){
+ if(nunc < 0)
+ seterr(ECorrupt, "decompression failed: %s", uw.err);
+ else
+ seterr(ECorrupt, "decompression gave partial block: %d/%d\n", nunc, cl->info.uncsize);
+ freezblock(cb);
+ freezblock(zb);
+ return nil;
+ }
+ break;
+ case ClumpENone:
+ if(cl->info.size != cl->info.uncsize){
+ seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block");
+ freezblock(cb);
+ freezblock(zb);
+ return nil;
+ }
+ memmove(zb->data, buf, cl->info.uncsize);
+ break;
+ default:
+ seterr(ECorrupt, "unknown encoding in loadlump");
+ freezblock(cb);
+ freezblock(zb);
+ return nil;
+ }
+ freezblock(cb);
+
+ if(verify){
+ scoremem(bh, zb->data, cl->info.uncsize);
+ if(scorecmp(cl->info.score, bh) != 0){
+ seterr(ECorrupt, "loading clump: corrupted; expected=%V got=%V", cl->info.score, bh);
+ freezblock(zb);
+ return nil;
+ }
+ if(vttypevalid(cl->info.type) < 0){
+ seterr(ECorrupt, "loading lump: invalid lump type %d", cl->info.type);
+ freezblock(zb);
+ return nil;
+ }
+ }
+
+ qlock(&stats.lock);
+ stats.clumpbreads += cl->info.size;
+ stats.clumpbuncomp += cl->info.uncsize;
+ qunlock(&stats.lock);
+
+ return zb;
+}