xref: /plan9-contrib/sys/src/cmd/fossil/archive.c (revision 5e96a66c77eb9140492ca53f857cbbf108e128ed)
1*5e96a66cSDavid du Colombier /*
2*5e96a66cSDavid du Colombier  * Archiver.  In charge of sending blocks to Venti.
3*5e96a66cSDavid du Colombier  */
4*5e96a66cSDavid du Colombier 
5*5e96a66cSDavid du Colombier #include "stdinc.h"
6*5e96a66cSDavid du Colombier #include "dat.h"
7*5e96a66cSDavid du Colombier #include "fns.h"
8*5e96a66cSDavid du Colombier #include "error.h"
9*5e96a66cSDavid du Colombier 
10*5e96a66cSDavid du Colombier #include "9.h"	/* for consPrint */
11*5e96a66cSDavid du Colombier 
12*5e96a66cSDavid du Colombier #define DEBUG 0
13*5e96a66cSDavid du Colombier 
14*5e96a66cSDavid du Colombier static void archThread(void*);
15*5e96a66cSDavid du Colombier 
16*5e96a66cSDavid du Colombier struct Arch
17*5e96a66cSDavid du Colombier {
18*5e96a66cSDavid du Colombier 	int ref;
19*5e96a66cSDavid du Colombier 	uint blockSize;
20*5e96a66cSDavid du Colombier 	uint diskSize;
21*5e96a66cSDavid du Colombier 	Cache *c;
22*5e96a66cSDavid du Colombier 	Fs *fs;
23*5e96a66cSDavid du Colombier 	VtSession *z;
24*5e96a66cSDavid du Colombier 
25*5e96a66cSDavid du Colombier 	VtLock *lk;
26*5e96a66cSDavid du Colombier 	VtRendez *starve;
27*5e96a66cSDavid du Colombier 	VtRendez *die;
28*5e96a66cSDavid du Colombier };
29*5e96a66cSDavid du Colombier 
30*5e96a66cSDavid du Colombier Arch *
31*5e96a66cSDavid du Colombier archInit(Cache *c, Disk *disk, Fs *fs, VtSession *z)
32*5e96a66cSDavid du Colombier {
33*5e96a66cSDavid du Colombier 	Arch *a;
34*5e96a66cSDavid du Colombier 
35*5e96a66cSDavid du Colombier 	a = vtMemAllocZ(sizeof(Arch));
36*5e96a66cSDavid du Colombier 
37*5e96a66cSDavid du Colombier 	a->c = c;
38*5e96a66cSDavid du Colombier 	a->z = z;
39*5e96a66cSDavid du Colombier 	a->fs = fs;
40*5e96a66cSDavid du Colombier 	a->blockSize = diskBlockSize(disk);
41*5e96a66cSDavid du Colombier 	a->lk = vtLockAlloc();
42*5e96a66cSDavid du Colombier 	a->starve = vtRendezAlloc(a->lk);
43*5e96a66cSDavid du Colombier 
44*5e96a66cSDavid du Colombier 	a->ref = 2;
45*5e96a66cSDavid du Colombier 	vtThread(archThread, a);
46*5e96a66cSDavid du Colombier 
47*5e96a66cSDavid du Colombier 	return a;
48*5e96a66cSDavid du Colombier }
49*5e96a66cSDavid du Colombier 
50*5e96a66cSDavid du Colombier void
51*5e96a66cSDavid du Colombier archFree(Arch *a)
52*5e96a66cSDavid du Colombier {
53*5e96a66cSDavid du Colombier 	/* kill slave */
54*5e96a66cSDavid du Colombier 	vtLock(a->lk);
55*5e96a66cSDavid du Colombier 	a->die = vtRendezAlloc(a->lk);
56*5e96a66cSDavid du Colombier 	vtWakeup(a->starve);
57*5e96a66cSDavid du Colombier 	while(a->ref > 1)
58*5e96a66cSDavid du Colombier 		vtSleep(a->die);
59*5e96a66cSDavid du Colombier 	vtUnlock(a->lk);
60*5e96a66cSDavid du Colombier 	vtRendezFree(a->starve);
61*5e96a66cSDavid du Colombier 	vtRendezFree(a->die);
62*5e96a66cSDavid du Colombier 	vtLockFree(a->lk);
63*5e96a66cSDavid du Colombier 	vtMemFree(a);
64*5e96a66cSDavid du Colombier }
65*5e96a66cSDavid du Colombier 
66*5e96a66cSDavid du Colombier static int
67*5e96a66cSDavid du Colombier ventiSend(Arch *a, Block *b, uchar *data)
68*5e96a66cSDavid du Colombier {
69*5e96a66cSDavid du Colombier 	uint n;
70*5e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
71*5e96a66cSDavid du Colombier 
72*5e96a66cSDavid du Colombier 	if(DEBUG > 1)
73*5e96a66cSDavid du Colombier 		fprint(2, "ventiSend: sending %#ux %L to venti\n", b->addr, &b->l);
74*5e96a66cSDavid du Colombier 	n = vtZeroTruncate(vtType[b->l.type], data, a->blockSize);
75*5e96a66cSDavid du Colombier 	if(DEBUG > 1)
76*5e96a66cSDavid du Colombier 		fprint(2, "ventiSend: truncate %d to %d\n", a->blockSize, n);
77*5e96a66cSDavid du Colombier 	if(!vtWrite(a->z, score, vtType[b->l.type], data, n)){
78*5e96a66cSDavid du Colombier 		fprint(2, "ventiSend: vtWrite block %#ux failed: %R\n", b->addr);
79*5e96a66cSDavid du Colombier 		return 0;
80*5e96a66cSDavid du Colombier 	}
81*5e96a66cSDavid du Colombier 	if(!vtSha1Check(score, data, n)){
82*5e96a66cSDavid du Colombier 		uchar score2[VtScoreSize];
83*5e96a66cSDavid du Colombier 		vtSha1(score2, data, n);
84*5e96a66cSDavid du Colombier 		fprint(2, "ventiSend: vtWrite block %#ux failed vtSha1Check %V %V\n",
85*5e96a66cSDavid du Colombier 			b->addr, score, score2);
86*5e96a66cSDavid du Colombier 		return 0;
87*5e96a66cSDavid du Colombier 	}
88*5e96a66cSDavid du Colombier 	if(!vtSync(a->z))
89*5e96a66cSDavid du Colombier 		return 0;
90*5e96a66cSDavid du Colombier 	return 1;
91*5e96a66cSDavid du Colombier }
92*5e96a66cSDavid du Colombier 
93*5e96a66cSDavid du Colombier /*
94*5e96a66cSDavid du Colombier  * parameters for recursion; there are so many,
95*5e96a66cSDavid du Colombier  * and some only change occasionally.  this is
96*5e96a66cSDavid du Colombier  * easier than spelling things out at each call.
97*5e96a66cSDavid du Colombier  */
98*5e96a66cSDavid du Colombier typedef struct Param Param;
99*5e96a66cSDavid du Colombier struct Param
100*5e96a66cSDavid du Colombier {
101*5e96a66cSDavid du Colombier 	/* these never change */
102*5e96a66cSDavid du Colombier 	uint snapEpoch;	/* epoch for snapshot being archived */
103*5e96a66cSDavid du Colombier 	uint blockSize;
104*5e96a66cSDavid du Colombier 	Cache *c;
105*5e96a66cSDavid du Colombier 	Arch *a;
106*5e96a66cSDavid du Colombier 
107*5e96a66cSDavid du Colombier 	/* changes on every call */
108*5e96a66cSDavid du Colombier 	uint depth;
109*5e96a66cSDavid du Colombier 
110*5e96a66cSDavid du Colombier 	/* statistics */
111*5e96a66cSDavid du Colombier 	uint nfixed;
112*5e96a66cSDavid du Colombier 	uint nsend;
113*5e96a66cSDavid du Colombier 	uint nvisit;
114*5e96a66cSDavid du Colombier 	uint nfailsend;
115*5e96a66cSDavid du Colombier 	uint maxdepth;
116*5e96a66cSDavid du Colombier 	uint nreclaim;
117*5e96a66cSDavid du Colombier 	uint nfake;
118*5e96a66cSDavid du Colombier 	uint nreal;
119*5e96a66cSDavid du Colombier 
120*5e96a66cSDavid du Colombier 	/* these occasionally change (must save old values and put back) */
121*5e96a66cSDavid du Colombier 	uint dsize;
122*5e96a66cSDavid du Colombier 	uint psize;
123*5e96a66cSDavid du Colombier 
124*5e96a66cSDavid du Colombier 	/* return value; avoids using stack space */
125*5e96a66cSDavid du Colombier 	Label l;
126*5e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
127*5e96a66cSDavid du Colombier };
128*5e96a66cSDavid du Colombier 
129*5e96a66cSDavid du Colombier static void
130*5e96a66cSDavid du Colombier shaBlock(uchar score[VtScoreSize], Block *b, uchar *data, uint bsize)
131*5e96a66cSDavid du Colombier {
132*5e96a66cSDavid du Colombier 	vtSha1(score, data, vtZeroTruncate(vtType[b->l.type], data, bsize));
133*5e96a66cSDavid du Colombier }
134*5e96a66cSDavid du Colombier 
135*5e96a66cSDavid du Colombier static uint
136*5e96a66cSDavid du Colombier etype(Entry *e)
137*5e96a66cSDavid du Colombier {
138*5e96a66cSDavid du Colombier 	uint t;
139*5e96a66cSDavid du Colombier 
140*5e96a66cSDavid du Colombier 	if(e->flags&VtEntryDir)
141*5e96a66cSDavid du Colombier 		t = BtDir;
142*5e96a66cSDavid du Colombier 	else
143*5e96a66cSDavid du Colombier 		t = BtData;
144*5e96a66cSDavid du Colombier 	return t+e->depth;
145*5e96a66cSDavid du Colombier }
146*5e96a66cSDavid du Colombier 
147*5e96a66cSDavid du Colombier static uchar*
148*5e96a66cSDavid du Colombier copyBlock(Block *b, u32int blockSize)
149*5e96a66cSDavid du Colombier {
150*5e96a66cSDavid du Colombier 	uchar *data;
151*5e96a66cSDavid du Colombier 
152*5e96a66cSDavid du Colombier 	data = vtMemAlloc(blockSize);
153*5e96a66cSDavid du Colombier 	if(data == nil)
154*5e96a66cSDavid du Colombier 		return nil;
155*5e96a66cSDavid du Colombier 	memmove(data, b->data, blockSize);
156*5e96a66cSDavid du Colombier 	return data;
157*5e96a66cSDavid du Colombier }
158*5e96a66cSDavid du Colombier 
159*5e96a66cSDavid du Colombier /*
160*5e96a66cSDavid du Colombier  * Walk over the block tree, archiving it to Venti.
161*5e96a66cSDavid du Colombier  *
162*5e96a66cSDavid du Colombier  * We don't archive the snapshots. Instead we zero the
163*5e96a66cSDavid du Colombier  * entries in a temporary copy and archive that.
164*5e96a66cSDavid du Colombier  *
165*5e96a66cSDavid du Colombier  * Return value is:
166*5e96a66cSDavid du Colombier  *
167*5e96a66cSDavid du Colombier  *	ArchFailure	some error occurred
168*5e96a66cSDavid du Colombier  *	ArchSuccess	block and all children archived
169*5e96a66cSDavid du Colombier  * 	ArchFaked	success, but block or children got copied
170*5e96a66cSDavid du Colombier  */
171*5e96a66cSDavid du Colombier enum
172*5e96a66cSDavid du Colombier {
173*5e96a66cSDavid du Colombier 	ArchFailure,
174*5e96a66cSDavid du Colombier 	ArchSuccess,
175*5e96a66cSDavid du Colombier 	ArchFaked,
176*5e96a66cSDavid du Colombier };
177*5e96a66cSDavid du Colombier static int
178*5e96a66cSDavid du Colombier archWalk(Param *p, u32int addr, uchar type, u32int tag)
179*5e96a66cSDavid du Colombier {
180*5e96a66cSDavid du Colombier 	int ret, i, x, psize, dsize;
181*5e96a66cSDavid du Colombier 	uchar *data, score[VtScoreSize];
182*5e96a66cSDavid du Colombier 	Block *b;
183*5e96a66cSDavid du Colombier 	Label l;
184*5e96a66cSDavid du Colombier 	Entry *e;
185*5e96a66cSDavid du Colombier 	WalkPtr w;
186*5e96a66cSDavid du Colombier 
187*5e96a66cSDavid du Colombier 	p->nvisit++;
188*5e96a66cSDavid du Colombier 
189*5e96a66cSDavid du Colombier 	b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0);
190*5e96a66cSDavid du Colombier 	if(b == nil){
191*5e96a66cSDavid du Colombier 		fprint(2, "archive(%ud, %#ux): cannot find block: %R\n", p->snapEpoch, addr);
192*5e96a66cSDavid du Colombier 		if(strcmp(vtGetError(), ELabelMismatch) == 0){
193*5e96a66cSDavid du Colombier 			/* might as well plod on so we write _something_ to Venti */
194*5e96a66cSDavid du Colombier 			memmove(p->score, vtZeroScore, VtScoreSize);
195*5e96a66cSDavid du Colombier 			return ArchFaked;
196*5e96a66cSDavid du Colombier 		}
197*5e96a66cSDavid du Colombier 		return ArchFailure;
198*5e96a66cSDavid du Colombier 	}
199*5e96a66cSDavid du Colombier 
200*5e96a66cSDavid du Colombier 	if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n",
201*5e96a66cSDavid du Colombier 		p->depth*2, "",  p->snapEpoch, b->addr, &b->l);
202*5e96a66cSDavid du Colombier 	p->depth++;
203*5e96a66cSDavid du Colombier 	if(p->depth > p->maxdepth)
204*5e96a66cSDavid du Colombier 		p->maxdepth = p->depth;
205*5e96a66cSDavid du Colombier 
206*5e96a66cSDavid du Colombier 	data = b->data;
207*5e96a66cSDavid du Colombier 	if((b->l.state&BsVenti) == 0){
208*5e96a66cSDavid du Colombier 		initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize);
209*5e96a66cSDavid du Colombier 		for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){
210*5e96a66cSDavid du Colombier 			if(e){
211*5e96a66cSDavid du Colombier 				if(!(e->flags&VtEntryActive))
212*5e96a66cSDavid du Colombier 					continue;
213*5e96a66cSDavid du Colombier 				if(e->snap != 0 && e->archive == 0){
214*5e96a66cSDavid du Colombier 				//	fprint(2, "snap; faking %#ux\n", b->addr);
215*5e96a66cSDavid du Colombier 					if(data == b->data){
216*5e96a66cSDavid du Colombier 						data = copyBlock(b, p->blockSize);
217*5e96a66cSDavid du Colombier 						if(data == nil){
218*5e96a66cSDavid du Colombier 							ret = ArchFailure;
219*5e96a66cSDavid du Colombier 							goto Out;
220*5e96a66cSDavid du Colombier 						}
221*5e96a66cSDavid du Colombier 						w.data = data;
222*5e96a66cSDavid du Colombier 					}
223*5e96a66cSDavid du Colombier 					memmove(e->score, vtZeroScore, VtScoreSize);
224*5e96a66cSDavid du Colombier 					e->depth = 0;
225*5e96a66cSDavid du Colombier 					e->size = 0;
226*5e96a66cSDavid du Colombier 					e->tag = 0;
227*5e96a66cSDavid du Colombier 					e->flags &= ~VtEntryLocal;
228*5e96a66cSDavid du Colombier 					entryPack(e, data, w.n-1);
229*5e96a66cSDavid du Colombier 					continue;
230*5e96a66cSDavid du Colombier 				}
231*5e96a66cSDavid du Colombier 			}
232*5e96a66cSDavid du Colombier 			addr = globalToLocal(score);
233*5e96a66cSDavid du Colombier 			if(addr == NilBlock)
234*5e96a66cSDavid du Colombier 				continue;
235*5e96a66cSDavid du Colombier 			dsize = p->dsize;
236*5e96a66cSDavid du Colombier 			psize = p->psize;
237*5e96a66cSDavid du Colombier 			if(e){
238*5e96a66cSDavid du Colombier 				p->dsize= e->dsize;
239*5e96a66cSDavid du Colombier 				p->psize = e->psize;
240*5e96a66cSDavid du Colombier 			}
241*5e96a66cSDavid du Colombier 			vtUnlock(b->lk);
242*5e96a66cSDavid du Colombier 			x = archWalk(p, addr, type, tag);
243*5e96a66cSDavid du Colombier 			vtLock(b->lk);
244*5e96a66cSDavid du Colombier 			if(e){
245*5e96a66cSDavid du Colombier 				p->dsize = dsize;
246*5e96a66cSDavid du Colombier 				p->psize = psize;
247*5e96a66cSDavid du Colombier 			}
248*5e96a66cSDavid du Colombier 			while(b->iostate != BioClean && b->iostate != BioDirty)
249*5e96a66cSDavid du Colombier 				vtSleep(b->ioready);
250*5e96a66cSDavid du Colombier 			switch(x){
251*5e96a66cSDavid du Colombier 			case ArchFailure:
252*5e96a66cSDavid du Colombier 				fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n",
253*5e96a66cSDavid du Colombier 					addr, b->addr, i);
254*5e96a66cSDavid du Colombier 				ret = ArchFailure;
255*5e96a66cSDavid du Colombier 				goto Out;
256*5e96a66cSDavid du Colombier 			case ArchFaked:
257*5e96a66cSDavid du Colombier if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score);
258*5e96a66cSDavid du Colombier 				if(data == b->data){
259*5e96a66cSDavid du Colombier 					data = copyBlock(b, p->blockSize);
260*5e96a66cSDavid du Colombier 					if(data == nil){
261*5e96a66cSDavid du Colombier 						ret = ArchFailure;
262*5e96a66cSDavid du Colombier 						goto Out;
263*5e96a66cSDavid du Colombier 					}
264*5e96a66cSDavid du Colombier 					w.data = data;
265*5e96a66cSDavid du Colombier 				}
266*5e96a66cSDavid du Colombier 				/* fall through */
267*5e96a66cSDavid du Colombier if(0) fprint(2, "falling\n");
268*5e96a66cSDavid du Colombier 			case ArchSuccess:
269*5e96a66cSDavid du Colombier 				if(e){
270*5e96a66cSDavid du Colombier 					memmove(e->score, p->score, VtScoreSize);
271*5e96a66cSDavid du Colombier 					e->flags &= ~VtEntryLocal;
272*5e96a66cSDavid du Colombier 					entryPack(e, data, w.n-1);
273*5e96a66cSDavid du Colombier 				}else
274*5e96a66cSDavid du Colombier 					memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize);
275*5e96a66cSDavid du Colombier 				if(data == b->data){
276*5e96a66cSDavid du Colombier 					blockDirty(b);
277*5e96a66cSDavid du Colombier 					if(!(b->l.state & BsCopied))
278*5e96a66cSDavid du Colombier 						blockRemoveLink(b, addr, p->l.type, p->l.tag);
279*5e96a66cSDavid du Colombier 				}
280*5e96a66cSDavid du Colombier 				break;
281*5e96a66cSDavid du Colombier 			}
282*5e96a66cSDavid du Colombier 		}
283*5e96a66cSDavid du Colombier 
284*5e96a66cSDavid du Colombier 		if(!ventiSend(p->a, b, data)){
285*5e96a66cSDavid du Colombier 			p->nfailsend++;
286*5e96a66cSDavid du Colombier 			ret = ArchFailure;
287*5e96a66cSDavid du Colombier 			goto Out;
288*5e96a66cSDavid du Colombier 		}
289*5e96a66cSDavid du Colombier 		p->nsend++;
290*5e96a66cSDavid du Colombier 		if(data != b->data)
291*5e96a66cSDavid du Colombier 			p->nfake++;
292*5e96a66cSDavid du Colombier 		if(data == b->data){	/* not faking it, so update state */
293*5e96a66cSDavid du Colombier 			p->nreal++;
294*5e96a66cSDavid du Colombier 			l = b->l;
295*5e96a66cSDavid du Colombier 			l.state |= BsVenti;
296*5e96a66cSDavid du Colombier 			if(!blockSetLabel(b, &l)){
297*5e96a66cSDavid du Colombier 				ret = ArchFailure;
298*5e96a66cSDavid du Colombier 				goto Out;
299*5e96a66cSDavid du Colombier 			}
300*5e96a66cSDavid du Colombier 		}
301*5e96a66cSDavid du Colombier 	}
302*5e96a66cSDavid du Colombier 
303*5e96a66cSDavid du Colombier 	shaBlock(p->score, b, data, p->blockSize);
304*5e96a66cSDavid du Colombier if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data);
305*5e96a66cSDavid du Colombier 	ret = data!=b->data ? ArchFaked : ArchSuccess;
306*5e96a66cSDavid du Colombier 	p->l = b->l;
307*5e96a66cSDavid du Colombier Out:
308*5e96a66cSDavid du Colombier 	if(data != b->data)
309*5e96a66cSDavid du Colombier 		vtMemFree(data);
310*5e96a66cSDavid du Colombier 	p->depth--;
311*5e96a66cSDavid du Colombier 	blockPut(b);
312*5e96a66cSDavid du Colombier 	return ret;
313*5e96a66cSDavid du Colombier }
314*5e96a66cSDavid du Colombier 
315*5e96a66cSDavid du Colombier static void
316*5e96a66cSDavid du Colombier archThread(void *v)
317*5e96a66cSDavid du Colombier {
318*5e96a66cSDavid du Colombier 	Arch *a = v;
319*5e96a66cSDavid du Colombier 	Block *b;
320*5e96a66cSDavid du Colombier 	Param p;
321*5e96a66cSDavid du Colombier 	Super super;
322*5e96a66cSDavid du Colombier 	int ret;
323*5e96a66cSDavid du Colombier 	u32int addr;
324*5e96a66cSDavid du Colombier 	uchar rbuf[VtRootSize];
325*5e96a66cSDavid du Colombier 	VtRoot root;
326*5e96a66cSDavid du Colombier 
327*5e96a66cSDavid du Colombier 	vtThreadSetName("arch");
328*5e96a66cSDavid du Colombier 
329*5e96a66cSDavid du Colombier 	for(;;){
330*5e96a66cSDavid du Colombier 		/* look for work */
331*5e96a66cSDavid du Colombier 		vtLock(a->fs->elk);
332*5e96a66cSDavid du Colombier 		b = superGet(a->c, &super);
333*5e96a66cSDavid du Colombier 		if(b == nil){
334*5e96a66cSDavid du Colombier 			vtUnlock(a->fs->elk);
335*5e96a66cSDavid du Colombier 			fprint(2, "archThread: superGet: %R");
336*5e96a66cSDavid du Colombier 			sleep(60*1000);
337*5e96a66cSDavid du Colombier 			continue;
338*5e96a66cSDavid du Colombier 		}
339*5e96a66cSDavid du Colombier 		addr = super.next;
340*5e96a66cSDavid du Colombier 		if(addr != NilBlock && super.current == NilBlock){
341*5e96a66cSDavid du Colombier 			super.current = addr;
342*5e96a66cSDavid du Colombier 			super.next = NilBlock;
343*5e96a66cSDavid du Colombier 			superPack(&super, b->data);
344*5e96a66cSDavid du Colombier 			blockDirty(b);
345*5e96a66cSDavid du Colombier 		}else
346*5e96a66cSDavid du Colombier 			addr = super.current;
347*5e96a66cSDavid du Colombier 		blockPut(b);
348*5e96a66cSDavid du Colombier 		vtUnlock(a->fs->elk);
349*5e96a66cSDavid du Colombier 
350*5e96a66cSDavid du Colombier 		if(addr == NilBlock){
351*5e96a66cSDavid du Colombier 			/* wait for work */
352*5e96a66cSDavid du Colombier 			vtLock(a->lk);
353*5e96a66cSDavid du Colombier 			vtSleep(a->starve);
354*5e96a66cSDavid du Colombier 			if(a->die != nil)
355*5e96a66cSDavid du Colombier 				goto Done;
356*5e96a66cSDavid du Colombier 			vtUnlock(a->lk);
357*5e96a66cSDavid du Colombier 			continue;
358*5e96a66cSDavid du Colombier 		}
359*5e96a66cSDavid du Colombier 
360*5e96a66cSDavid du Colombier sleep(10*1000);	/* window of opportunity to provoke races */
361*5e96a66cSDavid du Colombier 
362*5e96a66cSDavid du Colombier 		/* do work */
363*5e96a66cSDavid du Colombier 		memset(&p, 0, sizeof p);
364*5e96a66cSDavid du Colombier 		p.blockSize = a->blockSize;
365*5e96a66cSDavid du Colombier 		p.dsize = 3*VtEntrySize;	/* root has three Entries */
366*5e96a66cSDavid du Colombier 		p.c = a->c;
367*5e96a66cSDavid du Colombier 		p.a = a;
368*5e96a66cSDavid du Colombier 
369*5e96a66cSDavid du Colombier 		ret = archWalk(&p, addr, BtDir, RootTag);
370*5e96a66cSDavid du Colombier 		switch(ret){
371*5e96a66cSDavid du Colombier 		default:
372*5e96a66cSDavid du Colombier 			abort();
373*5e96a66cSDavid du Colombier 		case ArchFailure:
374*5e96a66cSDavid du Colombier 			fprint(2, "archiveBlock %#ux: %R\n", addr);
375*5e96a66cSDavid du Colombier 			sleep(60*1000);
376*5e96a66cSDavid du Colombier 			continue;
377*5e96a66cSDavid du Colombier 		case ArchSuccess:
378*5e96a66cSDavid du Colombier 		case ArchFaked:
379*5e96a66cSDavid du Colombier 			break;
380*5e96a66cSDavid du Colombier 		}
381*5e96a66cSDavid du Colombier 
382*5e96a66cSDavid du Colombier 		if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud"
383*5e96a66cSDavid du Colombier 			" send %ud nfailsend %ud nvisit %ud"
384*5e96a66cSDavid du Colombier 			" nreclaim %ud nfake %ud nreal %ud\n",
385*5e96a66cSDavid du Colombier 			addr, p.maxdepth, p.nfixed,
386*5e96a66cSDavid du Colombier 			p.nsend, p.nfailsend, p.nvisit,
387*5e96a66cSDavid du Colombier 			p.nreclaim, p.nfake, p.nreal);
388*5e96a66cSDavid du Colombier 		if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize);
389*5e96a66cSDavid du Colombier 
390*5e96a66cSDavid du Colombier 		/* tie up vac root */
391*5e96a66cSDavid du Colombier 		memset(&root, 0, sizeof root);
392*5e96a66cSDavid du Colombier 		root.version = VtRootVersion;
393*5e96a66cSDavid du Colombier 		strcpy(root.type, "vac");
394*5e96a66cSDavid du Colombier 		strecpy(root.name, root.name+sizeof root.name, "fossil");
395*5e96a66cSDavid du Colombier 		memmove(root.score, p.score, VtScoreSize);
396*5e96a66cSDavid du Colombier 		memmove(root.prev, super.last, VtScoreSize);
397*5e96a66cSDavid du Colombier 		root.blockSize = a->blockSize;
398*5e96a66cSDavid du Colombier 		vtRootPack(&root, rbuf);
399*5e96a66cSDavid du Colombier 		if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize)
400*5e96a66cSDavid du Colombier 		|| !vtSha1Check(p.score, rbuf, VtRootSize)){
401*5e96a66cSDavid du Colombier 			fprint(2, "vtWriteBlock %#ux: %R\n", addr);
402*5e96a66cSDavid du Colombier 			sleep(60*1000);
403*5e96a66cSDavid du Colombier 			continue;
404*5e96a66cSDavid du Colombier 		}
405*5e96a66cSDavid du Colombier 
406*5e96a66cSDavid du Colombier 		/* record success */
407*5e96a66cSDavid du Colombier 		vtLock(a->fs->elk);
408*5e96a66cSDavid du Colombier 		b = superGet(a->c, &super);
409*5e96a66cSDavid du Colombier 		if(b == nil){
410*5e96a66cSDavid du Colombier 			vtUnlock(a->fs->elk);
411*5e96a66cSDavid du Colombier 			fprint(2, "archThread: superGet: %R");
412*5e96a66cSDavid du Colombier 			sleep(60*1000);
413*5e96a66cSDavid du Colombier 			continue;
414*5e96a66cSDavid du Colombier 		}
415*5e96a66cSDavid du Colombier 		super.current = NilBlock;
416*5e96a66cSDavid du Colombier 		memmove(super.last, p.score, VtScoreSize);
417*5e96a66cSDavid du Colombier 		superPack(&super, b->data);
418*5e96a66cSDavid du Colombier 		blockDirty(b);
419*5e96a66cSDavid du Colombier 		blockPut(b);
420*5e96a66cSDavid du Colombier 		vtUnlock(a->fs->elk);
421*5e96a66cSDavid du Colombier 
422*5e96a66cSDavid du Colombier 		consPrint("archive vac:%V\n", p.score);
423*5e96a66cSDavid du Colombier 	}
424*5e96a66cSDavid du Colombier 
425*5e96a66cSDavid du Colombier Done:
426*5e96a66cSDavid du Colombier 	a->ref--;
427*5e96a66cSDavid du Colombier 	vtWakeup(a->die);
428*5e96a66cSDavid du Colombier 	vtUnlock(a->lk);
429*5e96a66cSDavid du Colombier }
430*5e96a66cSDavid du Colombier 
431*5e96a66cSDavid du Colombier void
432*5e96a66cSDavid du Colombier archKick(Arch *a)
433*5e96a66cSDavid du Colombier {
434*5e96a66cSDavid du Colombier 	if(a == nil){
435*5e96a66cSDavid du Colombier 		fprint(2, "warning: archKick nil\n");
436*5e96a66cSDavid du Colombier 		return;
437*5e96a66cSDavid du Colombier 	}
438*5e96a66cSDavid du Colombier 	vtLock(a->lk);
439*5e96a66cSDavid du Colombier 	vtWakeup(a->starve);
440*5e96a66cSDavid du Colombier 	vtUnlock(a->lk);
441*5e96a66cSDavid du Colombier }
442