Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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;
}