Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
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;
13 void
14 usage(void)
15 {
16 fprint(2, "usage: cmparenas [-b blocksize] [-s ms] [-v] arenapart1 arenapart2 [name...]]\n");
17 threadexitsall(0);
18 }
20 static int
21 preadblock(int fd, uchar *buf, int n, vlong off)
22 {
23 int nr, m;
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 }
37 static int
38 readblock(int fd, uchar *buf, int n)
39 {
40 int nr, m;
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 }
54 static int
55 printheader(char *name, ArenaHead *head, int fd)
56 {
57 Arena arena;
58 vlong baseoff, lo, hi, off;
59 int clumpmax;
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);
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;
79 fprint(2, "%s: base=%llx size=%llx blocksize=%x\n", name, off, head->size, head->blocksize);
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);
95 fprint(2, "arena:\n");
96 printarena(2, &arena);
97 return 0;
98 }
100 static void
101 cmparena(char *name, vlong len)
103 ArenaHead head;
104 DigestState s;
105 u64int n, e;
106 u32int bs;
107 int i, j;
108 char buf[20];
110 fprint(2, "cmp %s\n", name);
112 memset(&s, 0, sizeof s);
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;
121 if(unpackarenahead(&head, data) < 0){
122 fprint(2, "%s: corrupt arena header: %r\n", name);
123 return;
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);
132 if(readblock(fd1, data1, HeadSize) < 0){
133 fprint(2, "%s: reading header: %r\n", name);
134 return;
136 if(unpackarenahead(&head, data) < 0){
137 fprint(2, "%s: corrupt arena header: %r\n", name);
138 return;
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);
147 seek(fd, -HeadSize, 1);
148 seek(fd1, -HeadSize, 1);
150 if(printheader(name, &head, fd) < 0)
151 return;
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;
166 if(readblock(fd1, data1, bs) < 0){
167 fprint(2, "%s: read data: %r\n", name);
168 return;
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(" -");
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(" -");
188 print("\n");
195 static int
196 shouldcheck(char *name, char **s, int n)
198 int i;
200 if(n == 0)
201 return 1;
203 for(i=0; i<n; i++){
204 if(s[i] && strcmp(name, s[i]) == 0){
205 s[i] = nil;
206 return 1;
209 return 0;
212 char *
213 readap(int fd, ArenaPart *ap)
215 char *table;
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;
232 void
233 threadmain(int argc, char *argv[])
235 int i, nline;
236 char *p, *q, *table, *table1, *f[10], line[256];
237 vlong start, stop;
238 ArenaPart ap;
239 ArenaPart ap1;
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
258 if(argc < 2)
259 usage();
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]);
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");
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;
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;
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;
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;
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);
312 for(i=2; i<argc; i++)
313 if(argv[i] != 0)
314 fprint(2, "%s: did not find arena\n", argv[i]);
316 threadexitsall(nil);