/* * 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; }
/* * make an Arena, and initialize it based upon the disk header and trailer. */ Arena* initarena(Part *part, uint64_t base, uint64_t size, uint32_t blocksize) { Arena *arena; arena = MKZ(Arena); arena->part = part; arena->blocksize = blocksize; arena->clumpmax = arena->blocksize / ClumpInfoSize; arena->base = base + blocksize; arena->size = size - 2 * blocksize; if(loadarena(arena) < 0){ seterr(ECorrupt, "arena header or trailer corrupted"); freearena(arena); return nil; } if(okarena(arena) < 0){ freearena(arena); return nil; } if(arena->diskstats.sealed && scorecmp(zeroscore, arena->score)==0) sealarena(arena); return arena; }
void xmlscore(Hio *hout, u8int *v, char *tag) { if(scorecmp(zeroscore, v) == 0) return; hprint(hout, " %s=\"%V\"", tag, v); }
static vlong findintoc(HConnect *c, Arena *arena, uchar *score) { uchar *blk; int i; vlong off; vlong coff; ClumpInfo ci; blk = vtmalloc(arena->blocksize); off = arena->base + arena->size; coff = 0; for(i=0; i<arena->memstats.clumps; i++){ if(i%arena->clumpmax == 0){ off -= arena->blocksize; if(readpart(arena->part, off, blk, arena->blocksize) != arena->blocksize){ if(c) hprint(&c->hout, "<i>clump info directory at %#llx: %r</i>\n<br>\n", off); break; } } unpackclumpinfo(&ci, blk+(i%arena->clumpmax)*ClumpInfoSize); if(scorecmp(ci.score, score) == 0){ vtfree(blk); return coff; } coff += ClumpSize + ci.size; } vtfree(blk); return -1; }
static void darena(Hio *hout, Arena *arena) { hprint(hout, "arena='%s' on %s at [%lld,%lld)\n\tversion=%d created=%d modified=%d", arena->name, arena->part->name, arena->base, arena->base + arena->size + 2 * arena->blocksize, arena->version, arena->ctime, arena->wtime); if(arena->memstats.sealed) hprint(hout, " mem=sealed"); if(arena->diskstats.sealed) hprint(hout, " disk=sealed"); if(arena->inqueue) hprint(hout, " inqueue"); hprint(hout, "\n"); if(scorecmp(zeroscore, arena->score) != 0) hprint(hout, "\tscore=%V\n", arena->score); hprint(hout, "\twritten: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n", arena->memstats.clumps, arena->memstats.cclumps, arena->memstats.uncsize, arena->memstats.used - arena->memstats.clumps * ClumpSize, arena->memstats.used + arena->memstats.clumps * ClumpInfoSize); hprint(hout, "\tindexed: clumps=%d compressed clumps=%d data=%,lld compressed data=%,lld storage=%,lld\n", arena->diskstats.clumps, arena->diskstats.cclumps, arena->diskstats.uncsize, arena->diskstats.used - arena->diskstats.clumps * ClumpSize, arena->diskstats.used + arena->diskstats.clumps * ClumpInfoSize); }
int clumpinfoeq(ClumpInfo *c, ClumpInfo *d) { return c->type == d->type && c->size == d->size && c->uncsize == d->uncsize && scorecmp(c->score, d->score)==0; }
/* * 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; }
static IEntry* ihashlookup(IHash *ih, u8int score[VtScoreSize], int type) { u32int h; IEntry *ie; h = hashbits(score, ih->bits); for(ie=ih->table[h]; ie; ie=ie->nexthash) if((type == -1 || type == ie->ia.type) && scorecmp(score, ie->score) == 0) return ie; return nil; }
static IEntry* iesort(IEntry *ie) { int cmp; IEntry **l; IEntry *ie1, *ie2, *sorted; if(ie == nil || ie->nextdirty == nil) return ie; /* split the lists */ ie1 = ie; ie2 = ie; if(ie2) ie2 = ie2->nextdirty; if(ie2) ie2 = ie2->nextdirty; while(ie1 && ie2){ ie1 = ie1->nextdirty; ie2 = ie2->nextdirty; if(ie2) ie2 = ie2->nextdirty; } if(ie1){ ie2 = ie1->nextdirty; ie1->nextdirty = nil; } /* sort the lists */ ie1 = iesort(ie); ie2 = iesort(ie2); /* merge the lists */ sorted = nil; l = &sorted; cmp = 0; while(ie1 || ie2){ if(ie1 && ie2) cmp = scorecmp(ie1->score, ie2->score); if(ie1==nil || (ie2 && cmp > 0)){ *l = ie2; l = &ie2->nextdirty; ie2 = ie2->nextdirty; }else{ *l = ie1; l = &ie1->nextdirty; ie1 = ie1->nextdirty; } } *l = nil; return sorted; }
struct map *findscore(u8int *score) { int ix; ix = hashbits(score, hashb); //fprint(2, "find for %V is %d, maps[].data %p\n", score, ix, maps[ix].data); while (maps[ix].data) { //fprint(2, "Check: %d, %V\n", ix, maps[ix].score); //fprint(2, "scorecmp(%V,%V, %d\n", maps[ix].score, score,scorecmp(maps[ix].score, score) ); if (scorecmp(maps[ix].score, score) == 0) return &maps[ix]; ix++; } return nil; }
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; }
int findscore(Arena *arena, uchar *score) { IEntry ie; ClumpInfo *ci, *cis; u64int a; u32int clump; int i, n, found; //ZZZ remove fprint? if(arena->memstats.clumps) fprint(2, "reading directory for arena=%s with %d entries\n", arena->name, arena->memstats.clumps); cis = MKN(ClumpInfo, ClumpChunks); found = 0; a = 0; memset(&ie, 0, sizeof(IEntry)); for(clump = 0; clump < arena->memstats.clumps; clump += n){ n = ClumpChunks; if(n > arena->memstats.clumps - clump) n = arena->memstats.clumps - clump; if(readclumpinfos(arena, clump, cis, n) != n){ seterr(EOk, "arena directory read failed: %r"); break; } for(i = 0; i < n; i++){ ci = &cis[i]; if(scorecmp(score, ci->score)==0){ fprint(2, "found at clump=%d with type=%d size=%d csize=%d position=%lld\n", clump + i, ci->type, ci->uncsize, ci->size, a); found++; } a += ci->size + ClumpSize; } } free(cis); return found; }
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 int diskarenaclump(HConnect *c, Arena *arena, vlong off, char *scorestr) { uchar *blk, *blk2; Clump cl; char err[ERRMAX]; uchar xscore[VtScoreSize], score[VtScoreSize]; Unwhack uw; int n; if(scorestr){ if(vtparsescore(scorestr, nil, score) < 0){ hprint(&c->hout, "bad score %s: %r\n", scorestr); return -1; } if(off < 0){ off = findintoc(c, arena, score); if(off < 0){ hprint(&c->hout, "score %V not found in arena %s\n", score, arena->name); return -1; } hprint(&c->hout, "score %V at %#llx\n", score, off); } }else memset(score, 0, sizeof score); if(off < 0){ hprint(&c->hout, "bad offset %#llx\n", off); return -1; } off += arena->base; blk = vtmalloc(ClumpSize + VtMaxLumpSize); if(readpart(arena->part, off, blk, ClumpSize + VtMaxLumpSize) != ClumpSize + VtMaxLumpSize){ hprint(&c->hout, "reading at %#llx: %r\n", off); vtfree(blk); return -1; } if(unpackclump(&cl, blk, arena->clumpmagic) < 0){ hprint(&c->hout, "unpackclump: %r\n<br>"); rerrstr(err, sizeof err); if(strstr(err, "magic")){ hprint(&c->hout, "trying again with magic=%#ux<br>\n", U32GET(blk)); if(unpackclump(&cl, blk, U32GET(blk)) < 0){ hprint(&c->hout, "unpackclump: %r\n<br>\n"); goto error; } }else goto error; } hprint(&c->hout, "<pre>type=%d size=%d uncsize=%d score=%V\n", cl.info.type, cl.info.size, cl.info.uncsize, cl.info.score); hprint(&c->hout, "encoding=%d creator=%d time=%d %s</pre>\n", cl.encoding, cl.creator, cl.time, fmttime(err, cl.time)); if(cl.info.type == VtCorruptType) hprint(&c->hout, "clump is marked corrupt<br>\n"); if(cl.info.size >= VtMaxLumpSize){ hprint(&c->hout, "clump too big\n"); goto error; } switch(cl.encoding){ case ClumpECompress: blk2 = vtmalloc(VtMaxLumpSize); unwhackinit(&uw); n = unwhack(&uw, blk2, cl.info.uncsize, blk+ClumpSize, cl.info.size); if(n < 0){ hprint(&c->hout, "decompression failed\n"); vtfree(blk2); goto error; } if(n != cl.info.uncsize){ hprint(&c->hout, "got wrong amount: %d wanted %d\n", n, cl.info.uncsize); // hhex(blk2, n); vtfree(blk2); goto error; } scoremem(xscore, blk2, cl.info.uncsize); vtfree(blk2); break; case ClumpENone: scoremem(xscore, blk+ClumpSize, cl.info.size); break; } hprint(&c->hout, "score=%V<br>\n", xscore); if(scorestr && scorecmp(score, xscore) != 0) hprint(&c->hout, "score does NOT match expected %V\n", score); vtfree(blk); return 0; error: // hhex(blk, ClumpSize + VtMaxLumpSize); vtfree(blk); return -1; }
void sumarena(Arena *arena) { ZBlock *b; DigestState s; uint64_t a, e; uint32_t bs; int t; uint8_t score[VtScoreSize]; bs = MaxIoSize; if(bs < arena->blocksize) bs = arena->blocksize; /* * read & sum all blocks except the last one */ flushdcache(); memset(&s, 0, sizeof s); b = alloczblock(bs, 0, arena->part->blocksize); e = arena->base + arena->size; for(a = arena->base - arena->blocksize; a + arena->blocksize <= e; a += bs){ disksched(); while((t=arenasumsleeptime) == SleepForever){ sleep(1000); disksched(); } sleep(t); if(a + bs > e) bs = arena->blocksize; if(readpart(arena->part, a, b->data, bs) < 0) goto ReadErr; addstat(StatSumRead, 1); addstat(StatSumReadBytes, bs); sha1(b->data, bs, nil, &s); } /* * the last one is special, since it may already have the checksum included */ bs = arena->blocksize; if(readpart(arena->part, e, b->data, bs) < 0){ ReadErr: logerr(EOk, "sumarena can't sum %s, read at %lld failed: %r", arena->name, a); freezblock(b); return; } addstat(StatSumRead, 1); addstat(StatSumReadBytes, bs); sha1(b->data, bs-VtScoreSize, nil, &s); sha1(zeroscore, VtScoreSize, nil, &s); sha1(nil, 0, score, &s); /* * check for no checksum or the same */ if(scorecmp(score, &b->data[bs - VtScoreSize]) != 0 && scorecmp(zeroscore, &b->data[bs - VtScoreSize]) != 0) logerr(EOk, "overwriting mismatched checksums for arena=%s, found=%V calculated=%V", arena->name, &b->data[bs - VtScoreSize], score); freezblock(b); qlock(&arena->lock); scorecp(arena->score, score); wbarena(arena); qunlock(&arena->lock); }
static void rdarena(Arena *arena, u64int offset) { int i; u64int a, aa, e; uchar score[VtScoreSize]; Clump cl; ClumpInfo ci; ZBlock *lump; ZClump zcl; fprint(2, "wrarena: copying %s to venti\n", arena->name); printarena(2, arena); a = arena->base; e = arena->base + arena->size; if(offset != ~(u64int)0) { if(offset >= e - a) sysfatal("bad offset %#llx >= %#llx", offset, e - a); aa = offset; } else aa = 0; i = 0; for(a = 0; maxwrites != 0 && i < arena->memstats.clumps; a += ClumpSize + ci.size){ if(readclumpinfo(arena, i++, &ci) < 0) break; if(a < aa || ci.type == VtCorruptType){ if(ci.type == VtCorruptType) fprint(2, "%s: corrupt clump read at %#llx: +%d\n", argv0, a, ClumpSize+ci.size); continue; } lump = loadclump(arena, a, 0, &cl, score, 0); if(lump == nil) { fprint(2, "clump %#llx failed to read: %r\n", a); continue; } if(!fast && cl.info.type != VtCorruptType) { scoremem(score, lump->data, cl.info.uncsize); if(scorecmp(cl.info.score, score) != 0) { fprint(2, "clump %#llx has mismatched score\n", a); break; } if(vttypevalid(cl.info.type) < 0) { fprint(2, "clump %#llx has bad type %d\n", a, cl.info.type); break; } } if(z && cl.info.type != VtCorruptType){ zcl.cl = cl; zcl.lump = lump; zcl.aa = a; send(c, &zcl); }else freezblock(lump); if(maxwrites > 0) --maxwrites; } if(a > aa) aa = a; if(haveaoffset) print("end offset %#llx\n", aa); }
static void debugread(HConnect *c, u8int *score) { int type; Lump *u; IAddr ia; IEntry ie; int i; Arena *arena; u64int aa; ZBlock *zb; Clump cl; vlong off; u8int sc[VtScoreSize]; if(scorecmp(score, zeroscore) == 0){ hprint(&c->hout, "zero score\n"); return; } hprint(&c->hout, "<h2>index search %V</h2><pre>\n", score); if(icachelookup(score, -1, &ia) < 0) hprint(&c->hout, " icache: not found\n"); else hprint(&c->hout, " icache: addr=%#llx size=%d type=%d blocks=%d\n", ia.addr, ia.size, ia.type, ia.blocks); if(loadientry(mainindex, score, -1, &ie) < 0) hprint(&c->hout, " idisk: not found\n"); else hprint(&c->hout, " idisk: addr=%#llx size=%d type=%d blocks=%d\n", ie.ia.addr, ie.ia.size, ie.ia.type, ie.ia.blocks); hprint(&c->hout, "</pre><h2>lookup %V</h2>\n", score); hprint(&c->hout, "<pre>\n"); for(type=0; type < VtMaxType; type++){ hprint(&c->hout, "%V type %d:", score, type); u = lookuplump(score, type); if(u->data != nil) hprint(&c->hout, " +cache"); else hprint(&c->hout, " -cache"); putlump(u); if(lookupscore(score, type, &ia) < 0){ hprint(&c->hout, " -lookup\n"); continue; } hprint(&c->hout, "\n lookupscore: addr=%#llx size=%d blocks=%d\n", ia.addr, ia.size, ia.blocks); arena = amapitoa(mainindex, ia.addr, &aa); if(arena == nil){ hprint(&c->hout, " amapitoa failed: %r\n"); continue; } hprint(&c->hout, " amapitoa: aa=%#llx arena=" "<a href=\"/disk?disk=%s&type=a&arena=%s&score=%V\">%s</a>\n", aa, arena->part->name, arena->name, score, arena->name); zb = loadclump(arena, aa, ia.blocks, &cl, sc, 1); if(zb == nil){ hprint(&c->hout, " loadclump failed: %r\n"); continue; } hprint(&c->hout, " loadclump: uncsize=%d type=%d score=%V\n", cl.info.uncsize, cl.info.type, sc); if(ia.size != cl.info.uncsize || ia.type != cl.info.type || scorecmp(score, sc) != 0){ hprint(&c->hout, " clump info mismatch\n"); continue; } } if(hargstr(c, "brute", "")[0] == 'y'){ hprint(&c->hout, "</pre>\n"); hprint(&c->hout, "<h2>brute force arena search %V</h2>\n", score); hprint(&c->hout, "<pre>\n"); for(i=0; i<mainindex->narenas; i++){ arena = mainindex->arenas[i]; hprint(&c->hout, "%s...\n", arena->name); hflush(&c->hout); off = findintoc(nil, arena, score); if(off >= 0) hprint(&c->hout, "%s %#llx (%#llx)\n", arena->name, off, mainindex->amap[i].start + off); } } hprint(&c->hout, "</pre>\n"); }