Blob


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