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.

I figured that that would be more expensive, and the blocks will get re-used, anyway.