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;
235e96a66cSDavid du Colombier VtSession *z;
245e96a66cSDavid du Colombier
255e96a66cSDavid du Colombier VtLock *lk;
265e96a66cSDavid du Colombier VtRendez *starve;
275e96a66cSDavid du Colombier VtRendez *die;
285e96a66cSDavid du Colombier };
295e96a66cSDavid du Colombier
305e96a66cSDavid du Colombier Arch *
archInit(Cache * c,Disk * disk,Fs * fs,VtSession * z)315e96a66cSDavid du Colombier archInit(Cache *c, Disk *disk, Fs *fs, VtSession *z)
325e96a66cSDavid du Colombier {
335e96a66cSDavid du Colombier Arch *a;
345e96a66cSDavid du Colombier
355e96a66cSDavid du Colombier a = vtMemAllocZ(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);
415e96a66cSDavid du Colombier a->lk = vtLockAlloc();
425e96a66cSDavid du Colombier a->starve = vtRendezAlloc(a->lk);
435e96a66cSDavid du Colombier
445e96a66cSDavid du Colombier a->ref = 2;
455e96a66cSDavid du Colombier vtThread(archThread, a);
465e96a66cSDavid du Colombier
475e96a66cSDavid du Colombier return a;
485e96a66cSDavid du Colombier }
495e96a66cSDavid du Colombier
505e96a66cSDavid du Colombier void
archFree(Arch * a)515e96a66cSDavid du Colombier archFree(Arch *a)
525e96a66cSDavid du Colombier {
535e96a66cSDavid du Colombier /* kill slave */
545e96a66cSDavid du Colombier vtLock(a->lk);
555e96a66cSDavid du Colombier a->die = vtRendezAlloc(a->lk);
565e96a66cSDavid du Colombier vtWakeup(a->starve);
575e96a66cSDavid du Colombier while(a->ref > 1)
585e96a66cSDavid du Colombier vtSleep(a->die);
595e96a66cSDavid du Colombier vtUnlock(a->lk);
605e96a66cSDavid du Colombier vtRendezFree(a->starve);
615e96a66cSDavid du Colombier vtRendezFree(a->die);
625e96a66cSDavid du Colombier vtLockFree(a->lk);
635e96a66cSDavid du Colombier vtMemFree(a);
645e96a66cSDavid du Colombier }
655e96a66cSDavid du Colombier
665e96a66cSDavid du Colombier static int
ventiSend(Arch * a,Block * b,uchar * data)675e96a66cSDavid du Colombier ventiSend(Arch *a, Block *b, uchar *data)
685e96a66cSDavid du Colombier {
695e96a66cSDavid du Colombier uint n;
705e96a66cSDavid du Colombier uchar score[VtScoreSize];
715e96a66cSDavid du Colombier
725e96a66cSDavid du Colombier if(DEBUG > 1)
735e96a66cSDavid du Colombier fprint(2, "ventiSend: sending %#ux %L to venti\n", b->addr, &b->l);
745e96a66cSDavid du Colombier n = vtZeroTruncate(vtType[b->l.type], data, a->blockSize);
755e96a66cSDavid du Colombier if(DEBUG > 1)
765e96a66cSDavid du Colombier fprint(2, "ventiSend: truncate %d to %d\n", a->blockSize, n);
775e96a66cSDavid du Colombier if(!vtWrite(a->z, score, vtType[b->l.type], data, n)){
785e96a66cSDavid du Colombier fprint(2, "ventiSend: vtWrite block %#ux failed: %R\n", b->addr);
795e96a66cSDavid du Colombier return 0;
805e96a66cSDavid du Colombier }
815e96a66cSDavid du Colombier if(!vtSha1Check(score, data, n)){
825e96a66cSDavid du Colombier uchar score2[VtScoreSize];
835e96a66cSDavid du Colombier vtSha1(score2, data, n);
845e96a66cSDavid du Colombier fprint(2, "ventiSend: vtWrite block %#ux failed vtSha1Check %V %V\n",
855e96a66cSDavid du Colombier b->addr, score, score2);
865e96a66cSDavid du Colombier return 0;
875e96a66cSDavid du Colombier }
885e96a66cSDavid du Colombier if(!vtSync(a->z))
895e96a66cSDavid du Colombier return 0;
905e96a66cSDavid du Colombier return 1;
915e96a66cSDavid du Colombier }
925e96a66cSDavid du Colombier
935e96a66cSDavid du Colombier /*
945e96a66cSDavid du Colombier * parameters for recursion; there are so many,
955e96a66cSDavid du Colombier * and some only change occasionally. this is
965e96a66cSDavid du Colombier * easier than spelling things out at each call.
975e96a66cSDavid du Colombier */
985e96a66cSDavid du Colombier typedef struct Param Param;
995e96a66cSDavid du Colombier struct Param
1005e96a66cSDavid du Colombier {
1015e96a66cSDavid du Colombier /* these never change */
1025e96a66cSDavid du Colombier uint snapEpoch; /* epoch for snapshot being archived */
1035e96a66cSDavid du Colombier uint blockSize;
1045e96a66cSDavid du Colombier Cache *c;
1055e96a66cSDavid du Colombier Arch *a;
1065e96a66cSDavid du Colombier
1075e96a66cSDavid du Colombier /* changes on every call */
1085e96a66cSDavid du Colombier uint depth;
1095e96a66cSDavid du Colombier
1105e96a66cSDavid du Colombier /* statistics */
1115e96a66cSDavid du Colombier uint nfixed;
1125e96a66cSDavid du Colombier uint nsend;
1135e96a66cSDavid du Colombier uint nvisit;
1145e96a66cSDavid du Colombier uint nfailsend;
1155e96a66cSDavid du Colombier uint maxdepth;
1165e96a66cSDavid du Colombier uint nreclaim;
1175e96a66cSDavid du Colombier uint nfake;
1185e96a66cSDavid du Colombier uint nreal;
1195e96a66cSDavid du Colombier
1205e96a66cSDavid du Colombier /* these occasionally change (must save old values and put back) */
1215e96a66cSDavid du Colombier uint dsize;
1225e96a66cSDavid du Colombier uint psize;
1235e96a66cSDavid du Colombier
1245e96a66cSDavid du Colombier /* return value; avoids using stack space */
1255e96a66cSDavid du Colombier Label l;
1265e96a66cSDavid du Colombier uchar score[VtScoreSize];
1275e96a66cSDavid du Colombier };
1285e96a66cSDavid du Colombier
1295e96a66cSDavid du Colombier static void
shaBlock(uchar score[VtScoreSize],Block * b,uchar * data,uint bsize)1305e96a66cSDavid du Colombier shaBlock(uchar score[VtScoreSize], Block *b, uchar *data, uint bsize)
1315e96a66cSDavid du Colombier {
1325e96a66cSDavid du Colombier vtSha1(score, data, vtZeroTruncate(vtType[b->l.type], data, bsize));
1335e96a66cSDavid du Colombier }
1345e96a66cSDavid du Colombier
1355e96a66cSDavid du Colombier static uint
etype(Entry * e)1365e96a66cSDavid du Colombier etype(Entry *e)
1375e96a66cSDavid du Colombier {
1385e96a66cSDavid du Colombier uint t;
1395e96a66cSDavid du Colombier
1405e96a66cSDavid du Colombier if(e->flags&VtEntryDir)
1415e96a66cSDavid du Colombier t = BtDir;
1425e96a66cSDavid du Colombier else
1435e96a66cSDavid du Colombier t = BtData;
1445e96a66cSDavid du Colombier return t+e->depth;
1455e96a66cSDavid du Colombier }
1465e96a66cSDavid du Colombier
1475e96a66cSDavid du Colombier static uchar*
copyBlock(Block * b,u32int blockSize)1485e96a66cSDavid du Colombier copyBlock(Block *b, u32int blockSize)
1495e96a66cSDavid du Colombier {
1505e96a66cSDavid du Colombier uchar *data;
1515e96a66cSDavid du Colombier
1525e96a66cSDavid du Colombier data = vtMemAlloc(blockSize);
1535e96a66cSDavid du Colombier if(data == nil)
1545e96a66cSDavid du Colombier return nil;
1555e96a66cSDavid du Colombier memmove(data, b->data, blockSize);
1565e96a66cSDavid du Colombier return data;
1575e96a66cSDavid du Colombier }
1585e96a66cSDavid du Colombier
1595e96a66cSDavid du Colombier /*
1605e96a66cSDavid du Colombier * Walk over the block tree, archiving it to Venti.
1615e96a66cSDavid du Colombier *
1625e96a66cSDavid du Colombier * We don't archive the snapshots. Instead we zero the
163e569ccb5SDavid du Colombier * entries in a temporary copy of the block and archive that.
1645e96a66cSDavid du Colombier *
1655e96a66cSDavid du Colombier * Return value is:
1665e96a66cSDavid du Colombier *
1675e96a66cSDavid du Colombier * ArchFailure some error occurred
1685e96a66cSDavid du Colombier * ArchSuccess block and all children archived
1695e96a66cSDavid du Colombier * ArchFaked success, but block or children got copied
1705e96a66cSDavid du Colombier */
1715e96a66cSDavid du Colombier enum
1725e96a66cSDavid du Colombier {
1735e96a66cSDavid du Colombier ArchFailure,
1745e96a66cSDavid du Colombier ArchSuccess,
1755e96a66cSDavid du Colombier ArchFaked,
1765e96a66cSDavid du Colombier };
1775e96a66cSDavid du Colombier static int
archWalk(Param * p,u32int addr,uchar type,u32int tag)1785e96a66cSDavid du Colombier archWalk(Param *p, u32int addr, uchar type, u32int tag)
1795e96a66cSDavid du Colombier {
1805e96a66cSDavid du Colombier int ret, i, x, psize, dsize;
1815e96a66cSDavid du Colombier uchar *data, score[VtScoreSize];
1825e96a66cSDavid du Colombier Block *b;
1835e96a66cSDavid du Colombier Label l;
1845e96a66cSDavid du Colombier Entry *e;
1855e96a66cSDavid du Colombier WalkPtr w;
1865e96a66cSDavid du Colombier
1875e96a66cSDavid du Colombier p->nvisit++;
1885e96a66cSDavid du Colombier
1895e96a66cSDavid du Colombier b = cacheLocalData(p->c, addr, type, tag, OReadWrite,0);
1905e96a66cSDavid du Colombier if(b == nil){
1915e96a66cSDavid du Colombier fprint(2, "archive(%ud, %#ux): cannot find block: %R\n", p->snapEpoch, addr);
1925e96a66cSDavid du Colombier if(strcmp(vtGetError(), ELabelMismatch) == 0){
1935e96a66cSDavid du Colombier /* might as well plod on so we write _something_ to Venti */
1945e96a66cSDavid du Colombier memmove(p->score, vtZeroScore, VtScoreSize);
1955e96a66cSDavid du Colombier return ArchFaked;
1965e96a66cSDavid du Colombier }
1975e96a66cSDavid du Colombier return ArchFailure;
1985e96a66cSDavid du Colombier }
1995e96a66cSDavid du Colombier
2005e96a66cSDavid du Colombier if(DEBUG) fprint(2, "%*sarchive(%ud, %#ux): block label %L\n",
2015e96a66cSDavid du Colombier p->depth*2, "", p->snapEpoch, b->addr, &b->l);
2025e96a66cSDavid du Colombier p->depth++;
2035e96a66cSDavid du Colombier if(p->depth > p->maxdepth)
2045e96a66cSDavid du Colombier p->maxdepth = p->depth;
2055e96a66cSDavid du Colombier
2065e96a66cSDavid du Colombier data = b->data;
2075e96a66cSDavid du Colombier if((b->l.state&BsVenti) == 0){
2085e96a66cSDavid du Colombier initWalk(&w, b, b->l.type==BtDir ? p->dsize : p->psize);
2095e96a66cSDavid du Colombier for(i=0; nextWalk(&w, score, &type, &tag, &e); i++){
2105e96a66cSDavid du Colombier if(e){
2115e96a66cSDavid du Colombier if(!(e->flags&VtEntryActive))
2125e96a66cSDavid du Colombier continue;
213fe853e23SDavid du Colombier if((e->snap && !e->archive)
214fe853e23SDavid du Colombier || (e->flags&VtEntryNoArchive)){
215fe853e23SDavid du Colombier if(0) fprint(2, "snap; faking %#ux\n", b->addr);
2165e96a66cSDavid du Colombier if(data == b->data){
2175e96a66cSDavid du Colombier data = copyBlock(b, p->blockSize);
2185e96a66cSDavid du Colombier if(data == nil){
2195e96a66cSDavid du Colombier ret = ArchFailure;
2205e96a66cSDavid du Colombier goto Out;
2215e96a66cSDavid du Colombier }
2225e96a66cSDavid du Colombier w.data = data;
2235e96a66cSDavid du Colombier }
2245e96a66cSDavid du Colombier memmove(e->score, vtZeroScore, VtScoreSize);
2255e96a66cSDavid du Colombier e->depth = 0;
2265e96a66cSDavid du Colombier e->size = 0;
2275e96a66cSDavid du Colombier e->tag = 0;
2285e96a66cSDavid du Colombier e->flags &= ~VtEntryLocal;
2295e96a66cSDavid du Colombier entryPack(e, data, w.n-1);
2305e96a66cSDavid du Colombier continue;
2315e96a66cSDavid du Colombier }
2325e96a66cSDavid du Colombier }
2335e96a66cSDavid du Colombier addr = globalToLocal(score);
2345e96a66cSDavid du Colombier if(addr == NilBlock)
2355e96a66cSDavid du Colombier continue;
2365e96a66cSDavid du Colombier dsize = p->dsize;
2375e96a66cSDavid du Colombier psize = p->psize;
2385e96a66cSDavid du Colombier if(e){
2395e96a66cSDavid du Colombier p->dsize= e->dsize;
2405e96a66cSDavid du Colombier p->psize = e->psize;
2415e96a66cSDavid du Colombier }
2425e96a66cSDavid du Colombier vtUnlock(b->lk);
2435e96a66cSDavid du Colombier x = archWalk(p, addr, type, tag);
2445e96a66cSDavid du Colombier vtLock(b->lk);
2455e96a66cSDavid du Colombier if(e){
2465e96a66cSDavid du Colombier p->dsize = dsize;
2475e96a66cSDavid du Colombier p->psize = psize;
2485e96a66cSDavid du Colombier }
2495e96a66cSDavid du Colombier while(b->iostate != BioClean && b->iostate != BioDirty)
2505e96a66cSDavid du Colombier vtSleep(b->ioready);
2515e96a66cSDavid du Colombier switch(x){
2525e96a66cSDavid du Colombier case ArchFailure:
2535e96a66cSDavid du Colombier fprint(2, "archWalk %#ux failed; ptr is in %#ux offset %d\n",
2545e96a66cSDavid du Colombier addr, b->addr, i);
2555e96a66cSDavid du Colombier ret = ArchFailure;
2565e96a66cSDavid du Colombier goto Out;
2575e96a66cSDavid du Colombier case ArchFaked:
258fe853e23SDavid du Colombier /*
259fe853e23SDavid du Colombier * When we're writing the entry for an archive directory
260fe853e23SDavid du Colombier * (like /archive/2003/1215) then even if we've faked
261fe853e23SDavid du Colombier * any data, record the score unconditionally.
262fe853e23SDavid du Colombier * This way, we will always record the Venti score here.
263fe853e23SDavid du Colombier * Otherwise, temporary data or corrupted file system
264fe853e23SDavid du Colombier * would cause us to keep holding onto the on-disk
265fe853e23SDavid du Colombier * copy of the archive.
266fe853e23SDavid du Colombier */
267fe853e23SDavid du Colombier if(e==nil || !e->archive)
2685e96a66cSDavid du Colombier if(data == b->data){
269fe853e23SDavid du Colombier if(0) fprint(2, "faked %#ux, faking %#ux (%V)\n", addr, b->addr, p->score);
2705e96a66cSDavid du Colombier data = copyBlock(b, p->blockSize);
2715e96a66cSDavid du Colombier if(data == nil){
2725e96a66cSDavid du Colombier ret = ArchFailure;
2735e96a66cSDavid du Colombier goto Out;
2745e96a66cSDavid du Colombier }
2755e96a66cSDavid du Colombier w.data = data;
2765e96a66cSDavid du Colombier }
2775e96a66cSDavid du Colombier /* fall through */
2785e96a66cSDavid du Colombier if(0) fprint(2, "falling\n");
2795e96a66cSDavid du Colombier case ArchSuccess:
2805e96a66cSDavid du Colombier if(e){
2815e96a66cSDavid du Colombier memmove(e->score, p->score, VtScoreSize);
2825e96a66cSDavid du Colombier e->flags &= ~VtEntryLocal;
2835e96a66cSDavid du Colombier entryPack(e, data, w.n-1);
2845e96a66cSDavid du Colombier }else
2855e96a66cSDavid du Colombier memmove(data+(w.n-1)*VtScoreSize, p->score, VtScoreSize);
2865e96a66cSDavid du Colombier if(data == b->data){
2875e96a66cSDavid du Colombier blockDirty(b);
288e569ccb5SDavid du Colombier /*
289e569ccb5SDavid du Colombier * If b is in the active tree, then we need to note that we've
290e569ccb5SDavid du Colombier * just removed addr from the active tree (replacing it with the
291e569ccb5SDavid du Colombier * copy we just stored to Venti). If addr is in other snapshots,
292e569ccb5SDavid du Colombier * this will close addr but not free it, since it has a non-empty
293e569ccb5SDavid du Colombier * epoch range.
294e569ccb5SDavid du Colombier *
295e569ccb5SDavid du Colombier * If b is in the active tree but has been copied (this can happen
296e569ccb5SDavid du Colombier * if we get killed at just the right moment), then we will
297e569ccb5SDavid du Colombier * mistakenly leak its kids.
298e569ccb5SDavid du Colombier *
299e569ccb5SDavid du Colombier * The children of an archive directory (e.g., /archive/2004/0604)
300e569ccb5SDavid du Colombier * are not treated as in the active tree.
301e569ccb5SDavid du Colombier */
302e569ccb5SDavid du Colombier if((b->l.state&BsCopied)==0 && (e==nil || e->snap==0))
303e569ccb5SDavid du Colombier blockRemoveLink(b, addr, p->l.type, p->l.tag, 0);
3045e96a66cSDavid du Colombier }
3055e96a66cSDavid du Colombier break;
3065e96a66cSDavid du Colombier }
3075e96a66cSDavid du Colombier }
3085e96a66cSDavid du Colombier
3095e96a66cSDavid du Colombier if(!ventiSend(p->a, b, data)){
3105e96a66cSDavid du Colombier p->nfailsend++;
3115e96a66cSDavid du Colombier ret = ArchFailure;
3125e96a66cSDavid du Colombier goto Out;
3135e96a66cSDavid du Colombier }
3145e96a66cSDavid du Colombier p->nsend++;
3155e96a66cSDavid du Colombier if(data != b->data)
3165e96a66cSDavid du Colombier p->nfake++;
3175e96a66cSDavid du Colombier if(data == b->data){ /* not faking it, so update state */
3185e96a66cSDavid du Colombier p->nreal++;
3195e96a66cSDavid du Colombier l = b->l;
3205e96a66cSDavid du Colombier l.state |= BsVenti;
321e569ccb5SDavid du Colombier if(!blockSetLabel(b, &l, 0)){
3225e96a66cSDavid du Colombier ret = ArchFailure;
3235e96a66cSDavid du Colombier goto Out;
3245e96a66cSDavid du Colombier }
3255e96a66cSDavid du Colombier }
3265e96a66cSDavid du Colombier }
3275e96a66cSDavid du Colombier
3285e96a66cSDavid du Colombier shaBlock(p->score, b, data, p->blockSize);
3295e96a66cSDavid du Colombier if(0) fprint(2, "ventisend %V %p %p %p\n", p->score, data, b->data, w.data);
3305e96a66cSDavid du Colombier ret = data!=b->data ? ArchFaked : ArchSuccess;
3315e96a66cSDavid du Colombier p->l = b->l;
3325e96a66cSDavid du Colombier Out:
3335e96a66cSDavid du Colombier if(data != b->data)
3345e96a66cSDavid du Colombier vtMemFree(data);
3355e96a66cSDavid du Colombier p->depth--;
3365e96a66cSDavid du Colombier blockPut(b);
3375e96a66cSDavid du Colombier return ret;
3385e96a66cSDavid du Colombier }
3395e96a66cSDavid du Colombier
3405e96a66cSDavid du Colombier static void
archThread(void * v)3415e96a66cSDavid du Colombier archThread(void *v)
3425e96a66cSDavid du Colombier {
3435e96a66cSDavid du Colombier Arch *a = v;
3445e96a66cSDavid du Colombier Block *b;
3455e96a66cSDavid du Colombier Param p;
3465e96a66cSDavid du Colombier Super super;
3475e96a66cSDavid du Colombier int ret;
3485e96a66cSDavid du Colombier u32int addr;
3495e96a66cSDavid du Colombier uchar rbuf[VtRootSize];
3505e96a66cSDavid du Colombier VtRoot root;
3515e96a66cSDavid du Colombier
3525e96a66cSDavid du Colombier vtThreadSetName("arch");
3535e96a66cSDavid du Colombier
3545e96a66cSDavid du Colombier for(;;){
3555e96a66cSDavid du Colombier /* look for work */
3565e96a66cSDavid du Colombier vtLock(a->fs->elk);
3575e96a66cSDavid du Colombier b = superGet(a->c, &super);
3585e96a66cSDavid du Colombier if(b == nil){
3595e96a66cSDavid du Colombier vtUnlock(a->fs->elk);
360*aef37788SDavid du Colombier fprint(2, "archThread: superGet: %R\n");
3615e96a66cSDavid du Colombier sleep(60*1000);
3625e96a66cSDavid du Colombier continue;
3635e96a66cSDavid du Colombier }
3645e96a66cSDavid du Colombier addr = super.next;
3655e96a66cSDavid du Colombier if(addr != NilBlock && super.current == NilBlock){
3665e96a66cSDavid du Colombier super.current = addr;
3675e96a66cSDavid du Colombier super.next = NilBlock;
3685e96a66cSDavid du Colombier superPack(&super, b->data);
3695e96a66cSDavid du Colombier blockDirty(b);
3705e96a66cSDavid du Colombier }else
3715e96a66cSDavid du Colombier addr = super.current;
3725e96a66cSDavid du Colombier blockPut(b);
3735e96a66cSDavid du Colombier vtUnlock(a->fs->elk);
3745e96a66cSDavid du Colombier
3755e96a66cSDavid du Colombier if(addr == NilBlock){
3765e96a66cSDavid du Colombier /* wait for work */
3775e96a66cSDavid du Colombier vtLock(a->lk);
3785e96a66cSDavid du Colombier vtSleep(a->starve);
3795e96a66cSDavid du Colombier if(a->die != nil)
3805e96a66cSDavid du Colombier goto Done;
3815e96a66cSDavid du Colombier vtUnlock(a->lk);
3825e96a66cSDavid du Colombier continue;
3835e96a66cSDavid du Colombier }
3845e96a66cSDavid du Colombier
3855e96a66cSDavid du Colombier sleep(10*1000); /* window of opportunity to provoke races */
3865e96a66cSDavid du Colombier
3875e96a66cSDavid du Colombier /* do work */
3885e96a66cSDavid du Colombier memset(&p, 0, sizeof p);
3895e96a66cSDavid du Colombier p.blockSize = a->blockSize;
3905e96a66cSDavid du Colombier p.dsize = 3*VtEntrySize; /* root has three Entries */
3915e96a66cSDavid du Colombier p.c = a->c;
3925e96a66cSDavid du Colombier p.a = a;
3935e96a66cSDavid du Colombier
3945e96a66cSDavid du Colombier ret = archWalk(&p, addr, BtDir, RootTag);
3955e96a66cSDavid du Colombier switch(ret){
3965e96a66cSDavid du Colombier default:
3975e96a66cSDavid du Colombier abort();
3985e96a66cSDavid du Colombier case ArchFailure:
3995e96a66cSDavid du Colombier fprint(2, "archiveBlock %#ux: %R\n", addr);
4005e96a66cSDavid du Colombier sleep(60*1000);
4015e96a66cSDavid du Colombier continue;
4025e96a66cSDavid du Colombier case ArchSuccess:
4035e96a66cSDavid du Colombier case ArchFaked:
4045e96a66cSDavid du Colombier break;
4055e96a66cSDavid du Colombier }
4065e96a66cSDavid du Colombier
4075e96a66cSDavid du Colombier if(0) fprint(2, "archiveSnapshot 0x%#ux: maxdepth %ud nfixed %ud"
4085e96a66cSDavid du Colombier " send %ud nfailsend %ud nvisit %ud"
4095e96a66cSDavid du Colombier " nreclaim %ud nfake %ud nreal %ud\n",
4105e96a66cSDavid du Colombier addr, p.maxdepth, p.nfixed,
4115e96a66cSDavid du Colombier p.nsend, p.nfailsend, p.nvisit,
4125e96a66cSDavid du Colombier p.nreclaim, p.nfake, p.nreal);
4135e96a66cSDavid du Colombier if(0) fprint(2, "archiveBlock %V (%ud)\n", p.score, p.blockSize);
4145e96a66cSDavid du Colombier
4155e96a66cSDavid du Colombier /* tie up vac root */
4165e96a66cSDavid du Colombier memset(&root, 0, sizeof root);
4175e96a66cSDavid du Colombier root.version = VtRootVersion;
41834e04225SDavid du Colombier strecpy(root.type, root.type+sizeof root.type, "vac");
4195e96a66cSDavid du Colombier strecpy(root.name, root.name+sizeof root.name, "fossil");
4205e96a66cSDavid du Colombier memmove(root.score, p.score, VtScoreSize);
4215e96a66cSDavid du Colombier memmove(root.prev, super.last, VtScoreSize);
4225e96a66cSDavid du Colombier root.blockSize = a->blockSize;
4235e96a66cSDavid du Colombier vtRootPack(&root, rbuf);
4245e96a66cSDavid du Colombier if(!vtWrite(a->z, p.score, VtRootType, rbuf, VtRootSize)
4255e96a66cSDavid du Colombier || !vtSha1Check(p.score, rbuf, VtRootSize)){
4265e96a66cSDavid du Colombier fprint(2, "vtWriteBlock %#ux: %R\n", addr);
4275e96a66cSDavid du Colombier sleep(60*1000);
4285e96a66cSDavid du Colombier continue;
4295e96a66cSDavid du Colombier }
4305e96a66cSDavid du Colombier
4315e96a66cSDavid du Colombier /* record success */
4325e96a66cSDavid du Colombier vtLock(a->fs->elk);
4335e96a66cSDavid du Colombier b = superGet(a->c, &super);
4345e96a66cSDavid du Colombier if(b == nil){
4355e96a66cSDavid du Colombier vtUnlock(a->fs->elk);
436*aef37788SDavid du Colombier fprint(2, "archThread: superGet: %R\n");
4375e96a66cSDavid du Colombier sleep(60*1000);
4385e96a66cSDavid du Colombier continue;
4395e96a66cSDavid du Colombier }
4405e96a66cSDavid du Colombier super.current = NilBlock;
4415e96a66cSDavid du Colombier memmove(super.last, p.score, VtScoreSize);
4425e96a66cSDavid du Colombier superPack(&super, b->data);
4435e96a66cSDavid du Colombier blockDirty(b);
4445e96a66cSDavid du Colombier blockPut(b);
4455e96a66cSDavid du Colombier vtUnlock(a->fs->elk);
4465e96a66cSDavid du Colombier
4475e96a66cSDavid du Colombier consPrint("archive vac:%V\n", p.score);
4485e96a66cSDavid du Colombier }
4495e96a66cSDavid du Colombier
4505e96a66cSDavid du Colombier Done:
4515e96a66cSDavid du Colombier a->ref--;
4525e96a66cSDavid du Colombier vtWakeup(a->die);
4535e96a66cSDavid du Colombier vtUnlock(a->lk);
4545e96a66cSDavid du Colombier }
4555e96a66cSDavid du Colombier
4565e96a66cSDavid du Colombier void
archKick(Arch * a)4575e96a66cSDavid du Colombier archKick(Arch *a)
4585e96a66cSDavid du Colombier {
4595e96a66cSDavid du Colombier if(a == nil){
4605e96a66cSDavid du Colombier fprint(2, "warning: archKick nil\n");
4615e96a66cSDavid du Colombier return;
4625e96a66cSDavid du Colombier }
4635e96a66cSDavid du Colombier vtLock(a->lk);
4645e96a66cSDavid du Colombier vtWakeup(a->starve);
4655e96a66cSDavid du Colombier vtUnlock(a->lk);
4665e96a66cSDavid du Colombier }
467