#include "stdinc.h"
#include "dat.h"
#include "fns.h"
enum
{
ClumpChunks = 32*1024
};
static int missing, wrong;
/*
* shell sort is plenty good enough
* because we're going to do a bunch of disk i/o's
*/
static void
sortclumpinfo(ClumpInfo *ci, int *s, int n)
{
int i, j, m, t;
for(m = (n + 3) / 5; m > 0; m = (m + 1) / 3){
for(i = n - m; i-- > 0;){
for(j = i + m; j < n; j += m){
if(memcmp(ci[s[j - m]].score, ci[s[j]].score, VtScoreSize) <= 0)
break;
t = s[j];
s[j] = s[j - m];
s[j - m] = t;
}
}
}
}
int
syncarenaindex(Index *ix, Arena *arena, u32int clump, u64int a, int fix, int *pflush, int check)
{
Packet *pack;
IEntry ie;
IAddr ia;
ClumpInfo *ci, *cis;
u64int *addrs;
int i, n, ok, *s, flush;
trace(TraceProc, "syncarenaindex enter");
flush = 0;
cis = MKN(ClumpInfo, ClumpChunks);
addrs = MKN(u64int, ClumpChunks);
s = MKN(int, ClumpChunks);
ok = 0;
for(; clump < arena->memstats.clumps; clump += n){
n = ClumpChunks;
if(n > arena->memstats.clumps - clump)
n = arena->memstats.clumps - clump;
n = readclumpinfos(arena, clump, cis, n);
if(n <= 0){
fprint(2, "arena directory read failed\n");
ok = -1;
break;
}
for(i = 0; i < n; i++){
addrs[i] = a;
a += cis[i].size + ClumpSize;
s[i] = i;
}
sortclumpinfo(cis, s, n);
for(i = 0; i < n; i++){
ci = &cis[s[i]];
ia.type = ci->type;
ia.size = ci->uncsize;
ia.addr = addrs[s[i]];
ia.blocks = (ci->size + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
if(!check)
goto Add;
if(loadientry(ix, ci->score, ci->type, &ie) < 0){
trace(TraceProc, "syncarenaindex missing block %V.%d", ci->score, ci->type);
missing++;
if(0) fprint(2, "missing block type=%d score=%V\n", ci->type, ci->score);
}else if(iaddrcmp(&ia, &ie.ia) != 0){
trace(TraceProc, "syncarenaindex mismatched entry");
fprint(2, "\nmismatched index entry and clump at %d\n", clump + i);
fprint(2, "\tclump: type=%d size=%d blocks=%d addr=%lld\n", ia.type, ia.size, ia.blocks, ia.addr);
fprint(2, "\tindex: type=%d size=%d block=%d addr=%lld\n", ie.ia.type, ie.ia.size, ie.ia.blocks, ie.ia.addr);
pack = readlump(ie.score, ie.ia.type, ie.ia.size, nil);
packetfree(pack);
if(pack != nil){
fprint(2, "duplicated lump\n");
continue;
}
wrong++;
}else
continue;
Add:
if(!fix){
ok = -1;
continue;
}
flush = 1;
trace(TraceProc, "syncarenaindex insert %V", ci->score);
insertscore(ci->score, &ia, 1);
}
if(0 && clump / 1000 != (clump + n) / 1000)
fprint(2, ".");
}
free(cis);
free(addrs);
free(s);
if(flush){
flushdcache();
*pflush = 1;
}
return ok;
}
int
syncindex(Index *ix, int fix, int mustflush, int check)
{
Arena *arena;
AState as;
u64int a;
int i, e, e1, ok, ok1, flush;
ok = 0;
flush = 0;
for(i = 0; i < ix->narenas; i++){
trace(TraceProc, "syncindex start %d", i);
arena = ix->arenas[i];
/*
* Syncarena will scan through the arena looking for blocks
* that have been forgotten. It will update arena->memstats.used,
* so save the currenct copy as the place to start the
* syncarenaindex scan.
*/
a = arena->memstats.used;
e = syncarena(arena, ix->amap[i].start, TWID32, fix, fix);
e1 = e;
if(fix)
e1 &= ~(SyncHeader|SyncCIZero|SyncCIErr);
if(e1 == SyncHeader)
fprint(2, "arena %s: header is out-of-date\n", arena->name);
if(e1)
ok = -1;
else{
/*
* use diskstats not memstats here, because diskstats
* is what has been indexed; memstats is what has
* made it to disk (confusing names).
*/
ok1 = syncarenaindex(ix, arena,
arena->diskstats.clumps,
ix->amap[i].start + arena->diskstats.used,
fix, &flush, check);
if(ok1 < 0)
fprint(2, "syncarenaindex: %r\n");
if(fix && ok1==0 && (e & SyncHeader) && wbarena(arena) < 0)
fprint(2, "arena=%s header write failed: %r\n", arena->name);
ok |= ok1;
as.arena = arena;
as.aa = ix->amap[i].start + arena->memstats.used;
as.stats = arena->memstats;
setdcachestate(&as);
}
}
if(missing || wrong)
fprint(2, "syncindex: %d missing entries, %d wrong entries (flush=%d)\n", missing, wrong, flush);
if(fix && wbindex(ix) < 0){
fprint(2, "can't write back index header for %s: %r\n", ix->name);
return -1;
}
if(fix && flush){
flushdcache();
if(mustflush){
flushicache();
flushdcache();
}else
kickicache();
}
return ok;
}
|