Based on copy.c and readlist.c, I have cobbled together a venti client to
copy a list of venti blocks from one venti server to another. I am thinking
of using it to incrementally replicate the contents on one site site to
another. It could even be used for two-way replication, since the CAS and
deduplicating properties of venti ensures that you will never have write
conflicts at a block level.

I have tried it out by feeding it with the output from printarenas, and it
seems to work reasonably well. Does anyone have any good ideas about how to
incrementally extract the set of scores that has been added to a venti
server? You could extract the whole set of scores and do a diff with an old
set of course, but that's rather inefficient.

Ole-Hj.


#include <u.h>
#include <libc.h>
#include <thread.h>
#include <venti.h>
#include <bio.h>

enum
{
    // XXX What to do here?
    VtMaxLumpSize = 65535,
};

char *srchost;
char *dsthost;
Biobuf b;
VtConn *zsrc;
VtConn *zdst;
uchar *buf;
void run(Biobuf*);
int nn;

void
usage(void)
{
    fprint(2, "usage: copylist srchost dsthost list\n");
    threadexitsall("usage");
}

int
parsescore(uchar *score, char *buf, int n)
{
    int i, c;

    memset(score, 0, VtScoreSize);

    if(n != VtScoreSize*2){
        werrstr("score wrong length %d", n);
        return -1;
    }
    for(i=0; i<VtScoreSize*2; i++) {
        if(buf[i] >= '0' && buf[i] <= '9')
            c = buf[i] - '0';
        else if(buf[i] >= 'a' && buf[i] <= 'f')
            c = buf[i] - 'a' + 10;
        else if(buf[i] >= 'A' && buf[i] <= 'F')
            c = buf[i] - 'A' + 10;
        else {
            c = buf[i];
            werrstr("bad score char %d '%c'", c, c);
            return -1;
        }

        if((i & 1) == 0)
            c <<= 4;

        score[i>>1] |= c;
    }
    return 0;
}

void
threadmain(int argc, char *argv[])
{
    int fd, i;

    ARGBEGIN{
    default:
        usage();
        break;
    }ARGEND

    if(argc < 2)
        usage();

    fmtinstall('V', vtscorefmt);
    buf = vtmallocz(VtMaxLumpSize);

    srchost = argv[0];
    zsrc = vtdial(srchost);
    if(zsrc == nil)
        sysfatal("could not dial src server: %r");
    if(vtconnect(zsrc) < 0)
        sysfatal("vtconnect src: %r");

    dsthost = argv[1];
    zdst = vtdial(dsthost);
    if(zdst == nil)
        sysfatal("could not dial dst server: %r");
    if(vtconnect(zdst) < 0)
        sysfatal("vtconnect dst: %r");

    if(argc == 2){
        Binit(&b, 0, OREAD);
        run(&b);
    }else{
        for(i=2; i<argc; i++){
            if((fd = open(argv[i], OREAD)) < 0)
                sysfatal("open %s: %r", argv[i]);
            Binit(&b, fd, OREAD);
            run(&b);
        }
    }
    threadexitsall(nil);
}

void
run(Biobuf *b)
{
    char *p, *f[10];
    int nf;
    uchar score[20];
    int type, n;

    while((p = Brdline(b, '\n')) != nil){
        p[Blinelen(b)-1] = 0;
        nf = tokenize(p, f, nelem(f));
        if(nf != 2)
            sysfatal("syntax error in work list");
        if(parsescore(score, f[0], strlen(f[0])) < 0)
            sysfatal("bad score %s in work list", f[0]);
        type = atoi(f[1]);
        n = vtread(zsrc, score, type, buf, VtMaxLumpSize);
        if(n < 0)
            sysfatal("could not read %s %s: %r", f[0], f[1]);
        n = vtwrite(zdst, score, type, buf, n);
        if(n < 0)
            sysfatal("could not write %s %s: %r", f[0], f[1]);
        if(++nn%1000 == 0)
            print("%d...", nn);
    }
}

Reply via email to