xref: /plan9/sys/src/cmd/venti/srv/checkindex.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
1*368c31abSDavid du Colombier #include "stdinc.h"
2*368c31abSDavid du Colombier #include "dat.h"
3*368c31abSDavid du Colombier #include "fns.h"
4*368c31abSDavid du Colombier 
5*368c31abSDavid du Colombier static int extra, missing, wrong;
6*368c31abSDavid du Colombier 
7*368c31abSDavid du Colombier static void
phdr(DBlock * eb)8*368c31abSDavid du Colombier phdr(DBlock *eb)
9*368c31abSDavid du Colombier {
10*368c31abSDavid du Colombier 	static int did;
11*368c31abSDavid du Colombier 
12*368c31abSDavid du Colombier 	if(!did){
13*368c31abSDavid du Colombier 		did = 1;
14*368c31abSDavid du Colombier 		print("# diff actual correct\n");
15*368c31abSDavid du Colombier 	}
16*368c31abSDavid du Colombier 	print("%s block 0x%llux\n", eb->part->name, eb->addr);
17*368c31abSDavid du Colombier }
18*368c31abSDavid du Colombier 
19*368c31abSDavid du Colombier static void
pie(IEntry * ie,char c)20*368c31abSDavid du Colombier pie(IEntry *ie, char c)
21*368c31abSDavid du Colombier {
22*368c31abSDavid du Colombier 	print("%c %V %22lld %3d %5d %3d\n",
23*368c31abSDavid du Colombier 		c, ie->score, ie->ia.addr, ie->ia.type, ie->ia.size, ie->ia.blocks);
24*368c31abSDavid du Colombier }
25*368c31abSDavid du Colombier 
26*368c31abSDavid du Colombier static int
checkbucket(Index * ix,u32int buck,IBucket * ib)27*368c31abSDavid du Colombier checkbucket(Index *ix, u32int buck, IBucket *ib)
28*368c31abSDavid du Colombier {
29*368c31abSDavid du Colombier 	ISect *is;
30*368c31abSDavid du Colombier 	DBlock *eb;
31*368c31abSDavid du Colombier 	IBucket eib;
32*368c31abSDavid du Colombier 	IEntry ie, eie;
33*368c31abSDavid du Colombier 	int i, ei, ok, c, hdr;
34*368c31abSDavid du Colombier 
35*368c31abSDavid du Colombier 	is = ix->sects[indexsect0(ix, buck)];
36*368c31abSDavid du Colombier 	if(buck < is->start || buck >= is->stop){
37*368c31abSDavid du Colombier 		seterr(EAdmin, "cannot find index section for bucket %lud\n", (ulong)buck);
38*368c31abSDavid du Colombier 		return -1;
39*368c31abSDavid du Colombier 	}
40*368c31abSDavid du Colombier 	buck -= is->start;
41*368c31abSDavid du Colombier 	eb = getdblock(is->part, is->blockbase + ((u64int)buck << is->blocklog), OREAD);
42*368c31abSDavid du Colombier 	if(eb == nil)
43*368c31abSDavid du Colombier 		return -1;
44*368c31abSDavid du Colombier 	unpackibucket(&eib, eb->data, is->bucketmagic);
45*368c31abSDavid du Colombier 
46*368c31abSDavid du Colombier 	ok = 0;
47*368c31abSDavid du Colombier 	ei = 0;
48*368c31abSDavid du Colombier 	hdr = 0;
49*368c31abSDavid du Colombier 	for(i = 0; i < ib->n; i++){
50*368c31abSDavid du Colombier 		while(ei < eib.n){
51*368c31abSDavid du Colombier 			c = ientrycmp(&ib->data[i * IEntrySize], &eib.data[ei * IEntrySize]);
52*368c31abSDavid du Colombier 			if(c == 0){
53*368c31abSDavid du Colombier 				unpackientry(&ie, &ib->data[i * IEntrySize]);
54*368c31abSDavid du Colombier 				unpackientry(&eie, &eib.data[ei * IEntrySize]);
55*368c31abSDavid du Colombier 				if(iaddrcmp(&ie.ia, &eie.ia) != 0){
56*368c31abSDavid du Colombier 					if(!hdr){
57*368c31abSDavid du Colombier 						phdr(eb);
58*368c31abSDavid du Colombier 						hdr = 1;
59*368c31abSDavid du Colombier 					}
60*368c31abSDavid du Colombier 					wrong++;
61*368c31abSDavid du Colombier 					pie(&eie, '<');
62*368c31abSDavid du Colombier 					pie(&ie, '>');
63*368c31abSDavid du Colombier 				}
64*368c31abSDavid du Colombier 				ei++;
65*368c31abSDavid du Colombier 				goto cont;
66*368c31abSDavid du Colombier 			}
67*368c31abSDavid du Colombier 			if(c < 0)
68*368c31abSDavid du Colombier 				break;
69*368c31abSDavid du Colombier 			if(!hdr){
70*368c31abSDavid du Colombier 				phdr(eb);
71*368c31abSDavid du Colombier 				hdr = 1;
72*368c31abSDavid du Colombier 			}
73*368c31abSDavid du Colombier 			unpackientry(&eie, &eib.data[ei*IEntrySize]);
74*368c31abSDavid du Colombier 			extra++;
75*368c31abSDavid du Colombier 			pie(&eie, '<');
76*368c31abSDavid du Colombier 			ei++;
77*368c31abSDavid du Colombier 			ok = -1;
78*368c31abSDavid du Colombier 		}
79*368c31abSDavid du Colombier 		if(!hdr){
80*368c31abSDavid du Colombier 			phdr(eb);
81*368c31abSDavid du Colombier 			hdr = 1;
82*368c31abSDavid du Colombier 		}
83*368c31abSDavid du Colombier 		unpackientry(&ie, &ib->data[i*IEntrySize]);
84*368c31abSDavid du Colombier 		missing++;
85*368c31abSDavid du Colombier 		pie(&ie, '>');
86*368c31abSDavid du Colombier 		ok = -1;
87*368c31abSDavid du Colombier 	cont:;
88*368c31abSDavid du Colombier 	}
89*368c31abSDavid du Colombier 	for(; ei < eib.n; ei++){
90*368c31abSDavid du Colombier 		if(!hdr){
91*368c31abSDavid du Colombier 			phdr(eb);
92*368c31abSDavid du Colombier 			hdr = 1;
93*368c31abSDavid du Colombier 		}
94*368c31abSDavid du Colombier 		unpackientry(&eie, &eib.data[ei*IEntrySize]);
95*368c31abSDavid du Colombier 		pie(&eie, '<');
96*368c31abSDavid du Colombier 		ok = -1;
97*368c31abSDavid du Colombier 	}
98*368c31abSDavid du Colombier 	putdblock(eb);
99*368c31abSDavid du Colombier 	return ok;
100*368c31abSDavid du Colombier }
101*368c31abSDavid du Colombier 
102*368c31abSDavid du Colombier int
checkindex(Index * ix,Part * part,u64int off,u64int clumps,int zero)103*368c31abSDavid du Colombier checkindex(Index *ix, Part *part, u64int off, u64int clumps, int zero)
104*368c31abSDavid du Colombier {
105*368c31abSDavid du Colombier 	IEStream *ies;
106*368c31abSDavid du Colombier 	IBucket ib, zib;
107*368c31abSDavid du Colombier 	ZBlock *z, *b;
108*368c31abSDavid du Colombier 	u32int next, buck;
109*368c31abSDavid du Colombier 	int ok, bok;
110*368c31abSDavid du Colombier u64int found = 0;
111*368c31abSDavid du Colombier 
112*368c31abSDavid du Colombier /* ZZZ make buffer size configurable */
113*368c31abSDavid du Colombier 	b = alloczblock(ix->blocksize, 0, ix->blocksize);
114*368c31abSDavid du Colombier 	z = alloczblock(ix->blocksize, 1, ix->blocksize);
115*368c31abSDavid du Colombier 	ies = initiestream(part, off, clumps, 64*1024);
116*368c31abSDavid du Colombier 	if(b == nil || z == nil || ies == nil){
117*368c31abSDavid du Colombier 		werrstr("allocating: %r");
118*368c31abSDavid du Colombier 		ok = -1;
119*368c31abSDavid du Colombier 		goto out;
120*368c31abSDavid du Colombier 	}
121*368c31abSDavid du Colombier 	ok = 0;
122*368c31abSDavid du Colombier 	next = 0;
123*368c31abSDavid du Colombier 	memset(&ib, 0, sizeof ib);
124*368c31abSDavid du Colombier 	ib.data = b->data;
125*368c31abSDavid du Colombier 	zib.data = z->data;
126*368c31abSDavid du Colombier 	zib.n = 0;
127*368c31abSDavid du Colombier 	zib.buck = 0;
128*368c31abSDavid du Colombier 	for(;;){
129*368c31abSDavid du Colombier 		buck = buildbucket(ix, ies, &ib, ix->blocksize-IBucketSize);
130*368c31abSDavid du Colombier 		found += ib.n;
131*368c31abSDavid du Colombier 		if(zero){
132*368c31abSDavid du Colombier 			for(; next != buck; next++){
133*368c31abSDavid du Colombier 				if(next == ix->buckets){
134*368c31abSDavid du Colombier 					if(buck != TWID32){
135*368c31abSDavid du Colombier 						ok = -1;
136*368c31abSDavid du Colombier 						werrstr("internal error: bucket out of range");
137*368c31abSDavid du Colombier 					}
138*368c31abSDavid du Colombier 					if(ok < 0)
139*368c31abSDavid du Colombier 						werrstr("%d spurious entries, %d missing, %d wrong", extra, missing, wrong);
140*368c31abSDavid du Colombier 					goto out;
141*368c31abSDavid du Colombier 				}
142*368c31abSDavid du Colombier 				bok = checkbucket(ix, next, &zib);
143*368c31abSDavid du Colombier 				if(bok < 0)
144*368c31abSDavid du Colombier 					ok = -1;
145*368c31abSDavid du Colombier 			}
146*368c31abSDavid du Colombier 		}
147*368c31abSDavid du Colombier 		if(buck >= ix->buckets){
148*368c31abSDavid du Colombier 			if(buck == TWID32)
149*368c31abSDavid du Colombier 				break;
150*368c31abSDavid du Colombier 			werrstr("internal error: bucket out of range");
151*368c31abSDavid du Colombier 			ok = -1;
152*368c31abSDavid du Colombier 			goto out;
153*368c31abSDavid du Colombier 		}
154*368c31abSDavid du Colombier 		bok = checkbucket(ix, buck, &ib);
155*368c31abSDavid du Colombier 		if(bok < 0)
156*368c31abSDavid du Colombier 			ok = -1;
157*368c31abSDavid du Colombier 		next = buck + 1;
158*368c31abSDavid du Colombier 	}
159*368c31abSDavid du Colombier out:
160*368c31abSDavid du Colombier 	freeiestream(ies);
161*368c31abSDavid du Colombier 	freezblock(z);
162*368c31abSDavid du Colombier 	freezblock(b);
163*368c31abSDavid du Colombier 	return ok;
164*368c31abSDavid du Colombier }
165*368c31abSDavid du Colombier 
166*368c31abSDavid du Colombier int
checkbloom(Bloom * b1,Bloom * b2,int fix)167*368c31abSDavid du Colombier checkbloom(Bloom *b1, Bloom *b2, int fix)
168*368c31abSDavid du Colombier {
169*368c31abSDavid du Colombier 	u32int *a1, *a2;
170*368c31abSDavid du Colombier 	int i, n, extra, missing;
171*368c31abSDavid du Colombier 
172*368c31abSDavid du Colombier 	if(b1==nil && b2==nil)
173*368c31abSDavid du Colombier 		return 0;
174*368c31abSDavid du Colombier 	if(b1==nil || b2==nil){
175*368c31abSDavid du Colombier 		werrstr("nil/non-nil");
176*368c31abSDavid du Colombier 		return -1;
177*368c31abSDavid du Colombier 	}
178*368c31abSDavid du Colombier 	wbbloomhead(b1);
179*368c31abSDavid du Colombier 	wbbloomhead(b2);
180*368c31abSDavid du Colombier 	if(memcmp(b1->data, b2->data, BloomHeadSize) != 0){
181*368c31abSDavid du Colombier 		werrstr("bloom header mismatch");
182*368c31abSDavid du Colombier 		return -1;
183*368c31abSDavid du Colombier 	}
184*368c31abSDavid du Colombier 	a1 = (u32int*)b1->data;
185*368c31abSDavid du Colombier 	a2 = (u32int*)b2->data;
186*368c31abSDavid du Colombier 	n = b1->size/4;
187*368c31abSDavid du Colombier 	extra = 0;
188*368c31abSDavid du Colombier 	missing = 0;
189*368c31abSDavid du Colombier 	for(i=BloomHeadSize/4; i<n; i++){
190*368c31abSDavid du Colombier 		if(a1[i] != a2[i]){
191*368c31abSDavid du Colombier // print("%.8ux/%.8ux.", a1[i], a2[i]);
192*368c31abSDavid du Colombier 			extra   += countbits(a1[i] & ~a2[i]);
193*368c31abSDavid du Colombier 			missing += countbits(a2[i] & ~a1[i]);
194*368c31abSDavid du Colombier 		}
195*368c31abSDavid du Colombier 	}
196*368c31abSDavid du Colombier 	if(extra || missing)
197*368c31abSDavid du Colombier 		fprint(2, "bloom filter: %d spurious bits, %d missing bits\n",
198*368c31abSDavid du Colombier 			extra, missing);
199*368c31abSDavid du Colombier 	else
200*368c31abSDavid du Colombier 		fprint(2, "bloom filter: correct\n");
201*368c31abSDavid du Colombier 	if(!fix && missing){
202*368c31abSDavid du Colombier 		werrstr("missing bits");
203*368c31abSDavid du Colombier 		return -1;
204*368c31abSDavid du Colombier 	}
205*368c31abSDavid du Colombier 	if(fix && (missing || extra)){
206*368c31abSDavid du Colombier 		memmove(b1->data, b2->data, b1->size);
207*368c31abSDavid du Colombier 		return writebloom(b1);
208*368c31abSDavid du Colombier 	}
209*368c31abSDavid du Colombier 	return 0;
210*368c31abSDavid du Colombier }
211*368c31abSDavid du Colombier 
212*368c31abSDavid du Colombier 
213*368c31abSDavid du Colombier void
usage(void)214*368c31abSDavid du Colombier usage(void)
215*368c31abSDavid du Colombier {
216*368c31abSDavid du Colombier 	fprint(2, "usage: checkindex [-f] [-B blockcachesize] config tmp\n");
217*368c31abSDavid du Colombier 	threadexitsall(0);
218*368c31abSDavid du Colombier }
219*368c31abSDavid du Colombier 
220*368c31abSDavid du Colombier Config conf;
221*368c31abSDavid du Colombier 
222*368c31abSDavid du Colombier void
threadmain(int argc,char * argv[])223*368c31abSDavid du Colombier threadmain(int argc, char *argv[])
224*368c31abSDavid du Colombier {
225*368c31abSDavid du Colombier 	Bloom *oldbloom, *newbloom;
226*368c31abSDavid du Colombier 	Part *part;
227*368c31abSDavid du Colombier 	u64int clumps, base;
228*368c31abSDavid du Colombier 	u32int bcmem;
229*368c31abSDavid du Colombier 	int fix, skipz, ok;
230*368c31abSDavid du Colombier 
231*368c31abSDavid du Colombier 	fix = 0;
232*368c31abSDavid du Colombier 	bcmem = 0;
233*368c31abSDavid du Colombier 	skipz = 0;
234*368c31abSDavid du Colombier 	ARGBEGIN{
235*368c31abSDavid du Colombier 	case 'B':
236*368c31abSDavid du Colombier 		bcmem = unittoull(ARGF());
237*368c31abSDavid du Colombier 		break;
238*368c31abSDavid du Colombier 	case 'f':
239*368c31abSDavid du Colombier 		fix++;
240*368c31abSDavid du Colombier 		break;
241*368c31abSDavid du Colombier 	case 'Z':
242*368c31abSDavid du Colombier 		skipz = 1;
243*368c31abSDavid du Colombier 		break;
244*368c31abSDavid du Colombier 	default:
245*368c31abSDavid du Colombier 		usage();
246*368c31abSDavid du Colombier 		break;
247*368c31abSDavid du Colombier 	}ARGEND
248*368c31abSDavid du Colombier 
249*368c31abSDavid du Colombier 	if(argc != 2)
250*368c31abSDavid du Colombier 		usage();
251*368c31abSDavid du Colombier 
252*368c31abSDavid du Colombier 	ventifmtinstall();
253*368c31abSDavid du Colombier 
254*368c31abSDavid du Colombier 	part = initpart(argv[1], ORDWR|ODIRECT);
255*368c31abSDavid du Colombier 	if(part == nil)
256*368c31abSDavid du Colombier 		sysfatal("can't initialize temporary partition: %r");
257*368c31abSDavid du Colombier 
258*368c31abSDavid du Colombier 	if(!fix)
259*368c31abSDavid du Colombier 		readonly = 1;
260*368c31abSDavid du Colombier 
261*368c31abSDavid du Colombier 	if(initventi(argv[0], &conf) < 0)
262*368c31abSDavid du Colombier 		sysfatal("can't init venti: %r");
263*368c31abSDavid du Colombier 	if(mainindex->bloom && loadbloom(mainindex->bloom) < 0)
264*368c31abSDavid du Colombier 		sysfatal("can't load bloom filter: %r");
265*368c31abSDavid du Colombier 	oldbloom = mainindex->bloom;
266*368c31abSDavid du Colombier 	newbloom = nil;
267*368c31abSDavid du Colombier 	if(oldbloom){
268*368c31abSDavid du Colombier 		newbloom = vtmallocz(sizeof *newbloom);
269*368c31abSDavid du Colombier 		bloominit(newbloom, oldbloom->size, nil);
270*368c31abSDavid du Colombier 		newbloom->data = vtmallocz(oldbloom->size);
271*368c31abSDavid du Colombier 	}
272*368c31abSDavid du Colombier 	if(bcmem < maxblocksize * (mainindex->narenas + mainindex->nsects * 4 + 16))
273*368c31abSDavid du Colombier 		bcmem = maxblocksize * (mainindex->narenas + mainindex->nsects * 4 + 16);
274*368c31abSDavid du Colombier 	if(0) fprint(2, "initialize %d bytes of disk block cache\n", bcmem);
275*368c31abSDavid du Colombier 	initdcache(bcmem);
276*368c31abSDavid du Colombier 
277*368c31abSDavid du Colombier 	fprint(2, "checkindex: building entry list\n");
278*368c31abSDavid du Colombier 	clumps = sortrawientries(mainindex, part, &base, newbloom);
279*368c31abSDavid du Colombier 	if(clumps == TWID64)
280*368c31abSDavid du Colombier 		sysfatal("can't build sorted index: %r");
281*368c31abSDavid du Colombier 	fprint(2, "checkindex: checking %lld entries at %lld\n", clumps, base);
282*368c31abSDavid du Colombier 	ok = 0;
283*368c31abSDavid du Colombier 	if(checkindex(mainindex, part, base, clumps, !skipz) < 0){
284*368c31abSDavid du Colombier 		fprint(2, "checkindex: %r\n");
285*368c31abSDavid du Colombier 		ok = -1;
286*368c31abSDavid du Colombier 	}
287*368c31abSDavid du Colombier 	if(checkbloom(oldbloom, newbloom, fix) < 0){
288*368c31abSDavid du Colombier 		fprint(2, "checkbloom: %r\n");
289*368c31abSDavid du Colombier 		ok = -1;
290*368c31abSDavid du Colombier 	}
291*368c31abSDavid du Colombier 	if(ok < 0)
292*368c31abSDavid du Colombier 		sysfatal("errors found");
293*368c31abSDavid du Colombier 	fprint(2, "checkindex: index is correct\n");
294*368c31abSDavid du Colombier 	threadexitsall(0);
295*368c31abSDavid du Colombier }
296