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.

Please leave this the other way, so as not to hold the lock unnecessarily while encoding.  It's minor, but more correct and not particularly difficult to read.