| #include "stdinc.h" |
| #include "dat.h" |
| #include "fns.h" |
| |
| static int writeclumphead(Arena *arena, u64int aa, Clump *cl); |
| static int writeclumpmagic(Arena *arena, u64int aa, u32int magic); |
| |
| int |
| clumpinfocmp(ClumpInfo *c, ClumpInfo *d) |
| { |
| return c->type != d->type |
| || c->size != d->size |
| || c->uncsize != d->uncsize |
| || scorecmp(c->score, d->score)!=0; |
| } |
| |
| /* |
| * synchronize the clump info directory with |
| * with the clumps actually stored in the arena. |
| * the directory should be at least as up to date |
| * as the arena's trailer. |
| * |
| * checks/updates at most n clumps. |
| * |
| * returns 0 if ok, flags if error occurred |
| */ |
| int |
| syncarena(Arena *arena, u32int n, int zok, int fix) |
| { |
| ZBlock *lump; |
| Clump cl; |
| ClumpInfo ci; |
| static ClumpInfo zci = { .type = -1 }; |
| u8int score[VtScoreSize]; |
| u64int uncsize, used, aa; |
| u32int clump, clumps, cclumps, magic; |
| int err, flush, broken; |
| |
| used = arena->memstats.used; |
| clumps = arena->memstats.clumps; |
| cclumps = arena->memstats.cclumps; |
| uncsize = arena->memstats.uncsize; |
| trace(TraceProc, "syncarena start"); |
| flush = 0; |
| err = 0; |
| for(; n; n--){ |
| aa = arena->memstats.used; |
| clump = arena->memstats.clumps; |
| magic = clumpmagic(arena, aa); |
| if(magic == ClumpFreeMagic) |
| break; |
| if(magic != arena->clumpmagic){ |
| fprint(2, "%s: illegal clump magic number=%#8.8ux at clump=%d\n", arena->name, magic, clump); |
| /* err |= SyncDataErr; */ |
| if(fix && writeclumpmagic(arena, aa, ClumpFreeMagic) < 0){ |
| fprint(2, "%s: can't write corrected clump free magic: %r", arena->name); |
| err |= SyncFixErr; |
| } |
| break; |
| } |
| |
| broken = 0; |
| lump = loadclump(arena, aa, 0, &cl, score, 0); |
| if(lump == nil){ |
| fprint(2, "%s: clump=%d failed to read correctly: %r\n", arena->name, clump); |
| break; |
| }else if(cl.info.type != VtCorruptType){ |
| scoremem(score, lump->data, cl.info.uncsize); |
| if(scorecmp(cl.info.score, score) != 0){ |
| /* ignore partially written block */ |
| if(cl.encoding == ClumpENone) |
| break; |
| fprint(2, "%s: clump=%d has mismatched score\n", arena->name, clump); |
| err |= SyncDataErr; |
| broken = 1; |
| }else if(vttypevalid(cl.info.type) < 0){ |
| fprint(2, "%s: clump=%d has invalid type %d", arena->name, clump, cl.info.type); |
| err |= SyncDataErr; |
| broken = 1; |
| } |
| if(broken && fix){ |
| cl.info.type = VtCorruptType; |
| if(writeclumphead(arena, aa, &cl) < 0){ |
| fprint(2, "%s: can't write corrected clump header: %r", arena->name); |
| err |= SyncFixErr; |
| } |
| } |
| } |
| freezblock(lump); |
| arena->memstats.used += ClumpSize + cl.info.size; |
| |
| arena->memstats.clumps++; |
| if(!broken && readclumpinfo(arena, clump, &ci)<0){ |
| fprint(2, "%s: arena directory read failed\n", arena->name); |
| broken = 1; |
| }else if(!broken && clumpinfocmp(&ci, &cl.info)!=0){ |
| if(clumpinfocmp(&ci, &zci) == 0){ |
| err |= SyncCIZero; |
| if(!zok) |
| fprint(2, "%s: unwritten clump info for clump=%d\n", arena->name, clump); |
| }else{ |
| err |= SyncCIErr; |
| fprint(2, "%s: bad clump info for clump=%d\n", arena->name, clump); |
| fprint(2, "\texpected score=%V type=%d size=%d uncsize=%d\n", |
| cl.info.score, cl.info.type, cl.info.size, cl.info.uncsize); |
| fprint(2, "\tfound score=%V type=%d size=%d uncsize=%d\n", |
| ci.score, ci.type, ci.size, ci.uncsize); |
| } |
| broken = 1; |
| } |
| if(broken && fix){ |
| flush = 1; |
| ci = cl.info; |
| if(writeclumpinfo(arena, clump, &ci) < 0){ |
| fprint(2, "%s: can't write correct clump directory: %r\n", arena->name); |
| err |= SyncFixErr; |
| } |
| } |
| trace(TraceProc, "syncarena unindexed clump %V %d", cl.info.score, arena->memstats.clumps); |
| |
| arena->memstats.uncsize += cl.info.uncsize; |
| if(cl.info.size < cl.info.uncsize) |
| arena->memstats.cclumps++; |
| } |
| |
| if(flush){ |
| trace(TraceProc, "syncarena flush"); |
| arena->wtime = now(); |
| if(arena->ctime == 0 && arena->memstats.clumps) |
| arena->ctime = arena->wtime; |
| flushdcache(); |
| } |
| |
| if(used != arena->memstats.used |
| || clumps != arena->memstats.clumps |
| || cclumps != arena->memstats.cclumps |
| || uncsize != arena->memstats.uncsize){ |
| err |= SyncHeader; |
| fprint(2, "arena %s: fix=%d flush=%d %lld->%lld %ud->%ud %ud->%ud %lld->%lld\n", |
| arena->name, |
| fix, |
| flush, |
| used, arena->memstats.used, |
| clumps, arena->memstats.clumps, |
| cclumps, arena->memstats.cclumps, |
| uncsize, arena->memstats.uncsize); |
| } |
| |
| return err; |
| } |
| |
| static int |
| writeclumphead(Arena *arena, u64int aa, Clump *cl) |
| { |
| ZBlock *zb; |
| int bad; |
| |
| zb = alloczblock(ClumpSize, 0, arena->blocksize); |
| if(zb == nil) |
| return -1; |
| bad = packclump(cl, zb->data, arena->clumpmagic)<0 |
| || writearena(arena, aa, zb->data, ClumpSize) != ClumpSize; |
| freezblock(zb); |
| return bad ? -1 : 0; |
| } |
| |
| static int |
| writeclumpmagic(Arena *arena, u64int aa, u32int magic) |
| { |
| u8int buf[U32Size]; |
| |
| packmagic(magic, buf); |
| return writearena(arena, aa, buf, U32Size) == U32Size; |
| } |