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