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
usage(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
preadblock(int fd,uchar * buf,int n,vlong off)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
readblock(int fd,uchar * buf,int n)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
printheader(char * name,ArenaHead * head,int fd)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
cmparena(char * name,vlong len)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
shouldcheck(char * name,char ** s,int n)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 *
readap(int fd,ArenaPart * ap)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
threadmain(int argc,char * argv[])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 }
318