static int flushblock(VtCache *c, VtBlock *bb, uint8_t score[VtScoreSize], int ppb, int epb, int type) { uint32_t addr; VtBlock *b; VtEntry e; int i; addr = vtglobaltolocal(score); if(addr == NilBlock) return 0; if(bb){ b = bb; if(memcmp(b->score, score, VtScoreSize) != 0) abort(); }else if((b = vtcachelocal(c, addr, type)) == nil) return -1; switch(type){ case VtDataType: break; case VtDirType: for(i=0; i<epb; i++){ if(vtentryunpack(&e, b->data, i) < 0) goto Err; if(!(e.flags&VtEntryActive)) continue; if(flushblock(c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize, e.type) < 0) goto Err; vtentrypack(&e, b->data, i); } break; default: /* VtPointerTypeX */ for(i=0; i<ppb; i++){ if(flushblock(c, nil, b->data+VtScoreSize*i, ppb, epb, type-1) < 0) goto Err; } break; } if(vtblockwrite(b) < 0) goto Err; memmove(score, b->score, VtScoreSize); if(b != bb) vtblockput(b); return 0; Err: if(b != bb) vtblockput(b); return -1; }
int vtfileflush(VtFile *f) { int ret; VtBlock *b; VtEntry e; assert(ISLOCKED(f)); b = fileload(f, &e); if(!(e.flags&VtEntryLocal)){ vtblockput(b); return 0; } ret = flushblock(f->c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize, e.type); if(ret < 0){ vtblockput(b); return -1; } vtentrypack(&e, b->data, f->offset % f->epb); vtblockput(b); return 0; }
void LazyIO::flushblocks() { uint64_t blockno; if (!mgr.getFirst(blockno)) return; do { flushblock(blockno); } while (mgr.getNext(blockno)); }
bool LazyIO::flushblock(uint64_t blockno) { Block *block; if (block = mgr.Lock(blockno)) { flushblock(block); mgr.Release(); return true; } return false; }
bool LazyIO::remove(uint64_t &blockno) { bool ret = false; Block *block; if (block = mgr.Lock(blockno)) { flushblock(block); ret = mgr.remove(blockno); mgr.Release(); } return ret; }
uint32_t LazyIO::writeblock(uint64_t blockno, const void *pv) { Block *block; if (block = mgr.Lock(blockno)) { uint32_t nwritten = blocksize; if (block->dirty) nwritten = flushblock(block); memcpy(block->pv, pv, blocksize); block->laccess = time(NULL); block->dirty = true; mgr.Release(); return nwritten; } cache(blockno, pv, true); return blocksize; }
int vtfileflushbefore(VtFile *r, u64int offset) { VtBlock *b, *bb; VtEntry e; int i, base, depth, ppb, epb, doflush; int index[VtPointerDepth+1], j, ret; VtBlock *bi[VtPointerDepth+2]; uchar *score; assert(ISLOCKED(r)); if(offset == 0) return 0; b = fileload(r, &e); if(b == nil) return -1; /* * compute path through tree for the last written byte and the next one. */ ret = -1; memset(bi, 0, sizeof bi); depth = DEPTH(e.type); bi[depth+1] = b; i = mkindices(&e, (offset-1)/e.dsize, index); if(i < 0) goto Err; if(i > depth) goto Err; ppb = e.psize / VtScoreSize; epb = e.dsize / VtEntrySize; /* * load the blocks along the last written byte */ index[depth] = r->offset % r->epb; for(i=depth; i>=0; i--){ bb = blockwalk(b, index[i], r->c, VtORDWR, &e); if(bb == nil) goto Err; bi[i] = bb; b = bb; } ret = 0; /* * walk up the path from leaf to root, flushing anything that * has been finished. */ base = e.type&~VtTypeDepthMask; for(i=0; i<=depth; i++){ doflush = 0; if(i == 0){ /* leaf: data or dir block */ if(offset%e.dsize == 0) doflush = 1; }else{ /* * interior node: pointer blocks. * specifically, b = bi[i] is a block whose index[i-1]'th entry * points at bi[i-1]. */ b = bi[i]; /* * the index entries up to but not including index[i-1] point at * finished blocks, so flush them for sure. */ for(j=0; j<index[i-1]; j++) if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0) goto Err; /* * if index[i-1] is the last entry in the block and is global * (i.e. the kid is flushed), then we can flush this block. */ if(j==ppb-1 && vtglobaltolocal(b->data+j*VtScoreSize)==NilBlock) doflush = 1; } if(doflush){ if(i == depth) score = e.score; else score = bi[i+1]->data+index[i]*VtScoreSize; if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0) goto Err; } } Err: /* top: entry. do this always so that the score is up-to-date */ vtentrypack(&e, bi[depth+1]->data, index[depth]); for(i=0; i<nelem(bi); i++) if(bi[i]) vtblockput(bi[i]); return ret; }