Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
5 int queuewrites = 0;
6 int writestodevnull = 0;
8 static Packet *readilump(Lump *u, IAddr *ia, u8int *score, int rac);
10 Packet*
11 readlump(u8int *score, int type, u32int size, int *cached)
12 {
13 Lump *u;
14 Packet *p;
15 IAddr ia;
16 u32int n;
17 int rac;
19 trace(TraceLump, "readlump enter");
20 /*
21 qlock(&stats.lock);
22 stats.lumpreads++;
23 qunlock(&stats.lock);
24 */
25 if(scorecmp(score, zeroscore) == 0)
26 return packetalloc();
27 u = lookuplump(score, type);
28 if(u->data != nil){
29 trace(TraceLump, "readlump lookuplump hit");
30 if(cached)
31 *cached = 1;
32 n = packetsize(u->data);
33 if(n > size){
34 seterr(EOk, "read too small: asked for %d need at least %d", size, n);
35 putlump(u);
37 return nil;
38 }
39 p = packetdup(u->data, 0, n);
40 putlump(u);
41 return p;
42 }
44 if(cached)
45 *cached = 0;
47 if(lookupscore(score, type, &ia, &rac) < 0){
48 //ZZZ place to check for someone trying to guess scores
49 seterr(EOk, "no block with score %V/%d exists", score, type);
51 putlump(u);
52 return nil;
53 }
54 if(ia.size > size){
55 seterr(EOk, "read too small 1: asked for %d need at least %d", size, ia.size);
57 putlump(u);
58 return nil;
59 }
61 trace(TraceLump, "readlump readilump");
62 p = readilump(u, &ia, score, rac);
63 putlump(u);
65 trace(TraceLump, "readlump exit");
66 return p;
67 }
69 /*
70 * save away a lump, and return it's score.
71 * doesn't store duplicates, but checks that the data is really the same.
72 */
73 int
74 writelump(Packet *p, u8int *score, int type, u32int creator, uint ms)
75 {
76 Lump *u;
77 int ok;
79 /*
80 qlock(&stats.lock);
81 stats.lumpwrites++;
82 qunlock(&stats.lock);
83 */
85 packetsha1(p, score);
86 if(packetsize(p) == 0 || writestodevnull==1){
87 packetfree(p);
88 return 0;
89 }
91 u = lookuplump(score, type);
92 if(u->data != nil){
93 ok = 0;
94 if(packetcmp(p, u->data) != 0){
95 seterr(EStrange, "score collision");
96 ok = -1;
97 }
98 packetfree(p);
99 putlump(u);
100 return ok;
103 if(writestodevnull==2){
104 packetfree(p);
105 return 0;
108 if(queuewrites)
109 return queuewrite(u, p, creator, ms);
111 ok = writeqlump(u, p, creator, ms);
113 putlump(u);
114 return ok;
117 int
118 writeqlump(Lump *u, Packet *p, int creator, uint ms)
120 ZBlock *flat;
121 Packet *old;
122 IAddr ia;
123 int ok;
124 int rac;
126 if(lookupscore(u->score, u->type, &ia, &rac) == 0){
127 /* assume the data is here! XXX */
128 packetfree(p);
129 ms = msec() - ms;
130 addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
131 return 0;
133 /*
134 * if the read fails,
135 * assume it was corrupted data and store the block again
136 */
137 old = readilump(u, &ia, u->score, rac);
138 if(old != nil){
139 ok = 0;
140 if(packetcmp(p, old) != 0){
141 seterr(EStrange, "score collision");
142 ok = -1;
144 packetfree(p);
145 packetfree(old);
147 ms = msec() - ms;
148 addstat2(StatRpcWriteOld, 1, StatRpcWriteOldTime, ms);
149 return ok;
151 logerr(EAdmin, "writelump: read %V failed, rewriting: %r\n", u->score);
154 flat = packet2zblock(p, packetsize(p));
155 ok = storeclump(mainindex, flat, u->score, u->type, creator, &ia);
156 freezblock(flat);
157 if(ok == 0)
158 ok = insertscore(u->score, &ia, 1);
159 if(ok == 0)
160 insertlump(u, p);
161 else
162 packetfree(p);
164 ms = msec() - ms;
165 addstat2(StatRpcWriteNew, 1, StatRpcWriteNewTime, ms);
166 return ok;
169 static void
170 lreadahead(u64int a, Arena *arena, u64int aa, int n)
172 u8int buf[ClumpSize];
173 Clump cl;
174 IAddr ia;
176 while(n > 0) {
177 if (aa >= arena->memstats.used)
178 break;
179 if(readarena(arena, aa, buf, ClumpSize) < ClumpSize)
180 break;
181 if(unpackclump(&cl, buf, arena->clumpmagic) < 0)
182 break;
183 ia.addr = a;
184 ia.type = cl.info.type;
185 ia.size = cl.info.uncsize;
186 ia.blocks = (cl.info.size + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
187 insertscore(cl.info.score, &ia, 0);
188 a += ClumpSize + cl.info.size;
189 aa += ClumpSize + cl.info.size;
190 n--;
194 static Packet*
195 readilump(Lump *u, IAddr *ia, u8int *score, int rac)
197 Arena *arena;
198 ZBlock *zb;
199 Packet *p, *pp;
200 Clump cl;
201 u64int a, aa;
202 u8int sc[VtScoreSize];
204 trace(TraceLump, "readilump enter");
205 arena = amapitoa(mainindex, ia->addr, &aa);
206 if(arena == nil){
207 trace(TraceLump, "readilump amapitoa failed");
208 return nil;
211 trace(TraceLump, "readilump loadclump");
212 zb = loadclump(arena, aa, ia->blocks, &cl, sc, paranoid);
213 if(zb == nil){
214 trace(TraceLump, "readilump loadclump failed");
215 return nil;
218 if(ia->size != cl.info.uncsize){
219 seterr(EInconsist, "index and clump size mismatch");
220 freezblock(zb);
221 return nil;
223 if(ia->type != cl.info.type){
224 seterr(EInconsist, "index and clump type mismatch");
225 freezblock(zb);
226 return nil;
228 if(scorecmp(score, sc) != 0){
229 seterr(ECrash, "score mismatch");
230 freezblock(zb);
231 return nil;
234 if(rac == 0) {
235 trace(TraceLump, "readilump readahead");
236 a = ia->addr + ClumpSize + cl.info.size;
237 aa += ClumpSize + cl.info.size;
238 lreadahead(a, arena, aa, 20);
241 trace(TraceLump, "readilump success");
242 p = zblock2packet(zb, cl.info.uncsize);
243 freezblock(zb);
244 pp = packetdup(p, 0, packetsize(p));
245 trace(TraceLump, "readilump insertlump");
246 insertlump(u, pp);
247 trace(TraceLump, "readilump exit");
248 return p;