241 lines
4.8 KiB
C
241 lines
4.8 KiB
C
#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;
|
|
}
|