Riffle: a high-performance write-once key/value storage engine for Clojure
blog.factual.com
blog.factual.com
[0]: https://github.com/spotify/sparkey [1]: https://github.com/StefanKarpinski/bam
It's unfortunate that using the JVM means that some wheels need to be reinvented, but those are the breaks, I guess.
Whether you're mmap'ing or using read(), you're hitting the page cache before you hit disc, and potentially evicting the LRU page thereof. Glancing through the source it doesn't look like they're using actual "direct IO" (which, in order to be performant, would have to have its own caching layer).
That being the case, for lots of tiny reads & writes I'd expect mmap to be superior to read() and write().
For memory mapping to make sense you need to fetch a big chunk of data, whereas read() gets a page's worth. For the data size and read pattern described in the post, the latter is much more desirable.