plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

checkindex.c (5978B)


      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 }