| #include "stdinc.h" |
| #include "dat.h" |
| #include "fns.h" |
| |
| int bootstrap = 0; |
| int syncwrites = 0; |
| int queuewrites = 0; |
| int writestodevnull = 0; |
| int verifywrites = 0; |
| |
| static Packet *readilump(Lump *u, IAddr *ia, u8int *score); |
| |
| /* |
| * Some of this logic is duplicated in hdisk.c |
| */ |
| Packet* |
| readlump(u8int *score, int type, u32int size, int *cached) |
| { |
| Lump *u; |
| Packet *p; |
| IAddr ia; |
| u32int n; |
| |
| trace(TraceLump, "readlump enter"); |
| /* |
| qlock(&stats.lock); |
| stats.lumpreads++; |
| qunlock(&stats.lock); |
| */ |
| if(scorecmp(score, zeroscore) == 0) |
| return packetalloc(); |
| u = lookuplump(score, type); |
| if(u->data != nil){ |
| trace(TraceLump, "readlump lookuplump hit"); |
| if(cached) |
| *cached = 1; |
| 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(cached) |
| *cached = 0; |
| |
| if(lookupscore(score, type, &ia) < 0){ |
| /* ZZZ place to check for someone trying to guess scores */ |
| seterr(EOk, "no block with score %V/%d exists", score, type); |
| |
| 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; |
| } |
| |
| trace(TraceLump, "readlump readilump"); |
| p = readilump(u, &ia, score); |
| putlump(u); |
| |
| trace(TraceLump, "readlump exit"); |
| 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, uint ms) |
| { |
| Lump *u; |
| int ok; |
| |
| /* |
| qlock(&stats.lock); |
| stats.lumpwrites++; |
| qunlock(&stats.lock); |
| */ |
| |
| packetsha1(p, score); |
| if(packetsize(p) == 0 || writestodevnull==1){ |
| packetfree(p); |
| return 0; |
| } |
| |
| u = lookuplump(score, type); |
| if(u->data != nil){ |
| ok = 0; |
| if(packetcmp(p, u->data) != 0){ |
| uchar nscore[VtScoreSize]; |
| |
| packetsha1(u->data, nscore); |
| if(scorecmp(u->score, score) != 0) |
| seterr(EStrange, "lookuplump returned bad score %V not %V", u->score, score); |
| else if(scorecmp(u->score, nscore) != 0) |
| seterr(EStrange, "lookuplump returned bad data %V not %V", nscore, u->score); |
| else |
| seterr(EStrange, "score collision %V", score); |
| ok = -1; |
| } |
| packetfree(p); |
| putlump(u); |
| return ok; |
| } |
| |
| if(writestodevnull==2){ |
| packetfree(p); |
| return 0; |
| } |
| |
| if(queuewrites) |
| return queuewrite(u, p, creator, ms); |
| |
| ok = writeqlump(u, p, creator, ms); |
| |
| putlump(u); |
| return ok; |
| } |
| |
| int |
| writeqlump(Lump *u, Packet *p, int creator, uint ms) |
| { |
| ZBlock *flat; |
| Packet *old; |
| IAddr ia; |
| int ok; |
| |
| if(lookupscore(u->score, u->type, &ia) == 0){ |
| if(verifywrites == 0){ |
| /* assume the data is here! */ |
| packetfree(p); |
| ms = msec() - ms; |
| addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms); |
| return 0; |
| } |
| |
| /* |
| * if the read fails, |
| * assume it was corrupted data and store the block again |
| */ |
| old = readilump(u, &ia, u->score); |
| if(old != nil){ |
| ok = 0; |
| if(packetcmp(p, old) != 0){ |
| uchar nscore[VtScoreSize]; |
| |
| packetsha1(old, nscore); |
| if(scorecmp(u->score, nscore) != 0) |
| seterr(EStrange, "readilump returned bad data %V not %V", nscore, u->score); |
| else |
| seterr(EStrange, "score collision %V", u->score); |
| ok = -1; |
| } |
| packetfree(p); |
| packetfree(old); |
| |
| ms = msec() - ms; |
| addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms); |
| 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) |
| insertlump(u, p); |
| else |
| packetfree(p); |
| |
| if(syncwrites){ |
| flushdcache(); |
| flushicache(); |
| flushdcache(); |
| } |
| |
| ms = msec() - ms; |
| addstat2(StatRpcWriteNew, 1, StatRpcWriteNewTime, ms); |
| return ok; |
| } |
| |
| static Packet* |
| readilump(Lump *u, IAddr *ia, u8int *score) |
| { |
| Arena *arena; |
| ZBlock *zb; |
| Packet *p, *pp; |
| Clump cl; |
| u64int aa; |
| u8int sc[VtScoreSize]; |
| |
| trace(TraceLump, "readilump enter"); |
| arena = amapitoa(mainindex, ia->addr, &aa); |
| if(arena == nil){ |
| trace(TraceLump, "readilump amapitoa failed"); |
| return nil; |
| } |
| |
| trace(TraceLump, "readilump loadclump"); |
| zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid); |
| if(zb == nil){ |
| trace(TraceLump, "readilump loadclump failed"); |
| 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; |
| } |
| |
| trace(TraceLump, "readilump success"); |
| p = zblock2packet(zb, cl.info.uncsize); |
| freezblock(zb); |
| pp = packetdup(p, 0, packetsize(p)); |
| trace(TraceLump, "readilump insertlump"); |
| insertlump(u, pp); |
| trace(TraceLump, "readilump exit"); |
| return p; |
| } |