Search code examples
javacaffeine

Caffeine cache - multiple expire configurations


Expiration can be configured in multiple ways:

  • expireAfterWrite
  • expireAfterAccess
  • expireAfter(Expiry)

While all 3 methods look helpful, internally they configure different cache variables. My question is: what is the purpose to have dedicated variables for expiration configuration. At first glance, expireAfterWrite and expireAfterAccess could be implemented reusing expireAfter(Expiry) passing a certain Expiry object.


Solution

  • This is because variable expiration, expireAfter, was introduced later in version 2.5.0. If that feature had come first then the others would have reused it, as you mentioned. There doesn't seem to be much to gain by migrating over, though, so its left as independent implementations. Laziness is probably the best answer.

    The reason variable came late is because Caffeine uses only amortized O(1) algorithms. Other caches at the time implemented variable expiration using either a O(lg n) priority queues (heap, redblack, ebtree, skiplist, or radix tree), or forced a maximum size and let the dead entry linger until size evicted. In those approaches, either cache operations slow as it grows or the pollution would degrade the hit rate.

    To my knowledge, Caffeine was the first cache to utilize a hierarchical timing wheel instead. This is algorithm is O(1) by using hashing rather than comparison to sort with. The implementation uses bitwise operations for added efficiency, e.g. shift and masks versus division and modulus. This result is a very fast and scalable approach and comparable to the fixed expiration's algorithm (a simple LRU style list). The details are summarized in this article.