diff options
Diffstat (limited to 'src/cmd/venti/lump.c')
-rw-r--r-- | src/cmd/venti/lump.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/cmd/venti/lump.c b/src/cmd/venti/lump.c new file mode 100644 index 00000000..c449f022 --- /dev/null +++ b/src/cmd/venti/lump.c @@ -0,0 +1,206 @@ +#include "stdinc.h" +#include "dat.h" +#include "fns.h" + +int queuewrites = 0; + +static Packet *readilump(Lump *u, IAddr *ia, u8int *score, int rac); + +Packet* +readlump(u8int *score, int type, u32int size) +{ + Lump *u; + Packet *p; + IAddr ia; + u32int n; + int rac; + + qlock(&stats.lock); + stats.lumpreads++; + qunlock(&stats.lock); + u = lookuplump(score, type); + if(u->data != nil){ + n = packetsize(u->data); + if(n > size){ + seterr(EOk, "read too small: asked for %d need at least %d", size, n); + putlump(u); + + return nil; + } + p = packetdup(u->data, 0, n); + putlump(u); + + return p; + } + + if(lookupscore(score, type, &ia, &rac) < 0){ + //ZZZ place to check for someone trying to guess scores + seterr(EOk, "no block with that score exists"); + + putlump(u); + return nil; + } + if(ia.size > size){ + seterr(EOk, "read too small 1: asked for %d need at least %d", size, ia.size); + + putlump(u); + return nil; + } + + p = readilump(u, &ia, score, rac); + putlump(u); + + return p; +} + +/* + * save away a lump, and return it's score. + * doesn't store duplicates, but checks that the data is really the same. + */ +int +writelump(Packet *p, u8int *score, int type, u32int creator) +{ + Lump *u; + int ok; + + qlock(&stats.lock); + stats.lumpwrites++; + qunlock(&stats.lock); + + packetsha1(p, score); + + u = lookuplump(score, type); + if(u->data != nil){ + ok = 0; + if(packetcmp(p, u->data) != 0){ + seterr(EStrange, "score collision"); + ok = -1; + } + packetfree(p); + putlump(u); + return ok; + } + +print("writelump %08x\n", mainindex->arenas[0]); + if(queuewrites) + return queuewrite(u, p, creator); + + ok = writeqlump(u, p, creator); + + putlump(u); + return ok; +} + +int +writeqlump(Lump *u, Packet *p, int creator) +{ + ZBlock *flat; + Packet *old; + IAddr ia; + int ok; + int rac; + + if(lookupscore(u->score, u->type, &ia, &rac) == 0){ + /* + * if the read fails, + * assume it was corrupted data and store the block again + */ + old = readilump(u, &ia, u->score, rac); + if(old != nil){ + ok = 0; + if(packetcmp(p, old) != 0){ + seterr(EStrange, "score collision"); + ok = -1; + } + packetfree(p); + packetfree(old); + + return ok; + } + logerr(EAdmin, "writelump: read %V failed, rewriting: %r\n", u->score); + } + + flat = packet2zblock(p, packetsize(p)); + ok = storeclump(mainindex, flat, u->score, u->type, creator, &ia); + freezblock(flat); + if(ok == 0) + ok = insertscore(u->score, &ia, 1); + if(ok == 0) + insertlump(u, p); + else + packetfree(p); + + return ok; +} + +static void +readahead(u64int a, Arena *arena, u64int aa, int n) +{ + u8int buf[ClumpSize]; + Clump cl; + IAddr ia; + + while(n > 0) { + if (aa >= arena->used) + break; + if(readarena(arena, aa, buf, ClumpSize) < ClumpSize) + break; + if(unpackclump(&cl, buf) < 0) + break; + ia.addr = a; + ia.type = cl.info.type; + ia.size = cl.info.uncsize; + ia.blocks = (cl.info.size + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog; + insertscore(cl.info.score, &ia, 0); + a += ClumpSize + cl.info.size; + aa += ClumpSize + cl.info.size; + n--; + } +} + +static Packet* +readilump(Lump *u, IAddr *ia, u8int *score, int rac) +{ + Arena *arena; + ZBlock *zb; + Packet *p, *pp; + Clump cl; + u64int a, aa; + u8int sc[VtScoreSize]; + + arena = amapitoa(mainindex, ia->addr, &aa); + if(arena == nil) + return nil; + + zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid); + if(zb == nil) + return nil; + + if(ia->size != cl.info.uncsize){ + seterr(EInconsist, "index and clump size mismatch"); + freezblock(zb); + return nil; + } + if(ia->type != cl.info.type){ + seterr(EInconsist, "index and clump type mismatch"); + freezblock(zb); + return nil; + } + if(scorecmp(score, sc) != 0){ + seterr(ECrash, "score mismatch"); + freezblock(zb); + return nil; + } + + if(rac == 0) { + a = ia->addr + ClumpSize + cl.info.size; + aa += ClumpSize + cl.info.size; + readahead(a, arena, aa, 20); + } + + p = zblock2packet(zb, cl.info.uncsize); + freezblock(zb); + pp = packetdup(p, 0, packetsize(p)); + insertlump(u, pp); + return p; +} |