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"

int                     syncwrites = 0;
int                     queuewrites = 0;
int                     writestodevnull = 0;
int                     verifywrites = 0;

static Packet           *readilump(Lump *u, IAddr *ia, u8int *score);

/*
 * Some of this logic is duplicated in hdisk.c
 */
Packet*
readlump(u8int *score, int type, u32int size, int *cached)
{
        Lump *u;
        Packet *p;
        IAddr ia;
        u32int n;

        trace(TraceLump, "readlump enter");
/*
        qlock(&stats.lock);
        stats.lumpreads++;
        qunlock(&stats.lock);
*/
        if(scorecmp(score, zeroscore) == 0)
                return packetalloc();
        u = lookuplump(score, type);
        if(u->data != nil){
                trace(TraceLump, "readlump lookuplump hit");
                if(cached)
                        *cached = 1;
                n = packetsize(u->data);
                if(n > size){
                        seterr(EOk, "read too small: asked for %d need at least %d", size, n);
                        putlump(u);

                        return nil;
                }
                p = packetdup(u->data, 0, n);
                putlump(u);
                return p;
        }

        if(cached)
                *cached = 0;

        if(lookupscore(score, type, &ia) < 0){
                /* ZZZ place to check for someone trying to guess scores */
                seterr(EOk, "no block with score %V/%d exists", score, type);

                putlump(u);
                return nil;
        }
        if(ia.size > size){
                seterr(EOk, "read too small 1: asked for %d need at least %d", size, ia.size);

                putlump(u);
                return nil;
        }

        trace(TraceLump, "readlump readilump");
        p = readilump(u, &ia, score);
        putlump(u);

        trace(TraceLump, "readlump exit");
        return p;
}

/*
 * save away a lump, and return it's score.
 * doesn't store duplicates, but checks that the data is really the same.
 */
int
writelump(Packet *p, u8int *score, int type, u32int creator, uint ms)
{
        Lump *u;
        int ok;

/*
        qlock(&stats.lock);
        stats.lumpwrites++;
        qunlock(&stats.lock);
*/

        packetsha1(p, score);
        if(packetsize(p) == 0 || writestodevnull==1){
                packetfree(p);
                return 0;
        }

        u = lookuplump(score, type);
        if(u->data != nil){
                ok = 0;
                if(packetcmp(p, u->data) != 0){
                        uchar nscore[VtScoreSize];

                        packetsha1(u->data, nscore);
                        if(scorecmp(u->score, score) != 0)
                                seterr(EStrange, "lookuplump returned bad score %V not %V", u->score, score);
                        else if(scorecmp(u->score, nscore) != 0)
                                seterr(EStrange, "lookuplump returned bad data %V not %V", nscore, u->score);
                        else
                                seterr(EStrange, "score collision %V", score);
                        ok = -1;
                }
                packetfree(p);
                putlump(u);
                return ok;
        }

        if(writestodevnull==2){
                packetfree(p);
                return 0;
        }

        if(queuewrites)
                return queuewrite(u, p, creator, ms);

        ok = writeqlump(u, p, creator, ms);

        putlump(u);
        return ok;
}

int
writeqlump(Lump *u, Packet *p, int creator, uint ms)
{
        ZBlock *flat;
        Packet *old;
        IAddr ia;
        int ok;

        if(lookupscore(u->score, u->type, &ia) == 0){
                if(verifywrites == 0){
                        /* assume the data is here! */
                        packetfree(p);
                        ms = msec() - ms;
                        addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
                        return 0;
                }

                /*
                 * if the read fails,
                 * assume it was corrupted data and store the block again
                 */
                old = readilump(u, &ia, u->score);
                if(old != nil){
                        ok = 0;
                        if(packetcmp(p, old) != 0){
                                uchar nscore[VtScoreSize];

                                packetsha1(old, nscore);
                                if(scorecmp(u->score, nscore) != 0)
                                        seterr(EStrange, "readilump returned bad data %V not %V", nscore, u->score);
                                else
                                        seterr(EStrange, "score collision %V", u->score);
                                ok = -1;
                        }
                        packetfree(p);
                        packetfree(old);

                        ms = msec() - ms;
                        addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
                        return ok;
                }
                logerr(EAdmin, "writelump: read %V failed, rewriting: %r\n", u->score);
        }

        flat = packet2zblock(p, packetsize(p));
        ok = storeclump(mainindex, flat, u->score, u->type, creator, &ia);
        freezblock(flat);
        if(ok == 0)
                insertlump(u, p);
        else
                packetfree(p);
        
        if(syncwrites){
                flushdcache();
                flushicache();
                flushdcache();
        }

        ms = msec() - ms;
        addstat2(StatRpcWriteNew, 1, StatRpcWriteNewTime, ms);
        return ok;
}

static Packet*
readilump(Lump *u, IAddr *ia, u8int *score)
{
        Arena *arena;
        ZBlock *zb;
        Packet *p, *pp;
        Clump cl;
        u64int aa;
        u8int sc[VtScoreSize];

        trace(TraceLump, "readilump enter");
        arena = amapitoa(mainindex, ia->addr, &aa);
        if(arena == nil){
                trace(TraceLump, "readilump amapitoa failed");
                return nil;
        }

        trace(TraceLump, "readilump loadclump");
        zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid);
        if(zb == nil){
                trace(TraceLump, "readilump loadclump failed");
                return nil;
        }

        if(ia->size != cl.info.uncsize){
                seterr(EInconsist, "index and clump size mismatch");
                freezblock(zb);
                return nil;
        }
        if(ia->type != cl.info.type){
                seterr(EInconsist, "index and clump type mismatch");
                freezblock(zb);
                return nil;
        }
        if(scorecmp(score, sc) != 0){
                seterr(ECrash, "score mismatch");
                freezblock(zb);
                return nil;
        }

        trace(TraceLump, "readilump success");
        p = zblock2packet(zb, cl.info.uncsize);
        freezblock(zb);
        pp = packetdup(p, 0, packetsize(p));
        trace(TraceLump, "readilump insertlump");
        insertlump(u, pp);
        trace(TraceLump, "readilump exit");
        return p;
}