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