xref: /plan9-contrib/sys/src/cmd/venti/srv/wrarena.c (revision 649197e1527dbedaf9577cb972c8a1f950d133c6)
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 
5 QLock godot;
6 char *host;
7 int readonly = 1;	/* for part.c */
8 int mainstacksize = 256*1024;
9 Channel *c;
10 VtConn *z;
11 int fast;	/* and a bit unsafe; only for benchmarking */
12 int haveaoffset;
13 int maxwrites = -1;
14 int verbose;
15 
16 typedef struct ZClump ZClump;
17 struct ZClump
18 {
19 	ZBlock *lump;
20 	Clump cl;
21 	u64int aa;
22 };
23 
24 void
usage(void)25 usage(void)
26 {
27 	fprint(2, "usage: wrarena [-h host] arenafile [offset]\n");
28 	threadexitsall("usage");
29 }
30 
31 void
vtsendthread(void * v)32 vtsendthread(void *v)
33 {
34 	ZClump zcl;
35 
36 	USED(v);
37 	while(recv(c, &zcl) == 1){
38 		if(zcl.lump == nil)
39 			break;
40 		if(vtwrite(z, zcl.cl.info.score, zcl.cl.info.type, zcl.lump->data, zcl.cl.info.uncsize) < 0)
41 			sysfatal("failed writing clump %llud: %r", zcl.aa);
42 		if(verbose)
43 			print("%V\n", zcl.cl.info.score);
44 		freezblock(zcl.lump);
45 	}
46 	/*
47 	 * All the send threads try to exit right when
48 	 * threadmain is calling threadexitsall.
49 	 * Either libthread or the Linux NPTL pthreads library
50 	 * can't handle this condition (I suspect NPTL but have
51 	 * not confirmed this) and we get a seg fault in exit.
52 	 * I spent a day tracking this down with no success,
53 	 * so we're going to work around it instead by just
54 	 * sitting here and waiting for the threadexitsall to
55 	 * take effect.
56 	 */
57 	qlock(&godot);
58 }
59 
60 static void
rdarena(Arena * arena,u64int offset)61 rdarena(Arena *arena, u64int offset)
62 {
63 	int i;
64 	u64int a, aa, e;
65 	uchar score[VtScoreSize];
66 	Clump cl;
67 	ClumpInfo ci;
68 	ZBlock *lump;
69 	ZClump zcl;
70 
71 	fprint(2, "wrarena: copying %s to venti\n", arena->name);
72 	printarena(2, arena);
73 
74 	a = arena->base;
75 	e = arena->base + arena->size;
76 	if(offset != ~(u64int)0) {
77 		if(offset >= e - a)
78 			sysfatal("bad offset %#llx >= %#llx", offset, e - a);
79 		aa = offset;
80 	} else
81 		aa = 0;
82 
83 	i = 0;
84 	for(a = 0; maxwrites != 0 && i < arena->memstats.clumps;
85 	    a += ClumpSize + ci.size){
86 		if(readclumpinfo(arena, i++, &ci) < 0)
87 			break;
88 		if(a < aa || ci.type == VtCorruptType){
89 			if(ci.type == VtCorruptType)
90 				fprint(2, "%s: corrupt clump read at %#llx: +%d\n",
91 					argv0, a, ClumpSize+ci.size);
92 			continue;
93 		}
94 		lump = loadclump(arena, a, 0, &cl, score, 0);
95 		if(lump == nil) {
96 			fprint(2, "clump %#llx failed to read: %r\n", a);
97 			continue;
98 		}
99 		if(!fast && cl.info.type != VtCorruptType) {
100 			scoremem(score, lump->data, cl.info.uncsize);
101 			if(scorecmp(cl.info.score, score) != 0) {
102 				fprint(2, "clump %#llx has mismatched score\n",
103 					a);
104 				break;
105 			}
106 			if(vttypevalid(cl.info.type) < 0) {
107 				fprint(2, "clump %#llx has bad type %d\n",
108 					a, cl.info.type);
109 				break;
110 			}
111 		}
112 		if(z && cl.info.type != VtCorruptType){
113 			zcl.cl = cl;
114 			zcl.lump = lump;
115 			zcl.aa = a;
116 			send(c, &zcl);
117 		}else
118 			freezblock(lump);
119 		if(maxwrites > 0)
120 			--maxwrites;
121 	}
122 	if(a > aa)
123 		aa = a;
124 	if(haveaoffset)
125 		print("end offset %#llx\n", aa);
126 }
127 
128 void
threadmain(int argc,char * argv[])129 threadmain(int argc, char *argv[])
130 {
131 	int i;
132 	char *file;
133 	Arena *arena;
134 	u64int offset, aoffset;
135 	Part *part;
136 	uchar buf[8192];
137 	ArenaHead head;
138 	ZClump zerocl;
139 
140 	ventifmtinstall();
141 	qlock(&godot);
142 	aoffset = 0;
143 	ARGBEGIN{
144 	case 'f':
145 		fast = 1;
146 		ventidoublechecksha1 = 0;
147 		break;
148 	case 'h':
149 		host = EARGF(usage());
150 		break;
151 	case 'o':
152 		haveaoffset = 1;
153 		aoffset = strtoull(EARGF(usage()), 0, 0);
154 		break;
155 	case 'M':
156 		maxwrites = atoi(EARGF(usage()));
157 		break;
158 	case 'v':
159 		verbose = 1;
160 		break;
161 	default:
162 		usage();
163 		break;
164 	}ARGEND
165 
166 	offset = ~(u64int)0;
167 	switch(argc) {
168 	default:
169 		usage();
170 	case 2:
171 		offset = strtoull(argv[1], 0, 0);
172 		/* fall through */
173 	case 1:
174 		file = argv[0];
175 	}
176 
177 	fmtinstall('V', vtscorefmt);
178 
179 	statsinit();
180 
181 	part = initpart(file, OREAD);
182 	if(part == nil)
183 		sysfatal("can't open file %s: %r", file);
184 	if(readpart(part, aoffset, buf, sizeof buf) < 0)
185 		sysfatal("can't read file %s: %r", file);
186 
187 	if(unpackarenahead(&head, buf) < 0)
188 		sysfatal("corrupted arena header: %r");
189 
190 	if(aoffset+head.size > part->size)
191 		sysfatal("arena is truncated: want %llud bytes have %llud",
192 			head.size, part->size);
193 
194 	partblocksize(part, head.blocksize);
195 	initdcache(8 * MaxDiskBlock);
196 
197 	arena = initarena(part, aoffset, head.size, head.blocksize);
198 	if(arena == nil)
199 		sysfatal("initarena: %r");
200 
201 	z = nil;
202 	if(host==nil || strcmp(host, "/dev/null") != 0){
203 		z = vtdial(host);
204 		if(z == nil)
205 			sysfatal("could not connect to server: %r");
206 		if(vtconnect(z) < 0)
207 			sysfatal("vtconnect: %r");
208 	}
209 
210 	c = chancreate(sizeof(ZClump), 0);
211 	for(i=0; i<12; i++)
212 		vtproc(vtsendthread, nil);
213 
214 	rdarena(arena, offset);
215 	if(vtsync(z) < 0)
216 		sysfatal("executing sync: %r");
217 
218 	memset(&zerocl, 0, sizeof zerocl);
219 	for(i=0; i<12; i++)
220 		send(c, &zerocl);
221 	if(z){
222 		vthangup(z);
223 	}
224 	threadexitsall(0);
225 }
226