Adam Heath wrote:
Ok, this is a cute bug.
Under the hood, UtilCache makes use of java.util.LinkedHashMap when
maxMemSize is set. It configures LinkedHashMap to act like a LRU map;
every access reorders the internal linked list. Access here is
defined as a call to get(key).
The problem is that to handle element expiration, UtilCache must call
get(key) on LinkedHashMap. This causes the key to be accessed, which
pushes it to the front of the linked list, and breaks the LRU contract.
The way to fix this is to switch UtilCache away from a polling
mechanism for expiration. Instead, a DelayQueue can be used, where
every single CacheLine is registered into a single, static DelayQueue,
and a thread is started that is always polling from that. When an
item is returned from the poll, it removes it from it's containing cache.
This is the only way I see to get UtilCache make to being a proper LRU
system.
I think it would help if the original cache design decisions were
available so we can understand why things were set up that way.
The first question that comes to my mind is: Why does the cache need to
be polled? It seems to me the max memory size would need to be checked
only when a new item is about to be placed in the cache.