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 }