Class MRUCache<K,V>

java.lang.Object
java.util.AbstractMap<K,V>
java.util.HashMap<K,V>
com.randomnoun.common.MRUCache<K,V>
All Implemented Interfaces:
Serializable, Cloneable, Map<K,V>

public class MRUCache<K,V> extends HashMap<K,V>
Most-recently used cache class.

You probably want to use something in the guava Collections library these days instead.

This class can be used to implement serverside data caches. The constructor takes three parameters: maximum size, expiry time (in milliseconds) and a 'RetrievalCallback' object (defined as an interface in this class).

As items are put into this object, they are timestamped; if a key is applied to retrieve an object that has 'expired', then this object will return null (if no callback has been supplied), or will execute the callback to refresh the value. A callback can (optionally) be supplied with every get() invocation so that this object knows precisely how to generate the requested object. (This works since it is usually computationally cheaper to generate the Callback object than to generate the result of the callback, which generally needs to fetch information from a database).

There are two possible expiry mechanisms: either an item is expired from the time it is entered into the cache, or expired from the time it is last retrieved from the cache. The former makes sense for 'dynamic' data that may change over time (e.g. rowcounts); the latter makes sense for 'static' data that is just used to cache large objects that don't need to be in memory at all times (e.g. message definitions). By default this object will operate as per 'static' rules; the other method can be selected by calling the setDynamicCaching() after construction.

Implementation notes

It may be possible to extend this class to use WeakReferences, so that it can shrink in size as memory constraints within the VM become increased. This is unlikely to be useful in practice, however, since this is probably an indication of a memory leak or over-utilised server. It may make more sense to just reduce the maximum size in these cases. Performance tuning would be required to know for sure.

Also note that if an object exceeds it's expiryTime, it is *not* automatically removed from the cache. This would involve having an additional Timer thread running through these objects and scanning for expired objects, which is unlikely to be useful in practice. An additional method could be implemented to trigger these cleanups if this becomes necessary.

Author:
knoxg
See Also:
  • Field Details

    • logger

      public static org.apache.log4j.Logger logger
      Logger instance for this class
  • Constructor Details

    • MRUCache

      public MRUCache(int cacheSize, int expiryTime, MRUCache.RetrievalCallback<K,V> callback)
      Creates a new MRUCache object.
      Parameters:
      cacheSize - The maximum number of elements that this cache can hold. A value <=0 means that the size of this map is not limited.
      expiryTime - The amount of time (in ms) an entry can remain valid, measured from when the element is first added to the cache (or last retrieved if setDynamicCaching() is in effect. A value <=0 means that items do not have an expiry period.
      callback - A callback which can be used to populate entries in the cache that are unknown, or have expired. This parameter can be set to null if and only if the two-parameter get(Object, RetrievalCallback) method is used to retrieve elements from the map.
  • Method Details

    • get

      public V get(Object key)
      Retrieve an element from the cache. If a callback was defined in the cache constructor, then this will be used to refresh values in the cache if they are missing, or have expired.
      Specified by:
      get in interface Map<K,V>
      Overrides:
      get in class HashMap<K,V>
      Parameters:
      key - key whose associated value is to be returned
      Returns:
      the value to which this map maps the specified key, or null if the map contains no mapping for this key.
    • get

      public V get(K key, MRUCache.RetrievalCallback<K,V> callback)
      Retrieves an element from the cache. The supplied callback will be used to refresh the value in the cache if it is missing, or has expired. If the requested element is missing and the callback is set to null, then null is returned.
      Parameters:
      key - key whose associated value is to be returned
      callback - a callback used to populate the cache if necessary
      Returns:
      the value to which this map maps the specified key, or null if the map contains no mapping for this key.
    • getNoCallback

      public Object getNoCallback(Object key)
      Returns the object if it is in the cache and has not expired. This method will return null if the the key is not in cache, or if it is in the cache but has expired.
      Parameters:
      key - key whose associated value is to be returned
      Returns:
      the value to which this map maps the specified key, or null if the map contains no mapping for this key.
    • put

      public V put(K key, V value)
      Add an element into the cache.
      Specified by:
      put in interface Map<K,V>
      Overrides:
      put in class HashMap<K,V>
      Parameters:
      key - key with which the specified value is to be associated.
      value - value to be associated with the specified key.
      Returns:
      the previous value of this map entry, if one exists, otherwise null
    • setDynamicCaching

      public void setDynamicCaching()
      Enforces dynamic caching rules. When called, data will be expired from the time it is entered into the cache, rather than the time if is fetched from the cache. Suitable when we wish to apply a strict expiry time for dynamically-updating data, e.g. rowcounts.