Blame


1 056fe1ba 2003-11-23 devnull /*
2 056fe1ba 2003-11-23 devnull * Memory-only VtBlock cache.
3 056fe1ba 2003-11-23 devnull *
4 056fe1ba 2003-11-23 devnull * The cached Venti blocks are in the hash chains.
5 056fe1ba 2003-11-23 devnull * The cached local blocks are only in the blocks array.
6 056fe1ba 2003-11-23 devnull * The free blocks are in the heap, which is supposed to
7 056fe1ba 2003-11-23 devnull * be indexed by second-to-last use but actually
8 056fe1ba 2003-11-23 devnull * appears to be last use.
9 056fe1ba 2003-11-23 devnull */
10 056fe1ba 2003-11-23 devnull
11 056fe1ba 2003-11-23 devnull #include <u.h>
12 056fe1ba 2003-11-23 devnull #include <libc.h>
13 056fe1ba 2003-11-23 devnull #include <venti.h>
14 056fe1ba 2003-11-23 devnull
15 7252036f 2005-11-02 devnull int vtcachenread;
16 7252036f 2005-11-02 devnull int vtcachencopy;
17 7252036f 2005-11-02 devnull int vtcachenwrite;
18 6cd6f689 2006-05-05 devnull int vttracelevel;
19 056fe1ba 2003-11-23 devnull
20 056fe1ba 2003-11-23 devnull enum {
21 056fe1ba 2003-11-23 devnull BioLocal = 1,
22 056fe1ba 2003-11-23 devnull BioVenti,
23 056fe1ba 2003-11-23 devnull BioReading,
24 056fe1ba 2003-11-23 devnull BioWriting,
25 056fe1ba 2003-11-23 devnull BioEmpty,
26 cbeb0b26 2006-04-01 devnull BioVentiError
27 056fe1ba 2003-11-23 devnull };
28 056fe1ba 2003-11-23 devnull enum {
29 cbeb0b26 2006-04-01 devnull BadHeap = ~0
30 056fe1ba 2003-11-23 devnull };
31 056fe1ba 2003-11-23 devnull struct VtCache
32 056fe1ba 2003-11-23 devnull {
33 056fe1ba 2003-11-23 devnull QLock lk;
34 056fe1ba 2003-11-23 devnull VtConn *z;
35 056fe1ba 2003-11-23 devnull u32int blocksize;
36 056fe1ba 2003-11-23 devnull u32int now; /* ticks for usage time stamps */
37 056fe1ba 2003-11-23 devnull VtBlock **hash; /* hash table for finding addresses */
38 056fe1ba 2003-11-23 devnull int nhash;
39 056fe1ba 2003-11-23 devnull VtBlock **heap; /* heap for finding victims */
40 056fe1ba 2003-11-23 devnull int nheap;
41 056fe1ba 2003-11-23 devnull VtBlock *block; /* all allocated blocks */
42 056fe1ba 2003-11-23 devnull int nblock;
43 056fe1ba 2003-11-23 devnull uchar *mem; /* memory for all blocks and data */
44 a1882dc1 2004-06-17 devnull int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int);
45 056fe1ba 2003-11-23 devnull };
46 056fe1ba 2003-11-23 devnull
47 056fe1ba 2003-11-23 devnull static void cachecheck(VtCache*);
48 056fe1ba 2003-11-23 devnull
49 056fe1ba 2003-11-23 devnull VtCache*
50 e87f5d7c 2005-07-13 devnull vtcachealloc(VtConn *z, int blocksize, ulong nblock)
51 056fe1ba 2003-11-23 devnull {
52 056fe1ba 2003-11-23 devnull uchar *p;
53 056fe1ba 2003-11-23 devnull VtCache *c;
54 056fe1ba 2003-11-23 devnull int i;
55 056fe1ba 2003-11-23 devnull VtBlock *b;
56 056fe1ba 2003-11-23 devnull
57 056fe1ba 2003-11-23 devnull c = vtmallocz(sizeof(VtCache));
58 056fe1ba 2003-11-23 devnull
59 056fe1ba 2003-11-23 devnull c->z = z;
60 056fe1ba 2003-11-23 devnull c->blocksize = (blocksize + 127) & ~127;
61 056fe1ba 2003-11-23 devnull c->nblock = nblock;
62 056fe1ba 2003-11-23 devnull c->nhash = nblock;
63 056fe1ba 2003-11-23 devnull c->hash = vtmallocz(nblock*sizeof(VtBlock*));
64 056fe1ba 2003-11-23 devnull c->heap = vtmallocz(nblock*sizeof(VtBlock*));
65 056fe1ba 2003-11-23 devnull c->block = vtmallocz(nblock*sizeof(VtBlock));
66 056fe1ba 2003-11-23 devnull c->mem = vtmallocz(nblock*c->blocksize);
67 a1882dc1 2004-06-17 devnull c->write = vtwrite;
68 056fe1ba 2003-11-23 devnull
69 056fe1ba 2003-11-23 devnull p = c->mem;
70 056fe1ba 2003-11-23 devnull for(i=0; i<nblock; i++){
71 056fe1ba 2003-11-23 devnull b = &c->block[i];
72 056fe1ba 2003-11-23 devnull b->addr = NilBlock;
73 056fe1ba 2003-11-23 devnull b->c = c;
74 056fe1ba 2003-11-23 devnull b->data = p;
75 056fe1ba 2003-11-23 devnull b->heap = i;
76 056fe1ba 2003-11-23 devnull c->heap[i] = b;
77 056fe1ba 2003-11-23 devnull p += c->blocksize;
78 056fe1ba 2003-11-23 devnull }
79 056fe1ba 2003-11-23 devnull c->nheap = nblock;
80 056fe1ba 2003-11-23 devnull cachecheck(c);
81 056fe1ba 2003-11-23 devnull return c;
82 a1882dc1 2004-06-17 devnull }
83 a1882dc1 2004-06-17 devnull
84 a1882dc1 2004-06-17 devnull /*
85 a1882dc1 2004-06-17 devnull * BUG This is here so that vbackup can override it and do some
86 a1882dc1 2004-06-17 devnull * pipelining of writes. Arguably vtwrite or vtwritepacket or the
87 a1882dc1 2004-06-17 devnull * cache itself should be providing this functionality.
88 a1882dc1 2004-06-17 devnull */
89 a1882dc1 2004-06-17 devnull void
90 a1882dc1 2004-06-17 devnull vtcachesetwrite(VtCache *c, int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int))
91 a1882dc1 2004-06-17 devnull {
92 a1882dc1 2004-06-17 devnull if(write == nil)
93 a1882dc1 2004-06-17 devnull write = vtwrite;
94 a1882dc1 2004-06-17 devnull c->write = write;
95 056fe1ba 2003-11-23 devnull }
96 056fe1ba 2003-11-23 devnull
97 056fe1ba 2003-11-23 devnull void
98 056fe1ba 2003-11-23 devnull vtcachefree(VtCache *c)
99 056fe1ba 2003-11-23 devnull {
100 056fe1ba 2003-11-23 devnull int i;
101 056fe1ba 2003-11-23 devnull
102 056fe1ba 2003-11-23 devnull qlock(&c->lk);
103 056fe1ba 2003-11-23 devnull
104 056fe1ba 2003-11-23 devnull cachecheck(c);
105 056fe1ba 2003-11-23 devnull for(i=0; i<c->nblock; i++)
106 056fe1ba 2003-11-23 devnull assert(c->block[i].ref == 0);
107 056fe1ba 2003-11-23 devnull
108 056fe1ba 2003-11-23 devnull vtfree(c->hash);
109 056fe1ba 2003-11-23 devnull vtfree(c->heap);
110 056fe1ba 2003-11-23 devnull vtfree(c->block);
111 056fe1ba 2003-11-23 devnull vtfree(c->mem);
112 056fe1ba 2003-11-23 devnull vtfree(c);
113 056fe1ba 2003-11-23 devnull }
114 056fe1ba 2003-11-23 devnull
115 056fe1ba 2003-11-23 devnull static void
116 056fe1ba 2003-11-23 devnull vtcachedump(VtCache *c)
117 056fe1ba 2003-11-23 devnull {
118 056fe1ba 2003-11-23 devnull int i;
119 056fe1ba 2003-11-23 devnull VtBlock *b;
120 056fe1ba 2003-11-23 devnull
121 056fe1ba 2003-11-23 devnull for(i=0; i<c->nblock; i++){
122 056fe1ba 2003-11-23 devnull b = &c->block[i];
123 056fe1ba 2003-11-23 devnull print("cache block %d: type %d score %V iostate %d addr %d ref %d nlock %d\n",
124 056fe1ba 2003-11-23 devnull i, b->type, b->score, b->iostate, b->addr, b->ref, b->nlock);
125 056fe1ba 2003-11-23 devnull }
126 056fe1ba 2003-11-23 devnull }
127 056fe1ba 2003-11-23 devnull
128 056fe1ba 2003-11-23 devnull static void
129 056fe1ba 2003-11-23 devnull cachecheck(VtCache *c)
130 056fe1ba 2003-11-23 devnull {
131 056fe1ba 2003-11-23 devnull u32int size, now;
132 056fe1ba 2003-11-23 devnull int i, k, refed;
133 056fe1ba 2003-11-23 devnull VtBlock *b;
134 056fe1ba 2003-11-23 devnull
135 056fe1ba 2003-11-23 devnull size = c->blocksize;
136 056fe1ba 2003-11-23 devnull now = c->now;
137 056fe1ba 2003-11-23 devnull
138 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nheap; i++){
139 056fe1ba 2003-11-23 devnull if(c->heap[i]->heap != i)
140 056fe1ba 2003-11-23 devnull sysfatal("mis-heaped at %d: %d", i, c->heap[i]->heap);
141 056fe1ba 2003-11-23 devnull if(i > 0 && c->heap[(i - 1) >> 1]->used - now > c->heap[i]->used - now)
142 056fe1ba 2003-11-23 devnull sysfatal("bad heap ordering");
143 056fe1ba 2003-11-23 devnull k = (i << 1) + 1;
144 056fe1ba 2003-11-23 devnull if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now)
145 056fe1ba 2003-11-23 devnull sysfatal("bad heap ordering");
146 056fe1ba 2003-11-23 devnull k++;
147 056fe1ba 2003-11-23 devnull if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now)
148 056fe1ba 2003-11-23 devnull sysfatal("bad heap ordering");
149 056fe1ba 2003-11-23 devnull }
150 056fe1ba 2003-11-23 devnull
151 056fe1ba 2003-11-23 devnull refed = 0;
152 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nblock; i++){
153 056fe1ba 2003-11-23 devnull b = &c->block[i];
154 056fe1ba 2003-11-23 devnull if(b->data != &c->mem[i * size])
155 056fe1ba 2003-11-23 devnull sysfatal("mis-blocked at %d", i);
156 056fe1ba 2003-11-23 devnull if(b->ref && b->heap == BadHeap)
157 056fe1ba 2003-11-23 devnull refed++;
158 056fe1ba 2003-11-23 devnull else if(b->addr != NilBlock)
159 056fe1ba 2003-11-23 devnull refed++;
160 056fe1ba 2003-11-23 devnull }
161 056fe1ba 2003-11-23 devnull assert(c->nheap + refed == c->nblock);
162 056fe1ba 2003-11-23 devnull refed = 0;
163 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nblock; i++){
164 056fe1ba 2003-11-23 devnull b = &c->block[i];
165 056fe1ba 2003-11-23 devnull if(b->ref){
166 056fe1ba 2003-11-23 devnull refed++;
167 056fe1ba 2003-11-23 devnull }
168 056fe1ba 2003-11-23 devnull }
169 056fe1ba 2003-11-23 devnull }
170 056fe1ba 2003-11-23 devnull
171 056fe1ba 2003-11-23 devnull static int
172 056fe1ba 2003-11-23 devnull upheap(int i, VtBlock *b)
173 056fe1ba 2003-11-23 devnull {
174 056fe1ba 2003-11-23 devnull VtBlock *bb;
175 056fe1ba 2003-11-23 devnull u32int now;
176 056fe1ba 2003-11-23 devnull int p;
177 056fe1ba 2003-11-23 devnull VtCache *c;
178 056fe1ba 2003-11-23 devnull
179 056fe1ba 2003-11-23 devnull c = b->c;
180 056fe1ba 2003-11-23 devnull now = c->now;
181 056fe1ba 2003-11-23 devnull for(; i != 0; i = p){
182 056fe1ba 2003-11-23 devnull p = (i - 1) >> 1;
183 056fe1ba 2003-11-23 devnull bb = c->heap[p];
184 056fe1ba 2003-11-23 devnull if(b->used - now >= bb->used - now)
185 056fe1ba 2003-11-23 devnull break;
186 056fe1ba 2003-11-23 devnull c->heap[i] = bb;
187 056fe1ba 2003-11-23 devnull bb->heap = i;
188 056fe1ba 2003-11-23 devnull }
189 056fe1ba 2003-11-23 devnull c->heap[i] = b;
190 056fe1ba 2003-11-23 devnull b->heap = i;
191 056fe1ba 2003-11-23 devnull
192 056fe1ba 2003-11-23 devnull return i;
193 056fe1ba 2003-11-23 devnull }
194 056fe1ba 2003-11-23 devnull
195 056fe1ba 2003-11-23 devnull static int
196 056fe1ba 2003-11-23 devnull downheap(int i, VtBlock *b)
197 056fe1ba 2003-11-23 devnull {
198 056fe1ba 2003-11-23 devnull VtBlock *bb;
199 056fe1ba 2003-11-23 devnull u32int now;
200 056fe1ba 2003-11-23 devnull int k;
201 056fe1ba 2003-11-23 devnull VtCache *c;
202 056fe1ba 2003-11-23 devnull
203 056fe1ba 2003-11-23 devnull c = b->c;
204 056fe1ba 2003-11-23 devnull now = c->now;
205 056fe1ba 2003-11-23 devnull for(; ; i = k){
206 056fe1ba 2003-11-23 devnull k = (i << 1) + 1;
207 056fe1ba 2003-11-23 devnull if(k >= c->nheap)
208 056fe1ba 2003-11-23 devnull break;
209 056fe1ba 2003-11-23 devnull if(k + 1 < c->nheap && c->heap[k]->used - now > c->heap[k + 1]->used - now)
210 056fe1ba 2003-11-23 devnull k++;
211 056fe1ba 2003-11-23 devnull bb = c->heap[k];
212 056fe1ba 2003-11-23 devnull if(b->used - now <= bb->used - now)
213 056fe1ba 2003-11-23 devnull break;
214 056fe1ba 2003-11-23 devnull c->heap[i] = bb;
215 056fe1ba 2003-11-23 devnull bb->heap = i;
216 056fe1ba 2003-11-23 devnull }
217 056fe1ba 2003-11-23 devnull c->heap[i] = b;
218 056fe1ba 2003-11-23 devnull b->heap = i;
219 056fe1ba 2003-11-23 devnull return i;
220 056fe1ba 2003-11-23 devnull }
221 056fe1ba 2003-11-23 devnull
222 056fe1ba 2003-11-23 devnull /*
223 056fe1ba 2003-11-23 devnull * Delete a block from the heap.
224 056fe1ba 2003-11-23 devnull * Called with c->lk held.
225 056fe1ba 2003-11-23 devnull */
226 056fe1ba 2003-11-23 devnull static void
227 056fe1ba 2003-11-23 devnull heapdel(VtBlock *b)
228 056fe1ba 2003-11-23 devnull {
229 056fe1ba 2003-11-23 devnull int i, si;
230 056fe1ba 2003-11-23 devnull VtCache *c;
231 056fe1ba 2003-11-23 devnull
232 056fe1ba 2003-11-23 devnull c = b->c;
233 056fe1ba 2003-11-23 devnull
234 056fe1ba 2003-11-23 devnull si = b->heap;
235 056fe1ba 2003-11-23 devnull if(si == BadHeap)
236 056fe1ba 2003-11-23 devnull return;
237 056fe1ba 2003-11-23 devnull b->heap = BadHeap;
238 056fe1ba 2003-11-23 devnull c->nheap--;
239 056fe1ba 2003-11-23 devnull if(si == c->nheap)
240 056fe1ba 2003-11-23 devnull return;
241 056fe1ba 2003-11-23 devnull b = c->heap[c->nheap];
242 056fe1ba 2003-11-23 devnull i = upheap(si, b);
243 056fe1ba 2003-11-23 devnull if(i == si)
244 056fe1ba 2003-11-23 devnull downheap(i, b);
245 056fe1ba 2003-11-23 devnull }
246 056fe1ba 2003-11-23 devnull
247 056fe1ba 2003-11-23 devnull /*
248 056fe1ba 2003-11-23 devnull * Insert a block into the heap.
249 056fe1ba 2003-11-23 devnull * Called with c->lk held.
250 056fe1ba 2003-11-23 devnull */
251 056fe1ba 2003-11-23 devnull static void
252 056fe1ba 2003-11-23 devnull heapins(VtBlock *b)
253 056fe1ba 2003-11-23 devnull {
254 056fe1ba 2003-11-23 devnull assert(b->heap == BadHeap);
255 056fe1ba 2003-11-23 devnull upheap(b->c->nheap++, b);
256 056fe1ba 2003-11-23 devnull }
257 056fe1ba 2003-11-23 devnull
258 056fe1ba 2003-11-23 devnull /*
259 056fe1ba 2003-11-23 devnull * locate the vtBlock with the oldest second to last use.
260 056fe1ba 2003-11-23 devnull * remove it from the heap, and fix up the heap.
261 056fe1ba 2003-11-23 devnull */
262 056fe1ba 2003-11-23 devnull /* called with c->lk held */
263 056fe1ba 2003-11-23 devnull static VtBlock*
264 056fe1ba 2003-11-23 devnull vtcachebumpblock(VtCache *c)
265 056fe1ba 2003-11-23 devnull {
266 056fe1ba 2003-11-23 devnull VtBlock *b;
267 056fe1ba 2003-11-23 devnull
268 056fe1ba 2003-11-23 devnull /*
269 056fe1ba 2003-11-23 devnull * locate the vtBlock with the oldest second to last use.
270 056fe1ba 2003-11-23 devnull * remove it from the heap, and fix up the heap.
271 056fe1ba 2003-11-23 devnull */
272 056fe1ba 2003-11-23 devnull if(c->nheap == 0){
273 056fe1ba 2003-11-23 devnull vtcachedump(c);
274 7cb74894 2004-06-17 devnull fprint(2, "vtcachebumpblock: no free blocks in vtCache");
275 7cb74894 2004-06-17 devnull abort();
276 056fe1ba 2003-11-23 devnull }
277 056fe1ba 2003-11-23 devnull b = c->heap[0];
278 056fe1ba 2003-11-23 devnull heapdel(b);
279 056fe1ba 2003-11-23 devnull
280 056fe1ba 2003-11-23 devnull assert(b->heap == BadHeap);
281 056fe1ba 2003-11-23 devnull assert(b->ref == 0);
282 056fe1ba 2003-11-23 devnull
283 056fe1ba 2003-11-23 devnull /*
284 056fe1ba 2003-11-23 devnull * unchain the vtBlock from hash chain if any
285 056fe1ba 2003-11-23 devnull */
286 056fe1ba 2003-11-23 devnull if(b->prev){
287 056fe1ba 2003-11-23 devnull *(b->prev) = b->next;
288 056fe1ba 2003-11-23 devnull if(b->next)
289 056fe1ba 2003-11-23 devnull b->next->prev = b->prev;
290 056fe1ba 2003-11-23 devnull b->prev = nil;
291 056fe1ba 2003-11-23 devnull }
292 056fe1ba 2003-11-23 devnull
293 056fe1ba 2003-11-23 devnull
294 056fe1ba 2003-11-23 devnull if(0)fprint(2, "droping %x:%V\n", b->addr, b->score);
295 056fe1ba 2003-11-23 devnull /* set vtBlock to a reasonable state */
296 056fe1ba 2003-11-23 devnull b->ref = 1;
297 056fe1ba 2003-11-23 devnull b->iostate = BioEmpty;
298 056fe1ba 2003-11-23 devnull return b;
299 056fe1ba 2003-11-23 devnull }
300 056fe1ba 2003-11-23 devnull
301 056fe1ba 2003-11-23 devnull /*
302 056fe1ba 2003-11-23 devnull * fetch a local block from the memory cache.
303 056fe1ba 2003-11-23 devnull * if it's not there, load it, bumping some other Block.
304 056fe1ba 2003-11-23 devnull * if we're out of free blocks, we're screwed.
305 056fe1ba 2003-11-23 devnull */
306 056fe1ba 2003-11-23 devnull VtBlock*
307 056fe1ba 2003-11-23 devnull vtcachelocal(VtCache *c, u32int addr, int type)
308 056fe1ba 2003-11-23 devnull {
309 056fe1ba 2003-11-23 devnull VtBlock *b;
310 056fe1ba 2003-11-23 devnull
311 23fb2edb 2005-07-24 devnull if(addr == 0)
312 23fb2edb 2005-07-24 devnull sysfatal("vtcachelocal: asked for nonexistent block 0");
313 23fb2edb 2005-07-24 devnull if(addr > c->nblock)
314 23fb2edb 2005-07-24 devnull sysfatal("vtcachelocal: asked for block #%ud; only %d blocks",
315 056fe1ba 2003-11-23 devnull addr, c->nblock);
316 056fe1ba 2003-11-23 devnull
317 23fb2edb 2005-07-24 devnull b = &c->block[addr-1];
318 056fe1ba 2003-11-23 devnull if(b->addr == NilBlock || b->iostate != BioLocal)
319 056fe1ba 2003-11-23 devnull sysfatal("vtcachelocal: block is not local");
320 056fe1ba 2003-11-23 devnull
321 056fe1ba 2003-11-23 devnull if(b->type != type)
322 056fe1ba 2003-11-23 devnull sysfatal("vtcachelocal: block has wrong type %d != %d", b->type, type);
323 056fe1ba 2003-11-23 devnull
324 056fe1ba 2003-11-23 devnull qlock(&c->lk);
325 056fe1ba 2003-11-23 devnull b->ref++;
326 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
327 056fe1ba 2003-11-23 devnull
328 056fe1ba 2003-11-23 devnull qlock(&b->lk);
329 056fe1ba 2003-11-23 devnull b->nlock = 1;
330 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
331 056fe1ba 2003-11-23 devnull return b;
332 056fe1ba 2003-11-23 devnull }
333 056fe1ba 2003-11-23 devnull
334 056fe1ba 2003-11-23 devnull VtBlock*
335 056fe1ba 2003-11-23 devnull vtcacheallocblock(VtCache *c, int type)
336 056fe1ba 2003-11-23 devnull {
337 056fe1ba 2003-11-23 devnull VtBlock *b;
338 056fe1ba 2003-11-23 devnull
339 056fe1ba 2003-11-23 devnull qlock(&c->lk);
340 056fe1ba 2003-11-23 devnull b = vtcachebumpblock(c);
341 056fe1ba 2003-11-23 devnull b->iostate = BioLocal;
342 056fe1ba 2003-11-23 devnull b->type = type;
343 23fb2edb 2005-07-24 devnull b->addr = (b - c->block)+1;
344 056fe1ba 2003-11-23 devnull vtzeroextend(type, b->data, 0, c->blocksize);
345 056fe1ba 2003-11-23 devnull vtlocaltoglobal(b->addr, b->score);
346 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
347 056fe1ba 2003-11-23 devnull
348 056fe1ba 2003-11-23 devnull qlock(&b->lk);
349 056fe1ba 2003-11-23 devnull b->nlock = 1;
350 6ce75e8d 2007-04-21 devnull b->pc = getcallerpc(&c);
351 056fe1ba 2003-11-23 devnull return b;
352 056fe1ba 2003-11-23 devnull }
353 056fe1ba 2003-11-23 devnull
354 056fe1ba 2003-11-23 devnull /*
355 056fe1ba 2003-11-23 devnull * fetch a global (Venti) block from the memory cache.
356 056fe1ba 2003-11-23 devnull * if it's not there, load it, bumping some other block.
357 056fe1ba 2003-11-23 devnull */
358 056fe1ba 2003-11-23 devnull VtBlock*
359 056fe1ba 2003-11-23 devnull vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type)
360 056fe1ba 2003-11-23 devnull {
361 056fe1ba 2003-11-23 devnull VtBlock *b;
362 056fe1ba 2003-11-23 devnull ulong h;
363 056fe1ba 2003-11-23 devnull int n;
364 056fe1ba 2003-11-23 devnull u32int addr;
365 056fe1ba 2003-11-23 devnull
366 6cd6f689 2006-05-05 devnull if(vttracelevel)
367 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d from %p\n", score, type, getcallerpc(&c));
368 056fe1ba 2003-11-23 devnull addr = vtglobaltolocal(score);
369 6cd6f689 2006-05-05 devnull if(addr != NilBlock){
370 6cd6f689 2006-05-05 devnull if(vttracelevel)
371 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => local\n", score, type);
372 6fc7da3c 2006-10-19 devnull b = vtcachelocal(c, addr, type);
373 6fc7da3c 2006-10-19 devnull if(b)
374 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
375 6fc7da3c 2006-10-19 devnull return b;
376 6cd6f689 2006-05-05 devnull }
377 056fe1ba 2003-11-23 devnull
378 056fe1ba 2003-11-23 devnull h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
379 056fe1ba 2003-11-23 devnull
380 056fe1ba 2003-11-23 devnull /*
381 056fe1ba 2003-11-23 devnull * look for the block in the cache
382 056fe1ba 2003-11-23 devnull */
383 056fe1ba 2003-11-23 devnull qlock(&c->lk);
384 056fe1ba 2003-11-23 devnull for(b = c->hash[h]; b != nil; b = b->next){
385 056fe1ba 2003-11-23 devnull if(b->addr != NilBlock || memcmp(b->score, score, VtScoreSize) != 0 || b->type != type)
386 056fe1ba 2003-11-23 devnull continue;
387 056fe1ba 2003-11-23 devnull heapdel(b);
388 056fe1ba 2003-11-23 devnull b->ref++;
389 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
390 6cd6f689 2006-05-05 devnull if(vttracelevel)
391 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => found in cache %p; locking\n", score, type, b);
392 056fe1ba 2003-11-23 devnull qlock(&b->lk);
393 056fe1ba 2003-11-23 devnull b->nlock = 1;
394 0c148046 2004-06-16 devnull if(b->iostate == BioVentiError){
395 eacc220a 2004-06-17 devnull if(chattyventi)
396 eacc220a 2004-06-17 devnull fprint(2, "cached read error for %V\n", score);
397 6cd6f689 2006-05-05 devnull if(vttracelevel)
398 6df24754 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => cache read error\n", score, type);
399 0c148046 2004-06-16 devnull vtblockput(b);
400 6df24754 2006-05-05 devnull werrstr("venti i/o error");
401 0c148046 2004-06-16 devnull return nil;
402 0c148046 2004-06-16 devnull }
403 6cd6f689 2006-05-05 devnull if(vttracelevel)
404 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => found in cache; returning\n", score, type);
405 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
406 056fe1ba 2003-11-23 devnull return b;
407 056fe1ba 2003-11-23 devnull }
408 056fe1ba 2003-11-23 devnull
409 056fe1ba 2003-11-23 devnull /*
410 056fe1ba 2003-11-23 devnull * not found
411 056fe1ba 2003-11-23 devnull */
412 056fe1ba 2003-11-23 devnull b = vtcachebumpblock(c);
413 056fe1ba 2003-11-23 devnull b->addr = NilBlock;
414 056fe1ba 2003-11-23 devnull b->type = type;
415 056fe1ba 2003-11-23 devnull memmove(b->score, score, VtScoreSize);
416 056fe1ba 2003-11-23 devnull /* chain onto correct hash */
417 056fe1ba 2003-11-23 devnull b->next = c->hash[h];
418 056fe1ba 2003-11-23 devnull c->hash[h] = b;
419 056fe1ba 2003-11-23 devnull if(b->next != nil)
420 056fe1ba 2003-11-23 devnull b->next->prev = &b->next;
421 056fe1ba 2003-11-23 devnull b->prev = &c->hash[h];
422 056fe1ba 2003-11-23 devnull
423 056fe1ba 2003-11-23 devnull /*
424 056fe1ba 2003-11-23 devnull * Lock b before unlocking c, so that others wait while we read.
425 056fe1ba 2003-11-23 devnull *
426 056fe1ba 2003-11-23 devnull * You might think there is a race between this qlock(b) before qunlock(c)
427 056fe1ba 2003-11-23 devnull * and the qlock(c) while holding a qlock(b) in vtblockwrite. However,
428 056fe1ba 2003-11-23 devnull * the block here can never be the block in a vtblockwrite, so we're safe.
429 056fe1ba 2003-11-23 devnull * We're certainly living on the edge.
430 056fe1ba 2003-11-23 devnull */
431 6cd6f689 2006-05-05 devnull if(vttracelevel)
432 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => bumped; locking %p\n", score, type, b);
433 056fe1ba 2003-11-23 devnull qlock(&b->lk);
434 056fe1ba 2003-11-23 devnull b->nlock = 1;
435 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
436 056fe1ba 2003-11-23 devnull
437 7252036f 2005-11-02 devnull vtcachenread++;
438 056fe1ba 2003-11-23 devnull n = vtread(c->z, score, type, b->data, c->blocksize);
439 056fe1ba 2003-11-23 devnull if(n < 0){
440 eacc220a 2004-06-17 devnull if(chattyventi)
441 eacc220a 2004-06-17 devnull fprint(2, "read %V: %r\n", score);
442 6cd6f689 2006-05-05 devnull if(vttracelevel)
443 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => bumped; read error\n", score, type);
444 056fe1ba 2003-11-23 devnull b->iostate = BioVentiError;
445 056fe1ba 2003-11-23 devnull vtblockput(b);
446 056fe1ba 2003-11-23 devnull return nil;
447 056fe1ba 2003-11-23 devnull }
448 056fe1ba 2003-11-23 devnull vtzeroextend(type, b->data, n, c->blocksize);
449 056fe1ba 2003-11-23 devnull b->iostate = BioVenti;
450 056fe1ba 2003-11-23 devnull b->nlock = 1;
451 6cd6f689 2006-05-05 devnull if(vttracelevel)
452 6df24754 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => loaded into cache; returning\n", score, type);
453 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&b);
454 6df24754 2006-05-05 devnull return b;
455 056fe1ba 2003-11-23 devnull }
456 056fe1ba 2003-11-23 devnull
457 056fe1ba 2003-11-23 devnull /*
458 056fe1ba 2003-11-23 devnull * The thread that has locked b may refer to it by
459 056fe1ba 2003-11-23 devnull * multiple names. Nlock counts the number of
460 056fe1ba 2003-11-23 devnull * references the locking thread holds. It will call
461 056fe1ba 2003-11-23 devnull * vtblockput once per reference.
462 056fe1ba 2003-11-23 devnull */
463 056fe1ba 2003-11-23 devnull void
464 056fe1ba 2003-11-23 devnull vtblockduplock(VtBlock *b)
465 056fe1ba 2003-11-23 devnull {
466 056fe1ba 2003-11-23 devnull assert(b->nlock > 0);
467 056fe1ba 2003-11-23 devnull b->nlock++;
468 056fe1ba 2003-11-23 devnull }
469 056fe1ba 2003-11-23 devnull
470 056fe1ba 2003-11-23 devnull /*
471 056fe1ba 2003-11-23 devnull * we're done with the block.
472 056fe1ba 2003-11-23 devnull * unlock it. can't use it after calling this.
473 056fe1ba 2003-11-23 devnull */
474 056fe1ba 2003-11-23 devnull void
475 056fe1ba 2003-11-23 devnull vtblockput(VtBlock* b)
476 056fe1ba 2003-11-23 devnull {
477 056fe1ba 2003-11-23 devnull VtCache *c;
478 056fe1ba 2003-11-23 devnull
479 056fe1ba 2003-11-23 devnull if(b == nil)
480 056fe1ba 2003-11-23 devnull return;
481 056fe1ba 2003-11-23 devnull
482 056fe1ba 2003-11-23 devnull if(0)fprint(2, "vtblockput: %d: %x %d %d\n", getpid(), b->addr, c->nheap, b->iostate);
483 6cd6f689 2006-05-05 devnull if(vttracelevel)
484 6cd6f689 2006-05-05 devnull fprint(2, "vtblockput %p from %p\n", b, getcallerpc(&b));
485 056fe1ba 2003-11-23 devnull
486 056fe1ba 2003-11-23 devnull if(--b->nlock > 0)
487 056fe1ba 2003-11-23 devnull return;
488 056fe1ba 2003-11-23 devnull
489 056fe1ba 2003-11-23 devnull /*
490 056fe1ba 2003-11-23 devnull * b->nlock should probably stay at zero while
491 056fe1ba 2003-11-23 devnull * the vtBlock is unlocked, but diskThread and vtSleep
492 056fe1ba 2003-11-23 devnull * conspire to assume that they can just qlock(&b->lk); vtblockput(b),
493 056fe1ba 2003-11-23 devnull * so we have to keep b->nlock set to 1 even
494 056fe1ba 2003-11-23 devnull * when the vtBlock is unlocked.
495 056fe1ba 2003-11-23 devnull */
496 056fe1ba 2003-11-23 devnull assert(b->nlock == 0);
497 056fe1ba 2003-11-23 devnull b->nlock = 1;
498 056fe1ba 2003-11-23 devnull
499 056fe1ba 2003-11-23 devnull qunlock(&b->lk);
500 056fe1ba 2003-11-23 devnull c = b->c;
501 056fe1ba 2003-11-23 devnull qlock(&c->lk);
502 056fe1ba 2003-11-23 devnull
503 056fe1ba 2003-11-23 devnull if(--b->ref > 0){
504 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
505 056fe1ba 2003-11-23 devnull return;
506 056fe1ba 2003-11-23 devnull }
507 056fe1ba 2003-11-23 devnull
508 056fe1ba 2003-11-23 devnull assert(b->ref == 0);
509 056fe1ba 2003-11-23 devnull switch(b->iostate){
510 056fe1ba 2003-11-23 devnull case BioVenti:
511 cbeb0b26 2006-04-01 devnull /*if(b->addr != NilBlock) print("blockput %d\n", b->addr); */
512 056fe1ba 2003-11-23 devnull b->used = c->now++;
513 981672ae 2006-07-23 devnull /* fall through */
514 056fe1ba 2003-11-23 devnull case BioVentiError:
515 056fe1ba 2003-11-23 devnull heapins(b);
516 056fe1ba 2003-11-23 devnull break;
517 056fe1ba 2003-11-23 devnull case BioLocal:
518 056fe1ba 2003-11-23 devnull break;
519 056fe1ba 2003-11-23 devnull }
520 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
521 056fe1ba 2003-11-23 devnull }
522 056fe1ba 2003-11-23 devnull
523 056fe1ba 2003-11-23 devnull int
524 056fe1ba 2003-11-23 devnull vtblockwrite(VtBlock *b)
525 056fe1ba 2003-11-23 devnull {
526 056fe1ba 2003-11-23 devnull uchar score[VtScoreSize];
527 056fe1ba 2003-11-23 devnull VtCache *c;
528 056fe1ba 2003-11-23 devnull uint h;
529 056fe1ba 2003-11-23 devnull int n;
530 056fe1ba 2003-11-23 devnull
531 056fe1ba 2003-11-23 devnull if(b->iostate != BioLocal){
532 0c148046 2004-06-16 devnull werrstr("vtblockwrite: not a local block");
533 0c148046 2004-06-16 devnull return -1;
534 056fe1ba 2003-11-23 devnull }
535 056fe1ba 2003-11-23 devnull
536 056fe1ba 2003-11-23 devnull c = b->c;
537 056fe1ba 2003-11-23 devnull n = vtzerotruncate(b->type, b->data, c->blocksize);
538 7252036f 2005-11-02 devnull vtcachenwrite++;
539 a1882dc1 2004-06-17 devnull if(c->write(c->z, score, b->type, b->data, n) < 0)
540 056fe1ba 2003-11-23 devnull return -1;
541 056fe1ba 2003-11-23 devnull
542 056fe1ba 2003-11-23 devnull memmove(b->score, score, VtScoreSize);
543 056fe1ba 2003-11-23 devnull
544 056fe1ba 2003-11-23 devnull qlock(&c->lk);
545 981672ae 2006-07-23 devnull b->addr = NilBlock; /* now on venti */
546 056fe1ba 2003-11-23 devnull b->iostate = BioVenti;
547 056fe1ba 2003-11-23 devnull h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
548 056fe1ba 2003-11-23 devnull b->next = c->hash[h];
549 056fe1ba 2003-11-23 devnull c->hash[h] = b;
550 056fe1ba 2003-11-23 devnull if(b->next != nil)
551 056fe1ba 2003-11-23 devnull b->next->prev = &b->next;
552 056fe1ba 2003-11-23 devnull b->prev = &c->hash[h];
553 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
554 056fe1ba 2003-11-23 devnull return 0;
555 056fe1ba 2003-11-23 devnull }
556 056fe1ba 2003-11-23 devnull
557 056fe1ba 2003-11-23 devnull uint
558 056fe1ba 2003-11-23 devnull vtcacheblocksize(VtCache *c)
559 056fe1ba 2003-11-23 devnull {
560 056fe1ba 2003-11-23 devnull return c->blocksize;
561 056fe1ba 2003-11-23 devnull }
562 056fe1ba 2003-11-23 devnull
563 056fe1ba 2003-11-23 devnull VtBlock*
564 056fe1ba 2003-11-23 devnull vtblockcopy(VtBlock *b)
565 056fe1ba 2003-11-23 devnull {
566 056fe1ba 2003-11-23 devnull VtBlock *bb;
567 056fe1ba 2003-11-23 devnull
568 7252036f 2005-11-02 devnull vtcachencopy++;
569 056fe1ba 2003-11-23 devnull bb = vtcacheallocblock(b->c, b->type);
570 056fe1ba 2003-11-23 devnull if(bb == nil){
571 056fe1ba 2003-11-23 devnull vtblockput(b);
572 056fe1ba 2003-11-23 devnull return nil;
573 056fe1ba 2003-11-23 devnull }
574 056fe1ba 2003-11-23 devnull memmove(bb->data, b->data, b->c->blocksize);
575 056fe1ba 2003-11-23 devnull vtblockput(b);
576 6fc7da3c 2006-10-19 devnull bb->pc = getcallerpc(&b);
577 056fe1ba 2003-11-23 devnull return bb;
578 056fe1ba 2003-11-23 devnull }
579 056fe1ba 2003-11-23 devnull
580 056fe1ba 2003-11-23 devnull void
581 056fe1ba 2003-11-23 devnull vtlocaltoglobal(u32int addr, uchar score[VtScoreSize])
582 056fe1ba 2003-11-23 devnull {
583 056fe1ba 2003-11-23 devnull memset(score, 0, 16);
584 056fe1ba 2003-11-23 devnull score[16] = addr>>24;
585 056fe1ba 2003-11-23 devnull score[17] = addr>>16;
586 056fe1ba 2003-11-23 devnull score[18] = addr>>8;
587 056fe1ba 2003-11-23 devnull score[19] = addr;
588 056fe1ba 2003-11-23 devnull }
589 056fe1ba 2003-11-23 devnull
590 056fe1ba 2003-11-23 devnull
591 056fe1ba 2003-11-23 devnull u32int
592 056fe1ba 2003-11-23 devnull vtglobaltolocal(uchar score[VtScoreSize])
593 056fe1ba 2003-11-23 devnull {
594 056fe1ba 2003-11-23 devnull static uchar zero[16];
595 056fe1ba 2003-11-23 devnull if(memcmp(score, zero, 16) != 0)
596 056fe1ba 2003-11-23 devnull return NilBlock;
597 056fe1ba 2003-11-23 devnull return (score[16]<<24)|(score[17]<<16)|(score[18]<<8)|score[19];
598 056fe1ba 2003-11-23 devnull }
599 d23a617a 2004-03-15 devnull