1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier
5368c31abSDavid du Colombier int syncwrites = 0;
6368c31abSDavid du Colombier int queuewrites = 0;
7368c31abSDavid du Colombier int writestodevnull = 0;
8368c31abSDavid du Colombier int verifywrites = 0;
9368c31abSDavid du Colombier
10*f9e1cf08SDavid du Colombier static Packet *readilump(Lump *u, IAddr *ia, u8int *score);
11368c31abSDavid du Colombier
12368c31abSDavid du Colombier /*
13368c31abSDavid du Colombier * Some of this logic is duplicated in hdisk.c
14368c31abSDavid du Colombier */
15368c31abSDavid du Colombier Packet*
readlump(u8int * score,int type,u32int size,int * cached)16368c31abSDavid du Colombier readlump(u8int *score, int type, u32int size, int *cached)
17368c31abSDavid du Colombier {
18368c31abSDavid du Colombier Lump *u;
19368c31abSDavid du Colombier Packet *p;
20368c31abSDavid du Colombier IAddr ia;
21368c31abSDavid du Colombier u32int n;
22368c31abSDavid du Colombier
23368c31abSDavid du Colombier trace(TraceLump, "readlump enter");
24368c31abSDavid du Colombier /*
25368c31abSDavid du Colombier qlock(&stats.lock);
26368c31abSDavid du Colombier stats.lumpreads++;
27368c31abSDavid du Colombier qunlock(&stats.lock);
28368c31abSDavid du Colombier */
29368c31abSDavid du Colombier if(scorecmp(score, zeroscore) == 0)
30368c31abSDavid du Colombier return packetalloc();
31368c31abSDavid du Colombier u = lookuplump(score, type);
32368c31abSDavid du Colombier if(u->data != nil){
33368c31abSDavid du Colombier trace(TraceLump, "readlump lookuplump hit");
34368c31abSDavid du Colombier if(cached)
35368c31abSDavid du Colombier *cached = 1;
36368c31abSDavid du Colombier n = packetsize(u->data);
37368c31abSDavid du Colombier if(n > size){
38368c31abSDavid du Colombier seterr(EOk, "read too small: asked for %d need at least %d", size, n);
39368c31abSDavid du Colombier putlump(u);
40368c31abSDavid du Colombier
41368c31abSDavid du Colombier return nil;
42368c31abSDavid du Colombier }
43368c31abSDavid du Colombier p = packetdup(u->data, 0, n);
44368c31abSDavid du Colombier putlump(u);
45368c31abSDavid du Colombier return p;
46368c31abSDavid du Colombier }
47368c31abSDavid du Colombier
48368c31abSDavid du Colombier if(cached)
49368c31abSDavid du Colombier *cached = 0;
50368c31abSDavid du Colombier
51*f9e1cf08SDavid du Colombier if(lookupscore(score, type, &ia) < 0){
52368c31abSDavid du Colombier /* ZZZ place to check for someone trying to guess scores */
53368c31abSDavid du Colombier seterr(EOk, "no block with score %V/%d exists", score, type);
54368c31abSDavid du Colombier
55368c31abSDavid du Colombier putlump(u);
56368c31abSDavid du Colombier return nil;
57368c31abSDavid du Colombier }
58368c31abSDavid du Colombier if(ia.size > size){
59368c31abSDavid du Colombier seterr(EOk, "read too small 1: asked for %d need at least %d", size, ia.size);
60368c31abSDavid du Colombier
61368c31abSDavid du Colombier putlump(u);
62368c31abSDavid du Colombier return nil;
63368c31abSDavid du Colombier }
64368c31abSDavid du Colombier
65368c31abSDavid du Colombier trace(TraceLump, "readlump readilump");
66*f9e1cf08SDavid du Colombier p = readilump(u, &ia, score);
67368c31abSDavid du Colombier putlump(u);
68368c31abSDavid du Colombier
69368c31abSDavid du Colombier trace(TraceLump, "readlump exit");
70368c31abSDavid du Colombier return p;
71368c31abSDavid du Colombier }
72368c31abSDavid du Colombier
73368c31abSDavid du Colombier /*
74368c31abSDavid du Colombier * save away a lump, and return it's score.
75368c31abSDavid du Colombier * doesn't store duplicates, but checks that the data is really the same.
76368c31abSDavid du Colombier */
77368c31abSDavid du Colombier int
writelump(Packet * p,u8int * score,int type,u32int creator,uint ms)78368c31abSDavid du Colombier writelump(Packet *p, u8int *score, int type, u32int creator, uint ms)
79368c31abSDavid du Colombier {
80368c31abSDavid du Colombier Lump *u;
81368c31abSDavid du Colombier int ok;
82368c31abSDavid du Colombier
83368c31abSDavid du Colombier /*
84368c31abSDavid du Colombier qlock(&stats.lock);
85368c31abSDavid du Colombier stats.lumpwrites++;
86368c31abSDavid du Colombier qunlock(&stats.lock);
87368c31abSDavid du Colombier */
88368c31abSDavid du Colombier
89368c31abSDavid du Colombier packetsha1(p, score);
90368c31abSDavid du Colombier if(packetsize(p) == 0 || writestodevnull==1){
91368c31abSDavid du Colombier packetfree(p);
92368c31abSDavid du Colombier return 0;
93368c31abSDavid du Colombier }
94368c31abSDavid du Colombier
95368c31abSDavid du Colombier u = lookuplump(score, type);
96368c31abSDavid du Colombier if(u->data != nil){
97368c31abSDavid du Colombier ok = 0;
98368c31abSDavid du Colombier if(packetcmp(p, u->data) != 0){
99368c31abSDavid du Colombier uchar nscore[VtScoreSize];
100368c31abSDavid du Colombier
101368c31abSDavid du Colombier packetsha1(u->data, nscore);
102368c31abSDavid du Colombier if(scorecmp(u->score, score) != 0)
103368c31abSDavid du Colombier seterr(EStrange, "lookuplump returned bad score %V not %V", u->score, score);
104368c31abSDavid du Colombier else if(scorecmp(u->score, nscore) != 0)
105368c31abSDavid du Colombier seterr(EStrange, "lookuplump returned bad data %V not %V", nscore, u->score);
106368c31abSDavid du Colombier else
107368c31abSDavid du Colombier seterr(EStrange, "score collision %V", score);
108368c31abSDavid du Colombier ok = -1;
109368c31abSDavid du Colombier }
110368c31abSDavid du Colombier packetfree(p);
111368c31abSDavid du Colombier putlump(u);
112368c31abSDavid du Colombier return ok;
113368c31abSDavid du Colombier }
114368c31abSDavid du Colombier
115368c31abSDavid du Colombier if(writestodevnull==2){
116368c31abSDavid du Colombier packetfree(p);
117368c31abSDavid du Colombier return 0;
118368c31abSDavid du Colombier }
119368c31abSDavid du Colombier
120368c31abSDavid du Colombier if(queuewrites)
121368c31abSDavid du Colombier return queuewrite(u, p, creator, ms);
122368c31abSDavid du Colombier
123368c31abSDavid du Colombier ok = writeqlump(u, p, creator, ms);
124368c31abSDavid du Colombier
125368c31abSDavid du Colombier putlump(u);
126368c31abSDavid du Colombier return ok;
127368c31abSDavid du Colombier }
128368c31abSDavid du Colombier
129368c31abSDavid du Colombier int
writeqlump(Lump * u,Packet * p,int creator,uint ms)130368c31abSDavid du Colombier writeqlump(Lump *u, Packet *p, int creator, uint ms)
131368c31abSDavid du Colombier {
132368c31abSDavid du Colombier ZBlock *flat;
133368c31abSDavid du Colombier Packet *old;
134368c31abSDavid du Colombier IAddr ia;
135368c31abSDavid du Colombier int ok;
136368c31abSDavid du Colombier
137*f9e1cf08SDavid du Colombier if(lookupscore(u->score, u->type, &ia) == 0){
138368c31abSDavid du Colombier if(verifywrites == 0){
139368c31abSDavid du Colombier /* assume the data is here! */
140368c31abSDavid du Colombier packetfree(p);
141368c31abSDavid du Colombier ms = msec() - ms;
142368c31abSDavid du Colombier addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
143368c31abSDavid du Colombier return 0;
144368c31abSDavid du Colombier }
145368c31abSDavid du Colombier
146368c31abSDavid du Colombier /*
147368c31abSDavid du Colombier * if the read fails,
148368c31abSDavid du Colombier * assume it was corrupted data and store the block again
149368c31abSDavid du Colombier */
150*f9e1cf08SDavid du Colombier old = readilump(u, &ia, u->score);
151368c31abSDavid du Colombier if(old != nil){
152368c31abSDavid du Colombier ok = 0;
153368c31abSDavid du Colombier if(packetcmp(p, old) != 0){
154368c31abSDavid du Colombier uchar nscore[VtScoreSize];
155368c31abSDavid du Colombier
156368c31abSDavid du Colombier packetsha1(old, nscore);
157368c31abSDavid du Colombier if(scorecmp(u->score, nscore) != 0)
158368c31abSDavid du Colombier seterr(EStrange, "readilump returned bad data %V not %V", nscore, u->score);
159368c31abSDavid du Colombier else
160368c31abSDavid du Colombier seterr(EStrange, "score collision %V", u->score);
161368c31abSDavid du Colombier ok = -1;
162368c31abSDavid du Colombier }
163368c31abSDavid du Colombier packetfree(p);
164368c31abSDavid du Colombier packetfree(old);
165368c31abSDavid du Colombier
166368c31abSDavid du Colombier ms = msec() - ms;
167368c31abSDavid du Colombier addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
168368c31abSDavid du Colombier return ok;
169368c31abSDavid du Colombier }
170368c31abSDavid du Colombier logerr(EAdmin, "writelump: read %V failed, rewriting: %r\n", u->score);
171368c31abSDavid du Colombier }
172368c31abSDavid du Colombier
173368c31abSDavid du Colombier flat = packet2zblock(p, packetsize(p));
174368c31abSDavid du Colombier ok = storeclump(mainindex, flat, u->score, u->type, creator, &ia);
175368c31abSDavid du Colombier freezblock(flat);
176368c31abSDavid du Colombier if(ok == 0)
177368c31abSDavid du Colombier insertlump(u, p);
178368c31abSDavid du Colombier else
179368c31abSDavid du Colombier packetfree(p);
180368c31abSDavid du Colombier
181368c31abSDavid du Colombier if(syncwrites){
182368c31abSDavid du Colombier flushdcache();
183368c31abSDavid du Colombier flushicache();
184368c31abSDavid du Colombier flushdcache();
185368c31abSDavid du Colombier }
186368c31abSDavid du Colombier
187368c31abSDavid du Colombier ms = msec() - ms;
188368c31abSDavid du Colombier addstat2(StatRpcWriteNew, 1, StatRpcWriteNewTime, ms);
189368c31abSDavid du Colombier return ok;
190368c31abSDavid du Colombier }
191368c31abSDavid du Colombier
192368c31abSDavid du Colombier static Packet*
readilump(Lump * u,IAddr * ia,u8int * score)193*f9e1cf08SDavid du Colombier readilump(Lump *u, IAddr *ia, u8int *score)
194368c31abSDavid du Colombier {
195368c31abSDavid du Colombier Arena *arena;
196368c31abSDavid du Colombier ZBlock *zb;
197368c31abSDavid du Colombier Packet *p, *pp;
198368c31abSDavid du Colombier Clump cl;
199*f9e1cf08SDavid du Colombier u64int aa;
200368c31abSDavid du Colombier u8int sc[VtScoreSize];
201368c31abSDavid du Colombier
202368c31abSDavid du Colombier trace(TraceLump, "readilump enter");
203368c31abSDavid du Colombier arena = amapitoa(mainindex, ia->addr, &aa);
204368c31abSDavid du Colombier if(arena == nil){
205368c31abSDavid du Colombier trace(TraceLump, "readilump amapitoa failed");
206368c31abSDavid du Colombier return nil;
207368c31abSDavid du Colombier }
208368c31abSDavid du Colombier
209368c31abSDavid du Colombier trace(TraceLump, "readilump loadclump");
210368c31abSDavid du Colombier zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid);
211368c31abSDavid du Colombier if(zb == nil){
212368c31abSDavid du Colombier trace(TraceLump, "readilump loadclump failed");
213368c31abSDavid du Colombier return nil;
214368c31abSDavid du Colombier }
215368c31abSDavid du Colombier
216368c31abSDavid du Colombier if(ia->size != cl.info.uncsize){
217368c31abSDavid du Colombier seterr(EInconsist, "index and clump size mismatch");
218368c31abSDavid du Colombier freezblock(zb);
219368c31abSDavid du Colombier return nil;
220368c31abSDavid du Colombier }
221368c31abSDavid du Colombier if(ia->type != cl.info.type){
222368c31abSDavid du Colombier seterr(EInconsist, "index and clump type mismatch");
223368c31abSDavid du Colombier freezblock(zb);
224368c31abSDavid du Colombier return nil;
225368c31abSDavid du Colombier }
226368c31abSDavid du Colombier if(scorecmp(score, sc) != 0){
227368c31abSDavid du Colombier seterr(ECrash, "score mismatch");
228368c31abSDavid du Colombier freezblock(zb);
229368c31abSDavid du Colombier return nil;
230368c31abSDavid du Colombier }
231368c31abSDavid du Colombier
232368c31abSDavid du Colombier trace(TraceLump, "readilump success");
233368c31abSDavid du Colombier p = zblock2packet(zb, cl.info.uncsize);
234368c31abSDavid du Colombier freezblock(zb);
235368c31abSDavid du Colombier pp = packetdup(p, 0, packetsize(p));
236368c31abSDavid du Colombier trace(TraceLump, "readilump insertlump");
237368c31abSDavid du Colombier insertlump(u, pp);
238368c31abSDavid du Colombier trace(TraceLump, "readilump exit");
239368c31abSDavid du Colombier return p;
240368c31abSDavid du Colombier }
241