#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
clumpInfoEq(ClumpInfo *c, ClumpInfo *d)
{
return c->type == d->type
&& c->size == d->size
&& c->uncsize == d->uncsize
&& scoreEq(c->score, d->score);
}
/*
* 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 1 if ok, -1 if an error occured, 0 if blocks were updated
*/
int
syncArena(Arena *arena, u32int n, int zok, int fix)
{
ZBlock *lump;
Clump cl;
ClumpInfo ci;
static ClumpInfo zci;
u8int score[VtScoreSize];
u64int uncsize, used, aa;
u32int clump, clumps, cclumps, magic;
int err, flush, broken, cierr;
used = arena->used;
clumps = arena->clumps;
cclumps = arena->cclumps;
uncsize = arena->uncsize;
flush = 0;
err = 0;
for(; n; n--){
aa = arena->used;
clump = arena->clumps;
magic = clumpMagic(arena, aa);
if(magic == ClumpFreeMagic)
break;
if(magic != ClumpMagic){
fprint(2, "illegal clump magic number=%#8.8ux at clump=%d\n", magic, clump);
err |= SyncDataErr;
//ZZZ write a zero here?
if(0 && fix && !writeClumpMagic(arena, aa, ClumpFreeMagic)){
fprint(2, "can't write corrected clump free magic: %R");
err |= SyncFixErr;
}
break;
}
arena->clumps++;
broken = 0;
cierr = 0;
lump = loadClump(arena, aa, 0, &cl, score, 0);
if(lump == nil){
fprint(2, "clump=%d failed to read correctly: %R\n", clump);
err |= SyncDataErr;
}else if(cl.info.type != VtTypeCorrupt){
scoreMem(score, lump->data, cl.info.uncsize);
if(!scoreEq(cl.info.score, score)){
fprint(2, "clump=%d has mismatched score\n", clump);
err = SyncDataErr;
broken = 1;
}else if(!vtTypeValid(cl.info.type)){
fprint(2, "clump=%d has invalid type %d", clump, cl.info.type);
err = SyncDataErr;
broken = 1;
}
if(broken && fix){
cl.info.type = VtTypeCorrupt;
if(!writeClumpHead(arena, aa, &cl)){
fprint(2, "can't write corrected clump header: %R");
err |= SyncFixErr;
}
}
}
freeZBlock(lump);
arena->used += ClumpSize + cl.info.size;
if(!broken && !readClumpInfo(arena, clump, &ci)){
fprint(2, "arena directory read failed\n");
broken = 1;
}else if(!broken && !clumpInfoEq(&ci, &cl.info)){
if(clumpInfoEq(&ci, &zci)){
cierr |= SyncCIZero;
if(!zok){
fprint(2, "unwritten clump info for clump=%d ", clump);
fprint(2, "score=%V type=%d\n",
cl.info.score, cl.info.type);
}
}else{
cierr |= SyncCIErr;
fprint(2, "bad clump info for clump=%d\n", 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)){
fprint(2, "can't write correct clump directory: %R\n");
err |= SyncFixErr;
}else
cierr &= ~(SyncCIZero|SyncCIErr);
}
err |= cierr;
arena->uncsize += cl.info.uncsize;
if(cl.info.size < cl.info.uncsize)
arena->cclumps++;
}
if(flush){
arena->wtime = now();
if(arena->ctime == 0 && arena->clumps)
arena->ctime = arena->wtime;
if(!flushCIBlocks(arena)){
fprint(2, "can't flush arena directory cache: %R");
err |= SyncFixErr;
}
}
if(used != arena->used
|| clumps != arena->clumps
|| cclumps != arena->cclumps
|| uncsize != arena->uncsize)
err |= SyncHeader;
return err;
}
static int
writeClumpHead(Arena *arena, u64int aa, Clump *cl)
{
ZBlock *zb;
int ok;
zb = allocZBlock(ClumpSize, 0);
if(zb == nil)
return 0;
ok = packClump(cl, zb->data)
&& writeArena(arena, aa, zb->data, ClumpSize) == ClumpSize;
freeZBlock(zb);
return ok;
}
static int
writeClumpMagic(Arena *arena, u64int aa, u32int magic)
{
u8int buf[U32Size];
packMagic(magic, buf);
return writeArena(arena, aa, buf, U32Size) == U32Size;
}
|