xref: /plan9-contrib/sys/src/cmd/venti/srv/cmparenas.c (revision 368c31ab13393dea083228fdd1c3445076f83a4b)
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