Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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