checkindex.c 5.8 KB

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