blob: 746a89cab3216029d45c05f0647c975d3e157de4 [file] [log] [blame]
#include "stdinc.h"
#include "dat.h"
#include "fns.h"
int queuewrites = 0;
static Packet *readilump(Lump *u, IAddr *ia, u8int *score, int rac);
Packet*
readlump(u8int *score, int type, u32int size)
{
Lump *u;
Packet *p;
IAddr ia;
u32int n;
int rac;
qlock(&stats.lock);
stats.lumpreads++;
qunlock(&stats.lock);
u = lookuplump(score, type);
if(u->data != nil){
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(lookupscore(score, type, &ia, &rac) < 0){
//ZZZ place to check for someone trying to guess scores
seterr(EOk, "no block with that score exists");
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;
}
p = readilump(u, &ia, score, rac);
putlump(u);
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)
{
Lump *u;
int ok;
qlock(&stats.lock);
stats.lumpwrites++;
qunlock(&stats.lock);
packetsha1(p, score);
u = lookuplump(score, type);
if(u->data != nil){
ok = 0;
if(packetcmp(p, u->data) != 0){
seterr(EStrange, "score collision");
ok = -1;
}
packetfree(p);
putlump(u);
return ok;
}
if(queuewrites)
return queuewrite(u, p, creator);
ok = writeqlump(u, p, creator);
putlump(u);
return ok;
}
int
writeqlump(Lump *u, Packet *p, int creator)
{
ZBlock *flat;
Packet *old;
IAddr ia;
int ok;
int rac;
if(lookupscore(u->score, u->type, &ia, &rac) == 0){
/*
* if the read fails,
* assume it was corrupted data and store the block again
*/
old = readilump(u, &ia, u->score, rac);
if(old != nil){
ok = 0;
if(packetcmp(p, old) != 0){
seterr(EStrange, "score collision");
ok = -1;
}
packetfree(p);
packetfree(old);
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)
ok = insertscore(u->score, &ia, 1);
if(ok == 0)
insertlump(u, p);
else
packetfree(p);
return ok;
}
static void
readahead(u64int a, Arena *arena, u64int aa, int n)
{
u8int buf[ClumpSize];
Clump cl;
IAddr ia;
while(n > 0) {
if (aa >= arena->used)
break;
if(readarena(arena, aa, buf, ClumpSize) < ClumpSize)
break;
if(unpackclump(&cl, buf) < 0)
break;
ia.addr = a;
ia.type = cl.info.type;
ia.size = cl.info.uncsize;
ia.blocks = (cl.info.size + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
insertscore(cl.info.score, &ia, 0);
a += ClumpSize + cl.info.size;
aa += ClumpSize + cl.info.size;
n--;
}
}
static Packet*
readilump(Lump *u, IAddr *ia, u8int *score, int rac)
{
Arena *arena;
ZBlock *zb;
Packet *p, *pp;
Clump cl;
u64int a, aa;
u8int sc[VtScoreSize];
arena = amapitoa(mainindex, ia->addr, &aa);
if(arena == nil)
return nil;
zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid);
if(zb == nil)
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;
}
if(rac == 0) {
a = ia->addr + ClumpSize + cl.info.size;
aa += ClumpSize + cl.info.size;
readahead(a, arena, aa, 20);
}
p = zblock2packet(zb, cl.info.uncsize);
freezblock(zb);
pp = packetdup(p, 0, packetsize(p));
insertlump(u, pp);
return p;
}