2 056fe1ba 2003-11-23 devnull * Memory-only VtBlock cache.
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.
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>
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;
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
29 cbeb0b26 2006-04-01 devnull BadHeap = ~0
31 056fe1ba 2003-11-23 devnull struct VtCache
33 056fe1ba 2003-11-23 devnull QLock lk;
34 056fe1ba 2003-11-23 devnull VtConn *z;
35 056fe1ba 2003-11-23 devnull u32int now; /* ticks for usage time stamps */
36 056fe1ba 2003-11-23 devnull VtBlock **hash; /* hash table for finding addresses */
37 056fe1ba 2003-11-23 devnull int nhash;
38 056fe1ba 2003-11-23 devnull VtBlock **heap; /* heap for finding victims */
39 056fe1ba 2003-11-23 devnull int nheap;
40 056fe1ba 2003-11-23 devnull VtBlock *block; /* all allocated blocks */
41 056fe1ba 2003-11-23 devnull int nblock;
42 a1882dc1 2004-06-17 devnull int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int);
43 75d04888 2009-05-25 rsc VtBlock *dead; /* blocks we don't have memory for */
45 75d04888 2009-05-25 rsc ulong maxmem;
48 056fe1ba 2003-11-23 devnull static void cachecheck(VtCache*);
51 75d04888 2009-05-25 rsc vtcachealloc(VtConn *z, ulong maxmem)
53 056fe1ba 2003-11-23 devnull VtCache *c;
56 056fe1ba 2003-11-23 devnull VtBlock *b;
57 75d04888 2009-05-25 rsc ulong maxmem0;
59 75d04888 2009-05-25 rsc maxmem0 = maxmem;
60 056fe1ba 2003-11-23 devnull c = vtmallocz(sizeof(VtCache));
61 75d04888 2009-05-25 rsc nblock = maxmem/100/(sizeof(VtBlock)+2*sizeof(VtBlock*));
62 056fe1ba 2003-11-23 devnull c->z = z;
63 056fe1ba 2003-11-23 devnull c->nblock = nblock;
64 056fe1ba 2003-11-23 devnull c->nhash = nblock;
65 056fe1ba 2003-11-23 devnull c->hash = vtmallocz(nblock*sizeof(VtBlock*));
66 056fe1ba 2003-11-23 devnull c->heap = vtmallocz(nblock*sizeof(VtBlock*));
67 056fe1ba 2003-11-23 devnull c->block = vtmallocz(nblock*sizeof(VtBlock));
68 a1882dc1 2004-06-17 devnull c->write = vtwrite;
69 75d04888 2009-05-25 rsc maxmem -= nblock*(sizeof(VtBlock) + 2*sizeof(VtBlock*));
70 75d04888 2009-05-25 rsc maxmem -= sizeof(VtCache);
71 75d04888 2009-05-25 rsc if((long)maxmem < 0)
72 75d04888 2009-05-25 rsc sysfatal("cache size far too small: %lud", maxmem0);
73 75d04888 2009-05-25 rsc c->mem = maxmem;
75 056fe1ba 2003-11-23 devnull for(i=0; i<nblock; i++){
76 056fe1ba 2003-11-23 devnull b = &c->block[i];
77 056fe1ba 2003-11-23 devnull b->addr = NilBlock;
78 056fe1ba 2003-11-23 devnull b->c = c;
79 056fe1ba 2003-11-23 devnull b->heap = i;
80 056fe1ba 2003-11-23 devnull c->heap[i] = b;
82 056fe1ba 2003-11-23 devnull c->nheap = nblock;
83 056fe1ba 2003-11-23 devnull cachecheck(c);
84 056fe1ba 2003-11-23 devnull return c;
88 a1882dc1 2004-06-17 devnull * BUG This is here so that vbackup can override it and do some
89 a1882dc1 2004-06-17 devnull * pipelining of writes. Arguably vtwrite or vtwritepacket or the
90 a1882dc1 2004-06-17 devnull * cache itself should be providing this functionality.
93 a1882dc1 2004-06-17 devnull vtcachesetwrite(VtCache *c, int (*write)(VtConn*, uchar[VtScoreSize], uint, uchar*, int))
95 a1882dc1 2004-06-17 devnull if(write == nil)
96 a1882dc1 2004-06-17 devnull write = vtwrite;
97 a1882dc1 2004-06-17 devnull c->write = write;
101 056fe1ba 2003-11-23 devnull vtcachefree(VtCache *c)
105 056fe1ba 2003-11-23 devnull qlock(&c->lk);
107 056fe1ba 2003-11-23 devnull cachecheck(c);
108 75d04888 2009-05-25 rsc for(i=0; i<c->nblock; i++) {
109 a0899df6 2009-06-16 rsc assert(c->block[i].data == nil || c->block[i].ref == 0);
110 75d04888 2009-05-25 rsc vtfree(c->block[i].data);
113 056fe1ba 2003-11-23 devnull vtfree(c->hash);
114 056fe1ba 2003-11-23 devnull vtfree(c->heap);
115 056fe1ba 2003-11-23 devnull vtfree(c->block);
116 056fe1ba 2003-11-23 devnull vtfree(c);
119 056fe1ba 2003-11-23 devnull static void
120 056fe1ba 2003-11-23 devnull vtcachedump(VtCache *c)
123 056fe1ba 2003-11-23 devnull VtBlock *b;
125 056fe1ba 2003-11-23 devnull for(i=0; i<c->nblock; i++){
126 056fe1ba 2003-11-23 devnull b = &c->block[i];
127 056fe1ba 2003-11-23 devnull print("cache block %d: type %d score %V iostate %d addr %d ref %d nlock %d\n",
128 056fe1ba 2003-11-23 devnull i, b->type, b->score, b->iostate, b->addr, b->ref, b->nlock);
132 056fe1ba 2003-11-23 devnull static void
133 056fe1ba 2003-11-23 devnull cachecheck(VtCache *c)
136 056fe1ba 2003-11-23 devnull int i, k, refed;
137 056fe1ba 2003-11-23 devnull VtBlock *b;
139 056fe1ba 2003-11-23 devnull now = c->now;
141 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nheap; i++){
142 056fe1ba 2003-11-23 devnull if(c->heap[i]->heap != i)
143 056fe1ba 2003-11-23 devnull sysfatal("mis-heaped at %d: %d", i, c->heap[i]->heap);
144 056fe1ba 2003-11-23 devnull if(i > 0 && c->heap[(i - 1) >> 1]->used - now > c->heap[i]->used - now)
145 056fe1ba 2003-11-23 devnull sysfatal("bad heap ordering");
146 056fe1ba 2003-11-23 devnull k = (i << 1) + 1;
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");
150 056fe1ba 2003-11-23 devnull if(k < c->nheap && c->heap[i]->used - now > c->heap[k]->used - now)
151 056fe1ba 2003-11-23 devnull sysfatal("bad heap ordering");
154 056fe1ba 2003-11-23 devnull refed = 0;
155 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nblock; i++){
156 056fe1ba 2003-11-23 devnull b = &c->block[i];
157 056fe1ba 2003-11-23 devnull if(b->ref && b->heap == BadHeap)
158 056fe1ba 2003-11-23 devnull refed++;
159 056fe1ba 2003-11-23 devnull else if(b->addr != NilBlock)
160 056fe1ba 2003-11-23 devnull refed++;
162 056fe1ba 2003-11-23 devnull assert(c->nheap + refed == c->nblock);
163 056fe1ba 2003-11-23 devnull refed = 0;
164 056fe1ba 2003-11-23 devnull for(i = 0; i < c->nblock; i++){
165 056fe1ba 2003-11-23 devnull b = &c->block[i];
166 056fe1ba 2003-11-23 devnull if(b->ref){
167 056fe1ba 2003-11-23 devnull refed++;
172 056fe1ba 2003-11-23 devnull static int
173 056fe1ba 2003-11-23 devnull upheap(int i, VtBlock *b)
175 056fe1ba 2003-11-23 devnull VtBlock *bb;
176 056fe1ba 2003-11-23 devnull u32int now;
178 056fe1ba 2003-11-23 devnull VtCache *c;
180 056fe1ba 2003-11-23 devnull c = b->c;
181 056fe1ba 2003-11-23 devnull now = c->now;
182 056fe1ba 2003-11-23 devnull for(; i != 0; i = p){
183 056fe1ba 2003-11-23 devnull p = (i - 1) >> 1;
184 056fe1ba 2003-11-23 devnull bb = c->heap[p];
185 056fe1ba 2003-11-23 devnull if(b->used - now >= bb->used - now)
187 056fe1ba 2003-11-23 devnull c->heap[i] = bb;
188 056fe1ba 2003-11-23 devnull bb->heap = i;
190 056fe1ba 2003-11-23 devnull c->heap[i] = b;
191 056fe1ba 2003-11-23 devnull b->heap = i;
193 056fe1ba 2003-11-23 devnull return i;
196 056fe1ba 2003-11-23 devnull static int
197 056fe1ba 2003-11-23 devnull downheap(int i, VtBlock *b)
199 056fe1ba 2003-11-23 devnull VtBlock *bb;
200 056fe1ba 2003-11-23 devnull u32int now;
202 056fe1ba 2003-11-23 devnull VtCache *c;
204 056fe1ba 2003-11-23 devnull c = b->c;
205 056fe1ba 2003-11-23 devnull now = c->now;
206 056fe1ba 2003-11-23 devnull for(; ; i = k){
207 056fe1ba 2003-11-23 devnull k = (i << 1) + 1;
208 056fe1ba 2003-11-23 devnull if(k >= c->nheap)
210 056fe1ba 2003-11-23 devnull if(k + 1 < c->nheap && c->heap[k]->used - now > c->heap[k + 1]->used - now)
212 056fe1ba 2003-11-23 devnull bb = c->heap[k];
213 056fe1ba 2003-11-23 devnull if(b->used - now <= bb->used - now)
215 056fe1ba 2003-11-23 devnull c->heap[i] = bb;
216 056fe1ba 2003-11-23 devnull bb->heap = i;
218 056fe1ba 2003-11-23 devnull c->heap[i] = b;
219 056fe1ba 2003-11-23 devnull b->heap = i;
220 056fe1ba 2003-11-23 devnull return i;
224 056fe1ba 2003-11-23 devnull * Delete a block from the heap.
225 056fe1ba 2003-11-23 devnull * Called with c->lk held.
227 056fe1ba 2003-11-23 devnull static void
228 056fe1ba 2003-11-23 devnull heapdel(VtBlock *b)
230 056fe1ba 2003-11-23 devnull int i, si;
231 056fe1ba 2003-11-23 devnull VtCache *c;
233 056fe1ba 2003-11-23 devnull c = b->c;
235 056fe1ba 2003-11-23 devnull si = b->heap;
236 056fe1ba 2003-11-23 devnull if(si == BadHeap)
238 056fe1ba 2003-11-23 devnull b->heap = BadHeap;
239 056fe1ba 2003-11-23 devnull c->nheap--;
240 056fe1ba 2003-11-23 devnull if(si == c->nheap)
242 056fe1ba 2003-11-23 devnull b = c->heap[c->nheap];
243 056fe1ba 2003-11-23 devnull i = upheap(si, b);
244 056fe1ba 2003-11-23 devnull if(i == si)
245 056fe1ba 2003-11-23 devnull downheap(i, b);
249 056fe1ba 2003-11-23 devnull * Insert a block into the heap.
250 056fe1ba 2003-11-23 devnull * Called with c->lk held.
252 056fe1ba 2003-11-23 devnull static void
253 056fe1ba 2003-11-23 devnull heapins(VtBlock *b)
255 056fe1ba 2003-11-23 devnull assert(b->heap == BadHeap);
256 056fe1ba 2003-11-23 devnull upheap(b->c->nheap++, b);
260 056fe1ba 2003-11-23 devnull * locate the vtBlock with the oldest second to last use.
261 056fe1ba 2003-11-23 devnull * remove it from the heap, and fix up the heap.
263 056fe1ba 2003-11-23 devnull /* called with c->lk held */
264 056fe1ba 2003-11-23 devnull static VtBlock*
265 056fe1ba 2003-11-23 devnull vtcachebumpblock(VtCache *c)
267 056fe1ba 2003-11-23 devnull VtBlock *b;
270 056fe1ba 2003-11-23 devnull * locate the vtBlock with the oldest second to last use.
271 056fe1ba 2003-11-23 devnull * remove it from the heap, and fix up the heap.
273 056fe1ba 2003-11-23 devnull if(c->nheap == 0){
274 056fe1ba 2003-11-23 devnull vtcachedump(c);
275 7cb74894 2004-06-17 devnull fprint(2, "vtcachebumpblock: no free blocks in vtCache");
276 7cb74894 2004-06-17 devnull abort();
278 056fe1ba 2003-11-23 devnull b = c->heap[0];
279 056fe1ba 2003-11-23 devnull heapdel(b);
281 056fe1ba 2003-11-23 devnull assert(b->heap == BadHeap);
282 056fe1ba 2003-11-23 devnull assert(b->ref == 0);
285 056fe1ba 2003-11-23 devnull * unchain the vtBlock from hash chain if any
287 056fe1ba 2003-11-23 devnull if(b->prev){
288 056fe1ba 2003-11-23 devnull *(b->prev) = b->next;
289 056fe1ba 2003-11-23 devnull if(b->next)
290 056fe1ba 2003-11-23 devnull b->next->prev = b->prev;
291 056fe1ba 2003-11-23 devnull b->prev = nil;
295 056fe1ba 2003-11-23 devnull if(0)fprint(2, "droping %x:%V\n", b->addr, b->score);
296 056fe1ba 2003-11-23 devnull /* set vtBlock to a reasonable state */
297 056fe1ba 2003-11-23 devnull b->ref = 1;
298 056fe1ba 2003-11-23 devnull b->iostate = BioEmpty;
303 75d04888 2009-05-25 rsc * evict blocks until there is enough memory for size bytes.
305 75d04888 2009-05-25 rsc static VtBlock*
306 75d04888 2009-05-25 rsc vtcacheevict(VtCache *c, ulong size)
311 75d04888 2009-05-25 rsc * If we were out of memory and put some blocks
312 75d04888 2009-05-25 rsc * to the side but now we have memory, grab one.
314 75d04888 2009-05-25 rsc if(c->mem >= size && c->dead) {
315 75d04888 2009-05-25 rsc b = c->dead;
316 75d04888 2009-05-25 rsc c->dead = b->next;
317 75d04888 2009-05-25 rsc b->next = nil;
322 75d04888 2009-05-25 rsc * Otherwise, evict until we have memory.
325 75d04888 2009-05-25 rsc b = vtcachebumpblock(c);
326 75d04888 2009-05-25 rsc if(c->mem+b->size >= size)
329 75d04888 2009-05-25 rsc * chain b onto dead list
331 75d04888 2009-05-25 rsc free(b->data);
332 75d04888 2009-05-25 rsc b->data = nil;
333 75d04888 2009-05-25 rsc c->mem += b->size;
334 75d04888 2009-05-25 rsc b->size = 0;
335 75d04888 2009-05-25 rsc b->next = c->dead;
336 75d04888 2009-05-25 rsc c->dead = b;
340 75d04888 2009-05-25 rsc * Allocate memory for block.
343 75d04888 2009-05-25 rsc if(size > b->size || size <= b->size/2) {
344 75d04888 2009-05-25 rsc free(b->data);
345 75d04888 2009-05-25 rsc c->mem += b->size;
346 75d04888 2009-05-25 rsc c->mem -= size;
347 75d04888 2009-05-25 rsc b->size = size;
348 75d04888 2009-05-25 rsc b->data = vtmalloc(size);
350 056fe1ba 2003-11-23 devnull return b;
354 056fe1ba 2003-11-23 devnull * fetch a local block from the memory cache.
355 056fe1ba 2003-11-23 devnull * if it's not there, load it, bumping some other Block.
356 056fe1ba 2003-11-23 devnull * if we're out of free blocks, we're screwed.
358 056fe1ba 2003-11-23 devnull VtBlock*
359 056fe1ba 2003-11-23 devnull vtcachelocal(VtCache *c, u32int addr, int type)
361 056fe1ba 2003-11-23 devnull VtBlock *b;
363 23fb2edb 2005-07-24 devnull if(addr == 0)
364 23fb2edb 2005-07-24 devnull sysfatal("vtcachelocal: asked for nonexistent block 0");
365 23fb2edb 2005-07-24 devnull if(addr > c->nblock)
366 23fb2edb 2005-07-24 devnull sysfatal("vtcachelocal: asked for block #%ud; only %d blocks",
367 589ae3a3 2008-10-26 rsc (uint)addr, c->nblock);
369 23fb2edb 2005-07-24 devnull b = &c->block[addr-1];
370 056fe1ba 2003-11-23 devnull if(b->addr == NilBlock || b->iostate != BioLocal)
371 056fe1ba 2003-11-23 devnull sysfatal("vtcachelocal: block is not local");
373 056fe1ba 2003-11-23 devnull if(b->type != type)
374 056fe1ba 2003-11-23 devnull sysfatal("vtcachelocal: block has wrong type %d != %d", b->type, type);
376 056fe1ba 2003-11-23 devnull qlock(&c->lk);
377 056fe1ba 2003-11-23 devnull b->ref++;
378 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
380 056fe1ba 2003-11-23 devnull qlock(&b->lk);
381 056fe1ba 2003-11-23 devnull b->nlock = 1;
382 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
383 056fe1ba 2003-11-23 devnull return b;
386 056fe1ba 2003-11-23 devnull VtBlock*
387 75d04888 2009-05-25 rsc vtcacheallocblock(VtCache *c, int type, ulong size)
389 056fe1ba 2003-11-23 devnull VtBlock *b;
391 056fe1ba 2003-11-23 devnull qlock(&c->lk);
392 75d04888 2009-05-25 rsc b = vtcacheevict(c, size);
393 056fe1ba 2003-11-23 devnull b->iostate = BioLocal;
394 056fe1ba 2003-11-23 devnull b->type = type;
395 23fb2edb 2005-07-24 devnull b->addr = (b - c->block)+1;
396 75d04888 2009-05-25 rsc vtzeroextend(type, b->data, 0, size);
397 056fe1ba 2003-11-23 devnull vtlocaltoglobal(b->addr, b->score);
398 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
400 056fe1ba 2003-11-23 devnull qlock(&b->lk);
401 056fe1ba 2003-11-23 devnull b->nlock = 1;
402 6ce75e8d 2007-04-21 devnull b->pc = getcallerpc(&c);
403 056fe1ba 2003-11-23 devnull return b;
407 056fe1ba 2003-11-23 devnull * fetch a global (Venti) block from the memory cache.
408 056fe1ba 2003-11-23 devnull * if it's not there, load it, bumping some other block.
410 056fe1ba 2003-11-23 devnull VtBlock*
411 75d04888 2009-05-25 rsc vtcacheglobal(VtCache *c, uchar score[VtScoreSize], int type, ulong size)
413 056fe1ba 2003-11-23 devnull VtBlock *b;
414 056fe1ba 2003-11-23 devnull ulong h;
416 056fe1ba 2003-11-23 devnull u32int addr;
418 6cd6f689 2006-05-05 devnull if(vttracelevel)
419 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d from %p\n", score, type, getcallerpc(&c));
420 056fe1ba 2003-11-23 devnull addr = vtglobaltolocal(score);
421 6cd6f689 2006-05-05 devnull if(addr != NilBlock){
422 6cd6f689 2006-05-05 devnull if(vttracelevel)
423 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => local\n", score, type);
424 6fc7da3c 2006-10-19 devnull b = vtcachelocal(c, addr, type);
426 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
427 6fc7da3c 2006-10-19 devnull return b;
430 056fe1ba 2003-11-23 devnull h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
433 056fe1ba 2003-11-23 devnull * look for the block in the cache
435 056fe1ba 2003-11-23 devnull qlock(&c->lk);
436 056fe1ba 2003-11-23 devnull for(b = c->hash[h]; b != nil; b = b->next){
437 056fe1ba 2003-11-23 devnull if(b->addr != NilBlock || memcmp(b->score, score, VtScoreSize) != 0 || b->type != type)
438 056fe1ba 2003-11-23 devnull continue;
439 056fe1ba 2003-11-23 devnull heapdel(b);
440 056fe1ba 2003-11-23 devnull b->ref++;
441 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
442 6cd6f689 2006-05-05 devnull if(vttracelevel)
443 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => found in cache %p; locking\n", score, type, b);
444 056fe1ba 2003-11-23 devnull qlock(&b->lk);
445 056fe1ba 2003-11-23 devnull b->nlock = 1;
446 0c148046 2004-06-16 devnull if(b->iostate == BioVentiError){
447 eacc220a 2004-06-17 devnull if(chattyventi)
448 eacc220a 2004-06-17 devnull fprint(2, "cached read error for %V\n", score);
449 6cd6f689 2006-05-05 devnull if(vttracelevel)
450 6df24754 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => cache read error\n", score, type);
451 0c148046 2004-06-16 devnull vtblockput(b);
452 6df24754 2006-05-05 devnull werrstr("venti i/o error");
453 0c148046 2004-06-16 devnull return nil;
455 6cd6f689 2006-05-05 devnull if(vttracelevel)
456 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => found in cache; returning\n", score, type);
457 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&c);
458 056fe1ba 2003-11-23 devnull return b;
462 056fe1ba 2003-11-23 devnull * not found
464 75d04888 2009-05-25 rsc b = vtcacheevict(c, size);
465 056fe1ba 2003-11-23 devnull b->addr = NilBlock;
466 056fe1ba 2003-11-23 devnull b->type = type;
467 056fe1ba 2003-11-23 devnull memmove(b->score, score, VtScoreSize);
468 056fe1ba 2003-11-23 devnull /* chain onto correct hash */
469 056fe1ba 2003-11-23 devnull b->next = c->hash[h];
470 056fe1ba 2003-11-23 devnull c->hash[h] = b;
471 056fe1ba 2003-11-23 devnull if(b->next != nil)
472 056fe1ba 2003-11-23 devnull b->next->prev = &b->next;
473 056fe1ba 2003-11-23 devnull b->prev = &c->hash[h];
476 056fe1ba 2003-11-23 devnull * Lock b before unlocking c, so that others wait while we read.
478 056fe1ba 2003-11-23 devnull * You might think there is a race between this qlock(b) before qunlock(c)
479 056fe1ba 2003-11-23 devnull * and the qlock(c) while holding a qlock(b) in vtblockwrite. However,
480 056fe1ba 2003-11-23 devnull * the block here can never be the block in a vtblockwrite, so we're safe.
481 056fe1ba 2003-11-23 devnull * We're certainly living on the edge.
483 6cd6f689 2006-05-05 devnull if(vttracelevel)
484 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => bumped; locking %p\n", score, type, b);
485 056fe1ba 2003-11-23 devnull qlock(&b->lk);
486 056fe1ba 2003-11-23 devnull b->nlock = 1;
487 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
489 7252036f 2005-11-02 devnull vtcachenread++;
490 75d04888 2009-05-25 rsc n = vtread(c->z, score, type, b->data, size);
491 056fe1ba 2003-11-23 devnull if(n < 0){
492 eacc220a 2004-06-17 devnull if(chattyventi)
493 eacc220a 2004-06-17 devnull fprint(2, "read %V: %r\n", score);
494 6cd6f689 2006-05-05 devnull if(vttracelevel)
495 6cd6f689 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => bumped; read error\n", score, type);
496 056fe1ba 2003-11-23 devnull b->iostate = BioVentiError;
497 056fe1ba 2003-11-23 devnull vtblockput(b);
498 056fe1ba 2003-11-23 devnull return nil;
500 75d04888 2009-05-25 rsc vtzeroextend(type, b->data, n, size);
501 056fe1ba 2003-11-23 devnull b->iostate = BioVenti;
502 056fe1ba 2003-11-23 devnull b->nlock = 1;
503 6cd6f689 2006-05-05 devnull if(vttracelevel)
504 6df24754 2006-05-05 devnull fprint(2, "vtcacheglobal %V %d => loaded into cache; returning\n", score, type);
505 6fc7da3c 2006-10-19 devnull b->pc = getcallerpc(&b);
506 6df24754 2006-05-05 devnull return b;
510 056fe1ba 2003-11-23 devnull * The thread that has locked b may refer to it by
511 056fe1ba 2003-11-23 devnull * multiple names. Nlock counts the number of
512 056fe1ba 2003-11-23 devnull * references the locking thread holds. It will call
513 056fe1ba 2003-11-23 devnull * vtblockput once per reference.
516 056fe1ba 2003-11-23 devnull vtblockduplock(VtBlock *b)
518 056fe1ba 2003-11-23 devnull assert(b->nlock > 0);
519 056fe1ba 2003-11-23 devnull b->nlock++;
523 056fe1ba 2003-11-23 devnull * we're done with the block.
524 056fe1ba 2003-11-23 devnull * unlock it. can't use it after calling this.
527 056fe1ba 2003-11-23 devnull vtblockput(VtBlock* b)
529 056fe1ba 2003-11-23 devnull VtCache *c;
531 056fe1ba 2003-11-23 devnull if(b == nil)
534 056fe1ba 2003-11-23 devnull if(0)fprint(2, "vtblockput: %d: %x %d %d\n", getpid(), b->addr, c->nheap, b->iostate);
535 6cd6f689 2006-05-05 devnull if(vttracelevel)
536 6cd6f689 2006-05-05 devnull fprint(2, "vtblockput %p from %p\n", b, getcallerpc(&b));
538 056fe1ba 2003-11-23 devnull if(--b->nlock > 0)
542 056fe1ba 2003-11-23 devnull * b->nlock should probably stay at zero while
543 056fe1ba 2003-11-23 devnull * the vtBlock is unlocked, but diskThread and vtSleep
544 056fe1ba 2003-11-23 devnull * conspire to assume that they can just qlock(&b->lk); vtblockput(b),
545 056fe1ba 2003-11-23 devnull * so we have to keep b->nlock set to 1 even
546 056fe1ba 2003-11-23 devnull * when the vtBlock is unlocked.
548 056fe1ba 2003-11-23 devnull assert(b->nlock == 0);
549 056fe1ba 2003-11-23 devnull b->nlock = 1;
551 056fe1ba 2003-11-23 devnull qunlock(&b->lk);
552 056fe1ba 2003-11-23 devnull c = b->c;
553 056fe1ba 2003-11-23 devnull qlock(&c->lk);
555 056fe1ba 2003-11-23 devnull if(--b->ref > 0){
556 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
560 056fe1ba 2003-11-23 devnull assert(b->ref == 0);
561 056fe1ba 2003-11-23 devnull switch(b->iostate){
562 056fe1ba 2003-11-23 devnull case BioVenti:
563 cbeb0b26 2006-04-01 devnull /*if(b->addr != NilBlock) print("blockput %d\n", b->addr); */
564 056fe1ba 2003-11-23 devnull b->used = c->now++;
565 981672ae 2006-07-23 devnull /* fall through */
566 056fe1ba 2003-11-23 devnull case BioVentiError:
567 056fe1ba 2003-11-23 devnull heapins(b);
569 056fe1ba 2003-11-23 devnull case BioLocal:
572 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
576 056fe1ba 2003-11-23 devnull vtblockwrite(VtBlock *b)
578 056fe1ba 2003-11-23 devnull uchar score[VtScoreSize];
579 056fe1ba 2003-11-23 devnull VtCache *c;
583 056fe1ba 2003-11-23 devnull if(b->iostate != BioLocal){
584 0c148046 2004-06-16 devnull werrstr("vtblockwrite: not a local block");
585 0c148046 2004-06-16 devnull return -1;
588 056fe1ba 2003-11-23 devnull c = b->c;
589 75d04888 2009-05-25 rsc n = vtzerotruncate(b->type, b->data, b->size);
590 7252036f 2005-11-02 devnull vtcachenwrite++;
591 a1882dc1 2004-06-17 devnull if(c->write(c->z, score, b->type, b->data, n) < 0)
592 056fe1ba 2003-11-23 devnull return -1;
594 056fe1ba 2003-11-23 devnull memmove(b->score, score, VtScoreSize);
596 056fe1ba 2003-11-23 devnull qlock(&c->lk);
597 981672ae 2006-07-23 devnull b->addr = NilBlock; /* now on venti */
598 056fe1ba 2003-11-23 devnull b->iostate = BioVenti;
599 056fe1ba 2003-11-23 devnull h = (u32int)(score[0]|(score[1]<<8)|(score[2]<<16)|(score[3]<<24)) % c->nhash;
600 056fe1ba 2003-11-23 devnull b->next = c->hash[h];
601 056fe1ba 2003-11-23 devnull c->hash[h] = b;
602 056fe1ba 2003-11-23 devnull if(b->next != nil)
603 056fe1ba 2003-11-23 devnull b->next->prev = &b->next;
604 056fe1ba 2003-11-23 devnull b->prev = &c->hash[h];
605 056fe1ba 2003-11-23 devnull qunlock(&c->lk);
606 056fe1ba 2003-11-23 devnull return 0;
609 056fe1ba 2003-11-23 devnull VtBlock*
610 056fe1ba 2003-11-23 devnull vtblockcopy(VtBlock *b)
612 056fe1ba 2003-11-23 devnull VtBlock *bb;
614 7252036f 2005-11-02 devnull vtcachencopy++;
615 75d04888 2009-05-25 rsc bb = vtcacheallocblock(b->c, b->type, b->size);
616 056fe1ba 2003-11-23 devnull if(bb == nil){
617 056fe1ba 2003-11-23 devnull vtblockput(b);
618 056fe1ba 2003-11-23 devnull return nil;
620 75d04888 2009-05-25 rsc memmove(bb->data, b->data, b->size);
621 056fe1ba 2003-11-23 devnull vtblockput(b);
622 6fc7da3c 2006-10-19 devnull bb->pc = getcallerpc(&b);
623 056fe1ba 2003-11-23 devnull return bb;
627 056fe1ba 2003-11-23 devnull vtlocaltoglobal(u32int addr, uchar score[VtScoreSize])
629 056fe1ba 2003-11-23 devnull memset(score, 0, 16);
630 056fe1ba 2003-11-23 devnull score[16] = addr>>24;
631 056fe1ba 2003-11-23 devnull score[17] = addr>>16;
632 056fe1ba 2003-11-23 devnull score[18] = addr>>8;
633 056fe1ba 2003-11-23 devnull score[19] = addr;
638 056fe1ba 2003-11-23 devnull vtglobaltolocal(uchar score[VtScoreSize])
640 056fe1ba 2003-11-23 devnull static uchar zero[16];
641 056fe1ba 2003-11-23 devnull if(memcmp(score, zero, 16) != 0)
642 056fe1ba 2003-11-23 devnull return NilBlock;
643 056fe1ba 2003-11-23 devnull return (score[16]<<24)|(score[17]<<16)|(score[18]<<8)|score[19];