#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, u64int start, 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, "can't write corrected clump free magic: %r");
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: start=%lld fix=%d flush=%d %lld->%lld %ud->%ud %ud->%ud %lld->%lld\n",
arena->name,
start,
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;
}
|