Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
/*
 * 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;
}
Beispiel #3
0
void
xmlscore(Hio *hout, u8int *v, char *tag)
{
	if(scorecmp(zeroscore, v) == 0)
		return;
	hprint(hout, " %s=\"%V\"", tag, v);
}
Beispiel #4
0
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;
}
Beispiel #5
0
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);
}
Beispiel #6
0
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;
}
Beispiel #7
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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);
}
Beispiel #16
0
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);
}
Beispiel #17
0
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");
}