cmparenas.c (7209B)
1 #include "stdinc.h" 2 #include "dat.h" 3 #include "fns.h" 4 5 static int verbose; 6 static int fd; 7 static int fd1; 8 static uchar *data; 9 static uchar *data1; 10 static int blocksize; 11 static int sleepms; 12 13 void 14 usage(void) 15 { 16 fprint(2, "usage: cmparenas [-b blocksize] [-s ms] [-v] arenapart1 arenapart2 [name...]]\n"); 17 threadexitsall(0); 18 } 19 20 static int 21 preadblock(int fd, uchar *buf, int n, vlong off) 22 { 23 int nr, m; 24 25 for(nr = 0; nr < n; nr += m){ 26 m = n - nr; 27 m = pread(fd, &buf[nr], m, off+nr); 28 if(m <= 0){ 29 if(m == 0) 30 werrstr("early eof"); 31 return -1; 32 } 33 } 34 return 0; 35 } 36 37 static int 38 readblock(int fd, uchar *buf, int n) 39 { 40 int nr, m; 41 42 for(nr = 0; nr < n; nr += m){ 43 m = n - nr; 44 m = read(fd, &buf[nr], m); 45 if(m <= 0){ 46 if(m == 0) 47 werrstr("early eof"); 48 return -1; 49 } 50 } 51 return 0; 52 } 53 54 static int 55 printheader(char *name, ArenaHead *head, int fd) 56 { 57 Arena arena; 58 vlong baseoff, lo, hi, off; 59 int clumpmax; 60 61 off = seek(fd, 0, 1); 62 seek(fd, off + head->size - head->blocksize, 0); 63 if(readblock(fd, data, head->blocksize) < 0){ 64 fprint(2, "%s: reading arena tail: %r\n", name); 65 return -1; 66 } 67 seek(fd, off, 0); 68 69 memset(&arena, 0, sizeof arena); 70 if(unpackarena(&arena, data) < 0){ 71 fprint(2, "%s: unpack arena tail: %r\n", name); 72 return -1; 73 } 74 arena.blocksize = head->blocksize; 75 arena.base = off + head->blocksize; 76 arena.clumpmax = arena.blocksize / ClumpInfoSize; 77 arena.size = head->size - 2*head->blocksize; 78 79 fprint(2, "%s: base=%llx size=%llx blocksize=%x\n", name, off, head->size, head->blocksize); 80 81 baseoff = head->blocksize; 82 fprint(2, "\t%llx-%llx: head\n", (vlong)0, baseoff); 83 lo = baseoff; 84 hi = baseoff + arena.diskstats.used; 85 fprint(2, "\t%llx-%llx: data (%llx)\n", lo, hi, hi - lo); 86 hi = head->size - head->blocksize; 87 clumpmax = head->blocksize / ClumpInfoSize; 88 if(clumpmax > 0) 89 lo = hi - (u64int)arena.diskstats.clumps/clumpmax * head->blocksize; 90 else 91 lo = hi; 92 fprint(2, "\t%llx-%llx: clumps (%llx)\n", lo, hi, hi - lo); 93 fprint(2, "\t%llx-%llx: tail\n", hi, hi + head->blocksize); 94 95 fprint(2, "arena:\n"); 96 printarena(2, &arena); 97 return 0; 98 } 99 100 static void 101 cmparena(char *name, vlong len) 102 { 103 ArenaHead head; 104 DigestState s; 105 u64int n, e; 106 u32int bs; 107 int i, j; 108 char buf[20]; 109 110 fprint(2, "cmp %s\n", name); 111 112 memset(&s, 0, sizeof s); 113 114 /* 115 * read a little bit, which will include the header 116 */ 117 if(readblock(fd, data, HeadSize) < 0){ 118 fprint(2, "%s: reading header: %r\n", name); 119 return; 120 } 121 if(unpackarenahead(&head, data) < 0){ 122 fprint(2, "%s: corrupt arena header: %r\n", name); 123 return; 124 } 125 if(head.version != ArenaVersion4 && head.version != ArenaVersion5) 126 fprint(2, "%s: warning: unknown arena version %d\n", name, head.version); 127 if(len != 0 && len != head.size) 128 fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len); 129 if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0) 130 fprint(2, "%s: warning: unexpected name %s\n", name, head.name); 131 132 if(readblock(fd1, data1, HeadSize) < 0){ 133 fprint(2, "%s: reading header: %r\n", name); 134 return; 135 } 136 if(unpackarenahead(&head, data) < 0){ 137 fprint(2, "%s: corrupt arena header: %r\n", name); 138 return; 139 } 140 if(head.version != ArenaVersion4 && head.version != ArenaVersion5) 141 fprint(2, "%s: warning: unknown arena version %d\n", name, head.version); 142 if(len != 0 && len != head.size) 143 fprint(2, "%s: warning: unexpected length %lld != %lld\n", name, head.size, len); 144 if(strcmp(name, "<stdin>") != 0 && strcmp(head.name, name) != 0) 145 fprint(2, "%s: warning: unexpected name %s\n", name, head.name); 146 147 seek(fd, -HeadSize, 1); 148 seek(fd1, -HeadSize, 1); 149 150 if(printheader(name, &head, fd) < 0) 151 return; 152 153 /* 154 * now we know how much to read 155 * read everything but the last block, which is special 156 */ 157 e = head.size; 158 bs = blocksize; 159 for(n = 0; n < e; n += bs){ 160 if(n + bs > e) 161 bs = e - n; 162 if(readblock(fd, data, bs) < 0){ 163 fprint(2, "%s: read data: %r\n", name); 164 return; 165 } 166 if(readblock(fd1, data1, bs) < 0){ 167 fprint(2, "%s: read data: %r\n", name); 168 return; 169 } 170 if(memcmp(data, data1, bs) != 0){ 171 print("mismatch at %llx\n", n); 172 for(i=0; i<bs; i+=16){ 173 if(memcmp(data+i, data1+i, 16) != 0){ 174 snprint(buf, sizeof buf, "%llx", n+i); 175 print("%s ", buf); 176 for(j=0; j<16; j++){ 177 print(" %.2ux", data[i+j]); 178 if(j == 7) 179 print(" -"); 180 } 181 print("\n"); 182 print("%*s ", (int)strlen(buf), ""); 183 for(j=0; j<16; j++){ 184 print(" %.2ux", data1[i+j]); 185 if(j == 7) 186 print(" -"); 187 } 188 print("\n"); 189 } 190 } 191 } 192 } 193 } 194 195 static int 196 shouldcheck(char *name, char **s, int n) 197 { 198 int i; 199 200 if(n == 0) 201 return 1; 202 203 for(i=0; i<n; i++){ 204 if(s[i] && strcmp(name, s[i]) == 0){ 205 s[i] = nil; 206 return 1; 207 } 208 } 209 return 0; 210 } 211 212 char * 213 readap(int fd, ArenaPart *ap) 214 { 215 char *table; 216 217 if(preadblock(fd, data, 8192, PartBlank) < 0) 218 sysfatal("read arena part header: %r"); 219 if(unpackarenapart(ap, data) < 0) 220 sysfatal("corrupted arena part header: %r"); 221 fprint(2, "# arena part version=%d blocksize=%d arenabase=%d\n", 222 ap->version, ap->blocksize, ap->arenabase); 223 ap->tabbase = (PartBlank+HeadSize+ap->blocksize-1)&~(ap->blocksize-1); 224 ap->tabsize = ap->arenabase - ap->tabbase; 225 table = malloc(ap->tabsize+1); 226 if(preadblock(fd, (uchar*)table, ap->tabsize, ap->tabbase) < 0) 227 sysfatal("reading arena part directory: %r"); 228 table[ap->tabsize] = 0; 229 return table; 230 } 231 232 void 233 threadmain(int argc, char *argv[]) 234 { 235 int i, nline; 236 char *p, *q, *table, *table1, *f[10], line[256]; 237 vlong start, stop; 238 ArenaPart ap; 239 ArenaPart ap1; 240 241 ventifmtinstall(); 242 blocksize = MaxIoSize; 243 ARGBEGIN{ 244 case 'b': 245 blocksize = unittoull(EARGF(usage())); 246 break; 247 case 's': 248 sleepms = atoi(EARGF(usage())); 249 break; 250 case 'v': 251 verbose++; 252 break; 253 default: 254 usage(); 255 break; 256 }ARGEND 257 258 if(argc < 2) 259 usage(); 260 261 data = vtmalloc(blocksize); 262 data1 = vtmalloc(blocksize); 263 if((fd = open(argv[0], OREAD)) < 0) 264 sysfatal("open %s: %r", argv[0]); 265 if((fd1 = open(argv[1], OREAD)) < 0) 266 sysfatal("open %s: %r", argv[0]); 267 268 table = readap(fd, &ap); 269 table1 = readap(fd1, &ap1); 270 if(strcmp(table, table1) != 0) 271 sysfatal("arena partitions do not have identical tables"); 272 273 nline = atoi(table); 274 p = strchr(table, '\n'); 275 if(p) 276 p++; 277 for(i=0; i<nline; i++){ 278 if(p == nil){ 279 fprint(2, "warning: unexpected arena table end\n"); 280 break; 281 } 282 q = strchr(p, '\n'); 283 if(q) 284 *q++ = 0; 285 if(strlen(p) >= sizeof line){ 286 fprint(2, "warning: long arena table line: %s\n", p); 287 p = q; 288 continue; 289 } 290 strcpy(line, p); 291 memset(f, 0, sizeof f); 292 if(tokenize(line, f, nelem(f)) < 3){ 293 fprint(2, "warning: bad arena table line: %s\n", p); 294 p = q; 295 continue; 296 } 297 p = q; 298 if(shouldcheck(f[0], argv+1, argc-1)){ 299 start = strtoull(f[1], 0, 0); 300 stop = strtoull(f[2], 0, 0); 301 if(stop <= start){ 302 fprint(2, "%s: bad start,stop %lld,%lld\n", f[0], stop, start); 303 continue; 304 } 305 if(seek(fd, start, 0) < 0) 306 fprint(2, "%s: seek to start: %r\n", f[0]); 307 if(seek(fd1, start, 0) < 0) 308 fprint(2, "%s: seek to start: %r\n", f[0]); 309 cmparena(f[0], stop - start); 310 } 311 } 312 for(i=2; i<argc; i++) 313 if(argv[i] != 0) 314 fprint(2, "%s: did not find arena\n", argv[i]); 315 316 threadexitsall(nil); 317 }