Tuesday, August 25, 2009

Block Cache Algorithm

I need to replace my old filesystem cache algorithm with something more new and efficient. The old one is based on LRU/LFU algorithm. There's a queue of cached blocks and an Hashtable to speedup block lookup.


struct blkcache_buf {
struct blkcache_buf * next; /* Next Queue Item */
struct blkcache_buf * prev; /* Prev Queue Item */
struct blkcache_buf * hash; /* Next Item with the same hash */

xuint16_t count; /* Retain count */
xxx_block_t block; /* Cached Block */
};

typedef struct {
struct blkcache_buf ** buf_hash; /* Bufs Hashtable */
xuint16_t buf_hash_size; /* Bufs Hashtable Size */
xuint16_t buf_used; /* Bufs in use */

struct blkcache_buf * head; /* Head of the Bufs Queue */
struct blkcache_buf * tail; /* Tail of the Bufs Queue */

xxx_device_t * device; /* Block Device used for I/O */
} xxx_blkcache_t;


Above, you can see the cache data structure and below the core of the cache Algorithm.


#define BUFHASH(cache, blocknr) ((blocknr) % (cache)->buf_hash_size)

xxx_block_t *xxx_blkcache_read (xxx_blkcache_t *cache,
xxx_blkptr_t blocknr)
{
struct blkcache_buf *buf;
xuint16_t hash_index;

/* Scan the hash chain for block */
hash_index = BUFHASH(cache, blocknr);
if ((buf = __blkcache_find(cache, blocknr, hash_index)) != NULL) {
buf->count++;

/* Move Buf far from head */
__blkcache_buf_shift(cache, buf);

return(&(buf->block));
}

/* Cache is Full, Remove one Item */
if ((cache->buf_used + 1) > cache->buf_hash_size) {
/* All buffers are in use */
if (cache->head->count > 0)
return(NULL);

/* Remove Least-Frequently Used */
buf = __blkcache_remove_lfu(cache);
cache->buf_used--;
}

/* Desidered block is not on available chain, Read It! */
if ((buf = __blkcache_buf_alloc(cache, buf, blocknr)) == NULL)
return(NULL);

/* Add One Use, Block cannot be removed */
buf->count++;

/* Go get the requested block unless searching or prefetching. */
__blkcache_readwrite(cache, buf, RFALSE);

/* Update Cache Hash */
cache->buf_used++;
buf->hash = cache->buf_hash[hash_index];
cache->buf_hash[hash_index] = buf;

/* Update Cache Queue */
if (cache->head == NULL) {
cache->head = cache->tail = buf;
} else {
buf->prev = cache->tail;
cache->tail->next = buf;
cache->tail = buf;
}

return(&(buf->block));
}


You can download a demo implementation here: lru-block-cache.c, but I'm waiting some ideas or suggestions to improve (or change radically) the Cache Algorithm. Thanks in advance!

1 comment:

  1. [...] I’m thinking and waiting for suggestions on how to improve my file-system block cache algorithm, I’ve decided to apply some changes to the Raleigh File-System Format (source code is not [...]

    ReplyDelete