xref: /plan9-contrib/sys/src/cmd/fossil/archive.c (revision d7aba6c3b511bc618cf0c53345848188fc02611a)
15e96a66cSDavid du Colombier /*
25e96a66cSDavid du Colombier  * Archiver.  In charge of sending blocks to Venti.
35e96a66cSDavid du Colombier  */
45e96a66cSDavid du Colombier 
55e96a66cSDavid du Colombier #include "stdinc.h"
65e96a66cSDavid du Colombier #include "dat.h"
75e96a66cSDavid du Colombier #include "fns.h"
85e96a66cSDavid du Colombier #include "error.h"
95e96a66cSDavid du Colombier 
105e96a66cSDavid du Colombier #include "9.h"	/* for consPrint */
115e96a66cSDavid du Colombier 
125e96a66cSDavid du Colombier #define DEBUG 0
135e96a66cSDavid du Colombier 
145e96a66cSDavid du Colombier static void archThread(void*);
155e96a66cSDavid du Colombier 
165e96a66cSDavid du Colombier struct Arch
175e96a66cSDavid du Colombier {
185e96a66cSDavid du Colombier 	int ref;
195e96a66cSDavid du Colombier 	uint blockSize;
205e96a66cSDavid du Colombier 	uint diskSize;
215e96a66cSDavid du Colombier 	Cache *c;
225e96a66cSDavid du Colombier 	Fs *fs;
23*d7aba6c3SDavid du Colombier 	VtConn *z;
245e96a66cSDavid du Colombier 
25*d7aba6c3SDavid du Colombier 	QLock lk;
26*d7aba6c3SDavid du Colombier 	Rendez starve;
27*d7aba6c3SDavid du Colombier 	Rendez die;
285e96a66cSDavid du Colombier };
295e96a66cSDavid du Colombier 
305e96a66cSDavid du Colombier Arch *
archInit(Cache * c,Disk * disk,Fs * fs,VtConn * z)31*d7aba6c3SDavid du Colombier archInit(Cache *c, Disk *disk, Fs *fs, VtConn *z)
325e96a66cSDavid du Colombier {
335e96a66cSDavid du Colombier 	Arch *a;
345e96a66cSDavid du Colombier 
35*d7aba6c3SDavid du Colombier 	a = vtmallocz(sizeof(Arch));
365e96a66cSDavid du Colombier 
375e96a66cSDavid du Colombier 	a->c = c;
385e96a66cSDavid du Colombier 	a->z = z;
395e96a66cSDavid du Colombier 	a->fs = fs;
405e96a66cSDavid du Colombier 	a->blockSize = diskBlockSize(disk);
41*d7aba6c3SDavid du Colombier 	a->starve.l = &a->lk;
425e96a66cSDavid du Colombier 
435e96a66cSDavid du Colombier 	a->ref = 2;
44*d7aba6c3SDavid du Colombier 	proccreate(archThread, a, STACK);
455e96a66cSDavid du Colombier 
465e96a66cSDavid du Colombier 	return a;
475e96a66cSDavid du Colombier }
485e96a66cSDavid du Colombier 
495e96a66cSDavid du Colombier void
archFree(Arch * a)505e96a66cSDavid du Colombier archFree(Arch *a)
515e96a66cSDavid du Colombier {
525e96a66cSDavid du Colombier 	/* kill slave */
53*d7aba6c3SDavid du Colombier 	qlock(&a->lk);
54*d7aba6c3SDavid du Colombier 	a->die.l = &a->lk;
55*d7aba6c3SDavid du Colombier 	rwakeup(&a->starve);
565e96a66cSDavid du Colombier 	while(a->ref > 1)
57*d7aba6c3SDavid du Colombier 		rsleep(&a->die);
58*d7aba6c3SDavid du Colombier 	qunlock(&a->lk);
59*d7aba6c3SDavid du Colombier 	vtfree(a);
605e96a66cSDavid du Colombier }
615e96a66cSDavid du Colombier 
625e96a66cSDavid du Colombier static int
ventiSend(Arch * a,Block * b,uchar * data)635e96a66cSDavid du Colombier ventiSend(Arch *a, Block *b, uchar *data)
645e96a66cSDavid du Colombier {
655e96a66cSDavid du Colombier 	uint n;
665e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
675e96a66cSDavid du Colombier 
685e96a66cSDavid du Colombier 	if(DEBUG > 1)
695e96a66cSDavid du Colombier 		fprint(2, "ventiSend: sending %#ux %L to venti\n", b->addr, &b->l);
70*d7aba6c3SDavid du Colombier 	n = vtzerotruncate(vtType[b->l.type], data, a->blockSize);
715e96a66cSDavid du Colombier 	if(DEBUG > 1)
725e96a66cSDavid du Colombier 		fprint(2, "ventiSend: truncate %d to %d\n", a->blockSize, n);
73*d7aba6c3SDavid du Colombier 	if(vtwrite(a->z, score, vtType[b->l.type], data, n) < 0){
74*d7aba6c3SDavid du Colombier 		fprint(2, "ventiSend: vtwrite block %#ux failed: %r\n", b->addr);
755e96a66cSDavid du Colombier 		return 0;
765e96a66cSDavid du Colombier 	}
77*d7aba6c3SDavid du Colombier 	if(vtsha1check(score, data, n) < 0){
785e96a66cSDavid du Colombier 		uchar score2[VtScoreSize];
79*d7aba6c3SDavid du Colombier 		vtsha1(score2, data, n);
80*d7aba6c3SDavid du Colombier 		fprint(2, "ventiSend: vtwrite block %#ux failed vtsha1check %V %V\n",
815e96a66cSDavid du Colombier 			b->addr, score, score2);
825e96a66cSDavid du Colombier 		return 0;
835e96a66cSDavid du Colombier 	}
84*d7aba6c3SDavid du Colombier 	if(vtsync(a->z) < 0)
855e96a66cSDavid du Colombier 		return 0;
865e96a66cSDavid du Colombier 	return 1;
875e96a66cSDavid du Colombier }
885e96a66cSDavid du Colombier 
895e96a66cSDavid du Colombier /*
905e96a66cSDavid du Colombier  * parameters for recursion; there are so many,
915e96a66cSDavid du Colombier  * and some only change occasionally.  this is
925e96a66cSDavid du Colombier  * easier than spelling things out at each call.
935e96a66cSDavid du Colombier  */
945e96a66cSDavid du Colombier typedef struct Param Param;
955e96a66cSDavid du Colombier struct Param
965e96a66cSDavid du Colombier {
975e96a66cSDavid du Colombier 	/* these never change */
985e96a66cSDavid du Colombier 	uint snapEpoch;	/* epoch for snapshot being archived */
995e96a66cSDavid du Colombier 	uint blockSize;
1005e96a66cSDavid du Colombier 	Cache *c;
1015e96a66cSDavid du Colombier 	Arch *a;
1025e96a66cSDavid du Colombier 
1035e96a66cSDavid du Colombier 	/* changes on every call */
1045e96a66cSDavid du Colombier 	uint depth;
1055e96a66cSDavid du Colombier 
1065e96a66cSDavid du Colombier 	/* statistics */
1075e96a66cSDavid du Colombier 	uint nfixed;
1085e96a66cSDavid du Colombier 	uint nsend;
1095e96a66cSDavid du Colombier 	uint nvisit;
1105e96a66cSDavid du Colombier 	uint nfailsend;
1115e96a66cSDavid du Colombier 	uint maxdepth;
1125e96a66cSDavid du Colombier 	uint nreclaim;
1135e96a66cSDavid du Colombier 	uint nfake;
1145e96a66cSDavid du Colombier 	uint nreal;
1155e96a66cSDavid du Colombier 
1165e96a66cSDavid du Colombier 	/* these occasionally change (must save old values and put back) */
1175e96a66cSDavid du Colombier 	uint dsize;
1185e96a66cSDavid du Colombier 	uint psize;
1195e96a66cSDavid du Colombier 
1205e96a66cSDavid du Colombier 	/* return value; avoids using stack space */
1215e96a66cSDavid du Colombier 	Label l;
1225e96a66cSDavid du Colombier 	uchar score[VtScoreSize];
1235e96a66cSDavid du Colombier };
1245e96a66cSDavid du Colombier 
1255e96a66cSDavid du Colombier static void
shaBlock(uchar score[VtScoreSize],Block * b,uchar * data,uint bsize)1265e96a66cSDavid du Colombier shaBlock(uchar score[VtScoreSize], Block *b, uchar *data, uint bsize)
1275e96a66cSDavid du Colombier {
128*d7aba6c3SDavid du Colombier 	vtsha1(score, data, vtzerotruncate(vtType[b->l.type], data, bsize));
1295e96a66cSDavid du Colombier }
1305e96a66cSDavid du Colombier 
1315e96a66cSDavid du Colombier static uint
etype(Entry * e)1325e96a66cSDavid du Colombier etype(Entry *e)
1335e96a66cSDavid du Colombier {
1345e96a66cSDavid du Colombier 	uint t;
1355e96a66cSDavid du Colombier 
136*d7aba6c3SDavid du Colombier 	if(e->flags&_VtEntryDir)
1375e96a66cSDavid du Colombier 		t = BtDir;
1385e96a66cSDavid du Colombier 	else
1395e96a66cSDavid du Colombier 		t = BtData;
1405e96a66cSDavid du Colombier 	return t+e->depth;
1415e96a66cSDavid du Colombier }
1425e96a66cSDavid du Colombier 
1435e96a66cSDavid du Colombier static uchar*
copyBlock(Block * b,u32int blockSize)1445e96a66cSDavid du Colombier copyBlock(Block *b, u32int blockSize)
1455e96a66cSDavid du Colombier {
1465e96a66cSDavid du Colombier 	uchar *data;
1475e96a66cSDavid du Colombier 
148*d7aba6c3SDavid du Colombier 	data = vtmalloc(blockSize);
1495e96a66cSDavid du Colombier 	if(data == nil)
1505e96a66cSDavid du Colombier 		return nil;
1515e96a66cSDavid du Colombier 	memmove(data, b->data, blockSize);
1525e96a66cSDavid du Colombier 	return data;
1535e96a66cSDavid du Colombier }
1545e96a66cSDavid du Colombier 
1555e96a66cSDavid du Colombier /*
1565e96a66cSDavid du Colombier  * Walk over the block tree, archiving it to Venti.
1575e96a66cSDavid du Colombier  *
1585e96a66cSDavid du Colombier  * We don't archive the snapshots. Instead we zero the
159e569ccb5SDavid du Colombier  * entries in a temporary copy of the block and archive that.
1605e96a66cSDavid du Colombier  *
1615e96a66cSDavid du Colombier  * Return value is:
1625e96a66cSDavid du Colombier  *
1635e96a66cSDavid du Colombier  *	ArchFailure	some error occurred
1645e96a66cSDavid du Colombier  *	ArchSuccess	block and all children archived
1655e96a66cSDavid du Colombier  * 	ArchFaked	success, but block or children got copied
1665e96a66cSDavid du Colombier  */
1675e96a66cSDavid du Colombier enum
1685e96a66cSDavid du Colombier {
1695e96a66cSDavid du Colombier 	ArchFailure,
1705e96a66cSDavid du Colombier 	ArchSuccess,
1715e96a66cSDavid du Colombier 	ArchFaked,
1725e96a66cSDavid du Colombier };
1735e96a66cSDavid du Colombier static int
archWalk(Param * p,u32int addr,uchar type,u32int tag)1745e96a66cSDavid du Colombier archWalk(Param *p, u32int addr, uchar type, u32int tag)
1755e96a66cSDavid du Colombier {
1765e96a66cSDavid du Colombier 	int ret, i, x, psize, dsize;
1775e96a66cSDavid du Colombier 	uchar *data, score[VtScoreSize];
1785e96a66cSDavid du Colombier 	Block *b;
1795e96a66cSDavid du Colombier 	Label l;
1805e96a66cSDavid du Colombier 	Entry *e;
1815e96a66cSDavid du Colombier 	WalkPtr w;
182*d7aba6c3SDavid du Colombier 	char err[ERRMAX];
1835e96a66cSDavid du Colombier 
1845e96a66cSDavid du Colombier 	p->nvisit++;
1855e96a66cSDavid du Colombier 
1865e96a66cSDavid du Colombier 	b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0);
1875e96a66cSDavid du Colombier 	if(b == nil){
188*d7aba6c3SDavid du Colombier 		fprint(2, "archive(%ud, %#ux): cannot find block: %r\n", p->snapEpoch, addr);
189*d7aba6c3SDavid du Colombier 		rerrstr(err, sizeof err);
190*d7aba6c3SDavid du Colombier 		if(strcmp(err, ELabelMismatch) == 0){
1915e96a66cSDavid du Colombier 			/* might as well plod on so we write _something_ to Venti */
192*d7aba6c3SDavid du Colombier 			memmove(p->score, vtzeroscore, VtScoreSize);
1935e96a66cSDavid du Colombier 			return ArchFaked;
1945e96a66cSDavid du Colombier 		}
1955e96a66cSDavid du Colombier 		return ArchFailure;
1965e96a66cSDavid du Colombier 	}
1975e96a66cSDavid du Colombier 
1985e96a66cSDavid du Colombier 	if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n",
1995e96a66cSDavid du Colombier 		p->depth*2, "",  p->snapEpoch, b->addr, &b->l);
2005e96a66cSDavid du Colombier 	p->depth++;
2015e96a66cSDavid du Colombier 	if(p->depth > p->maxdepth)
2025e96a66cSDavid du Colombier 		p->maxdepth = p->depth;
2035e96a66cSDavid du Colombier 
2045e96a66cSDavid du Colombier 	data = b->data;
2055e96a66cSDavid du Colombier 	if((b->l.state&BsVenti) == 0){
2065e96a66cSDavid du Colombier 		initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize);
2075e96a66cSDavid du Colombier 		for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){
2085e96a66cSDavid du Colombier 			if(e){
2095e96a66cSDavid du Colombier 				if(!(e->flags&VtEntryActive))
2105e96a66cSDavid du Colombier 					continue;
211fe853e23SDavid du Colombier 				if((e->snap && !e->archive)
212fe853e23SDavid du Colombier 				|| (e->flags&VtEntryNoArchive)){
213fe853e23SDavid du Colombier 					if(0) fprint(2, "snap; faking %#ux\n", b->addr);
2145e96a66cSDavid du Colombier 					if(data == b->data){
2155e96a66cSDavid du Colombier 						data = copyBlock(b, p->blockSize);
2165e96a66cSDavid du Colombier 						if(data == nil){
2175e96a66cSDavid du Colombier 							ret = ArchFailure;
2185e96a66cSDavid du Colombier 							goto Out;
2195e96a66cSDavid du Colombier 						}
2205e96a66cSDavid du Colombier 						w.data = data;
2215e96a66cSDavid du Colombier 					}
222*d7aba6c3SDavid du Colombier 					memmove(e->score, vtzeroscore, VtScoreSize);
2235e96a66cSDavid du Colombier 					e->depth = 0;
2245e96a66cSDavid du Colombier 					e->size = 0;
2255e96a66cSDavid du Colombier 					e->tag = 0;
2265e96a66cSDavid du Colombier 					e->flags &= ~VtEntryLocal;
2275e96a66cSDavid du Colombier 					entryPack(e, data, w.n-1);
2285e96a66cSDavid du Colombier 					continue;
2295e96a66cSDavid du Colombier 				}
2305e96a66cSDavid du Colombier 			}
2315e96a66cSDavid du Colombier 			addr = globalToLocal(score);
2325e96a66cSDavid du Colombier 			if(addr == NilBlock)
2335e96a66cSDavid du Colombier 				continue;
2345e96a66cSDavid du Colombier 			dsize = p->dsize;
2355e96a66cSDavid du Colombier 			psize = p->psize;
2365e96a66cSDavid du Colombier 			if(e){
2375e96a66cSDavid du Colombier 				p->dsize= e->dsize;
2385e96a66cSDavid du Colombier 				p->psize = e->psize;
2395e96a66cSDavid du Colombier 			}
240*d7aba6c3SDavid du Colombier 			qunlock(&b->lk);
2415e96a66cSDavid du Colombier 			x = archWalk(p, addr, type, tag);
242*d7aba6c3SDavid du Colombier 			qlock(&b->lk);
2435e96a66cSDavid du Colombier 			if(e){
2445e96a66cSDavid du Colombier 				p->dsize = dsize;
2455e96a66cSDavid du Colombier 				p->psize = psize;
2465e96a66cSDavid du Colombier 			}
2475e96a66cSDavid du Colombier 			while(b->iostate != BioClean && b->iostate != BioDirty)
248*d7aba6c3SDavid du Colombier 				rsleep(&b->ioready);
2495e96a66cSDavid du Colombier 			switch(x){
2505e96a66cSDavid du Colombier 			case ArchFailure:
2515e96a66cSDavid du Colombier 				fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n",
2525e96a66cSDavid du Colombier 					addr, b->addr, i);
2535e96a66cSDavid du Colombier 				ret = ArchFailure;
2545e96a66cSDavid du Colombier 				goto Out;
2555e96a66cSDavid du Colombier 			case ArchFaked:
256fe853e23SDavid du Colombier 				/*
257fe853e23SDavid du Colombier 				 * When we're writing the entry for an archive directory
258fe853e23SDavid du Colombier 				 * (like /archive/2003/1215) then even if we've faked
259fe853e23SDavid du Colombier 				 * any data, record the score unconditionally.
260fe853e23SDavid du Colombier 				 * This way, we will always record the Venti score here.
261fe853e23SDavid du Colombier 				 * Otherwise, temporary data or corrupted file system
262fe853e23SDavid du Colombier 				 * would cause us to keep holding onto the on-disk
263fe853e23SDavid du Colombier 				 * copy of the archive.
264fe853e23SDavid du Colombier 				 */
265fe853e23SDavid du Colombier 				if(e==nil || !e->archive)
2665e96a66cSDavid du Colombier 				if(data == b->data){
267fe853e23SDavid du Colombier if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score);
2685e96a66cSDavid du Colombier 					data = copyBlock(b, p->blockSize);
2695e96a66cSDavid du Colombier 					if(data == nil){
2705e96a66cSDavid du Colombier 						ret = ArchFailure;
2715e96a66cSDavid du Colombier 						goto Out;
2725e96a66cSDavid du Colombier 					}
2735e96a66cSDavid du Colombier 					w.data = data;
2745e96a66cSDavid du Colombier 				}
2755e96a66cSDavid du Colombier 				/* fall through */
2765e96a66cSDavid du Colombier if(0) fprint(2, "falling\n");
2775e96a66cSDavid du Colombier 			case ArchSuccess:
2785e96a66cSDavid du Colombier 				if(e){
2795e96a66cSDavid du Colombier 					memmove(e->score, p->score, VtScoreSize);
2805e96a66cSDavid du Colombier 					e->flags &= ~VtEntryLocal;
2815e96a66cSDavid du Colombier 					entryPack(e, data, w.n-1);
2825e96a66cSDavid du Colombier 				}else
2835e96a66cSDavid du Colombier 					memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize);
2845e96a66cSDavid du Colombier 				if(data == b->data){
2855e96a66cSDavid du Colombier 					blockDirty(b);
286e569ccb5SDavid du Colombier 					/*
287e569ccb5SDavid du Colombier 					 * If b is in the active tree, then we need to note that we've
288e569ccb5SDavid du Colombier 					 * just removed addr from the active tree (replacing it with the
289e569ccb5SDavid du Colombier 					 * copy we just stored to Venti).  If addr is in other snapshots,
290e569ccb5SDavid du Colombier 					 * this will close addr but not free it, since it has a non-empty
291e569ccb5SDavid du Colombier 					 * epoch range.
292e569ccb5SDavid du Colombier 					 *
293e569ccb5SDavid du Colombier 					 * If b is in the active tree but has been copied (this can happen
294e569ccb5SDavid du Colombier 					 * if we get killed at just the right moment), then we will
295e569ccb5SDavid du Colombier 					 * mistakenly leak its kids.
296e569ccb5SDavid du Colombier 					 *
297e569ccb5SDavid du Colombier 					 * The children of an archive directory (e.g., /archive/2004/0604)
298e569ccb5SDavid du Colombier 					 * are not treated as in the active tree.
299e569ccb5SDavid du Colombier 					 */
300e569ccb5SDavid du Colombier 					if((b->l.state&BsCopied)==0 && (e==nil || e->snap==0))
301e569ccb5SDavid du Colombier 						blockRemoveLink(b, addr, p->l.type, p->l.tag, 0);
3025e96a66cSDavid du Colombier 				}
3035e96a66cSDavid du Colombier 				break;
3045e96a66cSDavid du Colombier 			}
3055e96a66cSDavid du Colombier 		}
3065e96a66cSDavid du Colombier 
3075e96a66cSDavid du Colombier 		if(!ventiSend(p->a, b, data)){
3085e96a66cSDavid du Colombier 			p->nfailsend++;
3095e96a66cSDavid du Colombier 			ret = ArchFailure;
3105e96a66cSDavid du Colombier 			goto Out;
3115e96a66cSDavid du Colombier 		}
3125e96a66cSDavid du Colombier 		p->nsend++;
3135e96a66cSDavid du Colombier 		if(data != b->data)
3145e96a66cSDavid du Colombier 			p->nfake++;
3155e96a66cSDavid du Colombier 		if(data == b->data){	/* not faking it, so update state */
3165e96a66cSDavid du Colombier 			p->nreal++;
3175e96a66cSDavid du Colombier 			l = b->l;
3185e96a66cSDavid du Colombier 			l.state |= BsVenti;
319e569ccb5SDavid du Colombier 			if(!blockSetLabel(b, &l, 0)){
3205e96a66cSDavid du Colombier 				ret = ArchFailure;
3215e96a66cSDavid du Colombier 				goto Out;
3225e96a66cSDavid du Colombier 			}
3235e96a66cSDavid du Colombier 		}
3245e96a66cSDavid du Colombier 	}
3255e96a66cSDavid du Colombier 
3265e96a66cSDavid du Colombier 	shaBlock(p->score, b, data, p->blockSize);
3275e96a66cSDavid du Colombier if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data);
3285e96a66cSDavid du Colombier 	ret = data!=b->data ? ArchFaked : ArchSuccess;
3295e96a66cSDavid du Colombier 	p->l = b->l;
3305e96a66cSDavid du Colombier Out:
3315e96a66cSDavid du Colombier 	if(data != b->data)
332*d7aba6c3SDavid du Colombier 		vtfree(data);
3335e96a66cSDavid du Colombier 	p->depth--;
3345e96a66cSDavid du Colombier 	blockPut(b);
3355e96a66cSDavid du Colombier 	return ret;
3365e96a66cSDavid du Colombier }
3375e96a66cSDavid du Colombier 
3385e96a66cSDavid du Colombier static void
archThread(void * v)3395e96a66cSDavid du Colombier archThread(void *v)
3405e96a66cSDavid du Colombier {
3415e96a66cSDavid du Colombier 	Arch *a = v;
3425e96a66cSDavid du Colombier 	Block *b;
3435e96a66cSDavid du Colombier 	Param p;
3445e96a66cSDavid du Colombier 	Super super;
3455e96a66cSDavid du Colombier 	int ret;
3465e96a66cSDavid du Colombier 	u32int addr;
3475e96a66cSDavid du Colombier 	uchar rbuf[VtRootSize];
3485e96a66cSDavid du Colombier 	VtRoot root;
3495e96a66cSDavid du Colombier 
350*d7aba6c3SDavid du Colombier 	threadsetname("arch");
3515e96a66cSDavid du Colombier 
3525e96a66cSDavid du Colombier 	for(;;){
3535e96a66cSDavid du Colombier 		/* look for work */
354*d7aba6c3SDavid du Colombier 		wlock(&a->fs->elk);
3555e96a66cSDavid du Colombier 		b = superGet(a->c, &super);
3565e96a66cSDavid du Colombier 		if(b == nil){
357*d7aba6c3SDavid du Colombier 			wunlock(&a->fs->elk);
358*d7aba6c3SDavid du Colombier 			fprint(2, "archThread: superGet: %r\n");
3595e96a66cSDavid du Colombier 			sleep(60*1000);
3605e96a66cSDavid du Colombier 			continue;
3615e96a66cSDavid du Colombier 		}
3625e96a66cSDavid du Colombier 		addr = super.next;
3635e96a66cSDavid du Colombier 		if(addr != NilBlock && super.current == NilBlock){
3645e96a66cSDavid du Colombier 			super.current = addr;
3655e96a66cSDavid du Colombier 			super.next = NilBlock;
3665e96a66cSDavid du Colombier 			superPack(&super, b->data);
3675e96a66cSDavid du Colombier 			blockDirty(b);
3685e96a66cSDavid du Colombier 		}else
3695e96a66cSDavid du Colombier 			addr = super.current;
3705e96a66cSDavid du Colombier 		blockPut(b);
371*d7aba6c3SDavid du Colombier 		wunlock(&a->fs->elk);
3725e96a66cSDavid du Colombier 
3735e96a66cSDavid du Colombier 		if(addr == NilBlock){
3745e96a66cSDavid du Colombier 			/* wait for work */
375*d7aba6c3SDavid du Colombier 			qlock(&a->lk);
376*d7aba6c3SDavid du Colombier 			rsleep(&a->starve);
377*d7aba6c3SDavid du Colombier 			if(a->die.l != nil)
3785e96a66cSDavid du Colombier 				goto Done;
379*d7aba6c3SDavid du Colombier 			qunlock(&a->lk);
3805e96a66cSDavid du Colombier 			continue;
3815e96a66cSDavid du Colombier 		}
3825e96a66cSDavid du Colombier 
3835e96a66cSDavid du Colombier sleep(10*1000);	/* window of opportunity to provoke races */
3845e96a66cSDavid du Colombier 
3855e96a66cSDavid du Colombier 		/* do work */
3865e96a66cSDavid du Colombier 		memset(&p, 0, sizeof p);
3875e96a66cSDavid du Colombier 		p.blockSize = a->blockSize;
3885e96a66cSDavid du Colombier 		p.dsize = 3*VtEntrySize;	/* root has three Entries */
3895e96a66cSDavid du Colombier 		p.c = a->c;
3905e96a66cSDavid du Colombier 		p.a = a;
3915e96a66cSDavid du Colombier 
3925e96a66cSDavid du Colombier 		ret = archWalk(&p, addr, BtDir, RootTag);
3935e96a66cSDavid du Colombier 		switch(ret){
3945e96a66cSDavid du Colombier 		default:
3955e96a66cSDavid du Colombier 			abort();
3965e96a66cSDavid du Colombier 		case ArchFailure:
397*d7aba6c3SDavid du Colombier 			fprint(2, "archiveBlock %#ux: %r\n", addr);
3985e96a66cSDavid du Colombier 			sleep(60*1000);
3995e96a66cSDavid du Colombier 			continue;
4005e96a66cSDavid du Colombier 		case ArchSuccess:
4015e96a66cSDavid du Colombier 		case ArchFaked:
4025e96a66cSDavid du Colombier 			break;
4035e96a66cSDavid du Colombier 		}
4045e96a66cSDavid du Colombier 
4055e96a66cSDavid du Colombier 		if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud"
4065e96a66cSDavid du Colombier 			" send %ud nfailsend %ud nvisit %ud"
4075e96a66cSDavid du Colombier 			" nreclaim %ud nfake %ud nreal %ud\n",
4085e96a66cSDavid du Colombier 			addr, p.maxdepth, p.nfixed,
4095e96a66cSDavid du Colombier 			p.nsend, p.nfailsend, p.nvisit,
4105e96a66cSDavid du Colombier 			p.nreclaim, p.nfake, p.nreal);
4115e96a66cSDavid du Colombier 		if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize);
4125e96a66cSDavid du Colombier 
4135e96a66cSDavid du Colombier 		/* tie up vac root */
4145e96a66cSDavid du Colombier 		memset(&root, 0, sizeof root);
41534e04225SDavid du Colombier 		strecpy(root.type, root.type+sizeof root.type, "vac");
4165e96a66cSDavid du Colombier 		strecpy(root.name, root.name+sizeof root.name, "fossil");
4175e96a66cSDavid du Colombier 		memmove(root.score, p.score, VtScoreSize);
4185e96a66cSDavid du Colombier 		memmove(root.prev, super.last, VtScoreSize);
419*d7aba6c3SDavid du Colombier 		root.blocksize = a->blockSize;
420*d7aba6c3SDavid du Colombier 		vtrootpack(&root, rbuf);
421*d7aba6c3SDavid du Colombier 		if(vtwrite(a->z, p.score, VtRootType, rbuf, VtRootSize) < 0
422*d7aba6c3SDavid du Colombier 		|| vtsha1check(p.score, rbuf, VtRootSize) < 0){
423*d7aba6c3SDavid du Colombier 			fprint(2, "vtWriteBlock %#ux: %r\n", addr);
4245e96a66cSDavid du Colombier 			sleep(60*1000);
4255e96a66cSDavid du Colombier 			continue;
4265e96a66cSDavid du Colombier 		}
4275e96a66cSDavid du Colombier 
4285e96a66cSDavid du Colombier 		/* record success */
429*d7aba6c3SDavid du Colombier 		wlock(&a->fs->elk);
4305e96a66cSDavid du Colombier 		b = superGet(a->c, &super);
4315e96a66cSDavid du Colombier 		if(b == nil){
432*d7aba6c3SDavid du Colombier 			wunlock(&a->fs->elk);
433*d7aba6c3SDavid du Colombier 			fprint(2, "archThread: superGet: %r\n");
4345e96a66cSDavid du Colombier 			sleep(60*1000);
4355e96a66cSDavid du Colombier 			continue;
4365e96a66cSDavid du Colombier 		}
4375e96a66cSDavid du Colombier 		super.current = NilBlock;
4385e96a66cSDavid du Colombier 		memmove(super.last, p.score, VtScoreSize);
4395e96a66cSDavid du Colombier 		superPack(&super, b->data);
4405e96a66cSDavid du Colombier 		blockDirty(b);
4415e96a66cSDavid du Colombier 		blockPut(b);
442*d7aba6c3SDavid du Colombier 		wunlock(&a->fs->elk);
4435e96a66cSDavid du Colombier 
4445e96a66cSDavid du Colombier 		consPrint("archive vac:%V\n", p.score);
4455e96a66cSDavid du Colombier 	}
4465e96a66cSDavid du Colombier 
4475e96a66cSDavid du Colombier Done:
4485e96a66cSDavid du Colombier 	a->ref--;
449*d7aba6c3SDavid du Colombier 	rwakeup(&a->die);
450*d7aba6c3SDavid du Colombier 	qunlock(&a->lk);
4515e96a66cSDavid du Colombier }
4525e96a66cSDavid du Colombier 
4535e96a66cSDavid du Colombier void
archKick(Arch * a)4545e96a66cSDavid du Colombier archKick(Arch *a)
4555e96a66cSDavid du Colombier {
4565e96a66cSDavid du Colombier 	if(a == nil){
4575e96a66cSDavid du Colombier 		fprint(2, "warning: archKick nil\n");
4585e96a66cSDavid du Colombier 		return;
4595e96a66cSDavid du Colombier 	}
460*d7aba6c3SDavid du Colombier 	qlock(&a->lk);
461*d7aba6c3SDavid du Colombier 	rwakeup(&a->starve);
462*d7aba6c3SDavid du Colombier 	qunlock(&a->lk);
4635e96a66cSDavid du Colombier }
464