Add on-disk caching with readahead. The cache will grow to a maximum size and then start recycling blocks. Block allocations are tracked in the leveldb, and cached data is stored in files on disk.

Done.