5 typedef struct DCache DCache;
10 HashSize = 1<<HashLog,
11 HashMask = HashSize - 1,
18 DBlock *free; /* list of available lumps */
19 u32int now; /* ticks for usage timestamps */
20 int size; /* max. size of any block; allocated to each block */
21 DBlock **heads; /* hash table for finding address */
22 int nheap; /* number of available victims */
23 DBlock **heap; /* heap for locating victims */
24 int nblocks; /* number of blocks allocated */
25 DBlock *blocks; /* array of block descriptors */
26 u8int *mem; /* memory for all block descriptors */
31 static int downheap(int i, DBlock *b);
32 static int upheap(int i, DBlock *b);
33 static DBlock *bumpdblock(void);
34 static void delheap(DBlock *db);
35 static void fixheap(int i, DBlock *b);
38 initdcache(u32int mem)
41 u32int nblocks, blocksize;
44 if(mem < maxblocksize * 2)
45 sysfatal("need at least %d bytes for the disk cache", maxblocksize * 2);
47 sysfatal("no max. block size given for disk cache");
48 blocksize = maxblocksize;
49 nblocks = mem / blocksize;
51 fprint(2, "initialize disk cache with %d blocks of %d bytes\n", nblocks, blocksize);
52 dcache.full.l = &dcache.lock;
53 dcache.nblocks = nblocks;
54 dcache.size = blocksize;
55 dcache.heads = MKNZ(DBlock*, HashSize);
56 dcache.heap = MKNZ(DBlock*, nblocks);
57 dcache.blocks = MKNZ(DBlock, nblocks);
58 dcache.mem = MKNZ(u8int, nblocks * blocksize);
61 for(i = 0; i < nblocks; i++){
62 b = &dcache.blocks[i];
63 b->data = &dcache.mem[i * blocksize];
77 #define hashit(c) ((((c) * 0x6b43a9b5) >> (32 - HashLog)) & HashMask)
78 h = (addr >> 32) ^ addr;
83 getdblock(Part *part, u64int addr, int read)
88 size = part->blocksize;
89 if(size > dcache.size){
90 seterr(EAdmin, "block size %d too big for cache", size);
96 * look for the block in the cache
101 for(b = dcache.heads[h]; b != nil; b = b->next){
102 if(b->part == part && b->addr == addr){
105 qunlock(&stats.lock);
111 qunlock(&stats.lock);
114 * missed: locate the block with the oldest second to last use.
115 * remove it from the heap, and fix up the heap.
119 logerr(EAdmin, "all disk cache blocks in use");
120 rsleep(&dcache.full);
125 * the new block has no last use, so assume it happens sometime in the middle
126 ZZZ this is not reasonable
128 b->used = (b->used2 + dcache.now) / 2;
131 * rechain the block on the correct hash chain
133 b->next = dcache.heads[h];
146 b->used = dcache.now++;
147 if(b->heap != TWID32)
150 qunlock(&dcache.lock);
157 memset(&b->data[b->size], 0, size - b->size);
159 if(readpart(part, addr + b->size, &b->data[b->size], size - b->size) < 0){
165 stats.pcbreads += size - b->size;
166 qunlock(&stats.lock);
185 if(b->heap == TWID32)
186 upheap(dcache.nheap++, b);
187 rwakeup(&dcache.full);
190 qunlock(&dcache.lock);
195 * remove some block from use and update the free list and counters
205 dcache.free = b->next;
210 * remove blocks until we find one that is unused
211 * referenced blocks are left in the heap even though
212 * they can't be scavenged; this is simple a speed optimization
215 if(dcache.nheap == 0)
228 if(dcache.heads[h] != b)
229 sysfatal("bad hash chains in disk cache");
230 dcache.heads[h] = b->next;
232 b->prev->next = b->next;
234 b->next->prev = b->prev;
240 * delete an arbitrary block from the heap
245 fixheap(db->heap, dcache.heap[--dcache.nheap]);
250 * push an element up or down to it's correct new location
253 fixheap(int i, DBlock *b)
255 if(upheap(i, b) == i)
260 upheap(int i, DBlock *b)
267 for(; i != 0; i = p){
270 if(b->used2 - now >= bb->used2 - now)
282 downheap(int i, DBlock *b)
291 if(k >= dcache.nheap)
293 if(k + 1 < dcache.nheap && dcache.heap[k]->used2 - now > dcache.heap[k + 1]->used2 - now)
296 if(b->used2 - now <= bb->used2 - now)
308 findblock(DBlock *bb)
314 h = pbhash(bb->addr);
315 for(b = dcache.heads[h]; b != nil; b = b->next){
317 sysfatal("bad prev link");
322 sysfatal("block missing from hash table");
330 int i, k, refed, nfree;
335 for(i = 0; i < dcache.nheap; i++){
336 if(dcache.heap[i]->heap != i)
337 sysfatal("dc: mis-heaped at %d: %d", i, dcache.heap[i]->heap);
338 if(i > 0 && dcache.heap[(i - 1) >> 1]->used2 - now > dcache.heap[i]->used2 - now)
339 sysfatal("dc: bad heap ordering");
341 if(k < dcache.nheap && dcache.heap[i]->used2 - now > dcache.heap[k]->used2 - now)
342 sysfatal("dc: bad heap ordering");
344 if(k < dcache.nheap && dcache.heap[i]->used2 - now > dcache.heap[k]->used2 - now)
345 sysfatal("dc: bad heap ordering");
349 for(i = 0; i < dcache.nblocks; i++){
350 b = &dcache.blocks[i];
351 if(b->data != &dcache.mem[i * size])
352 sysfatal("dc: mis-blocked at %d", i);
353 if(b->ref && b->heap == TWID32)
358 && dcache.heap[b->heap] != b)
359 sysfatal("dc: spurious heap value");
363 for(b = dcache.free; b != nil; b = b->next){
364 if(b->addr != 0 || b->heap != TWID32)
365 sysfatal("dc: bad free list");
369 if(dcache.nheap + nfree + refed != dcache.nblocks)
370 sysfatal("dc: missing blocks: %d %d %d", dcache.nheap, refed, dcache.nblocks);
371 qunlock(&dcache.lock);