Class HeapCache<K,​V>

  • All Implemented Interfaces:
    AutoCloseable, org.cache2k.Cache<K,​V>, InternalCache<K,​V>, InternalCacheCloseContext, HeapCacheForEviction<K,​V>, TimerEventListener<K,​V>, org.cache2k.DataAware<K,​V>, org.cache2k.KeyValueSource<K,​V>
    Direct Known Subclasses:
    IntHeapCache

    public class HeapCache<K,​V>
    extends BaseCache<K,​V>
    implements HeapCacheForEviction<K,​V>
    Foundation for all cache variants. All common functionality is in here. For a (in-memory) cache we need three things: a fast hash table implementation, an LRU list (a simple double linked list), and a fast timer. The variants implement different eviction strategies.

    Locking: The cache has a single structure lock obtained via lock and also locks on each entry for operations on it. Though, mutation operations that happen on a single entry get serialized.

    Author:
    Jens Wilke
    • Field Detail

      • DEFAULT_EXCEPTION_PROPAGATOR

        public static final org.cache2k.io.ExceptionPropagator DEFAULT_EXCEPTION_PROPAGATOR
      • name

        protected final String name
      • loader

        protected final org.cache2k.io.AdvancedCacheLoader<K,​V> loader
      • clock

        protected org.cache2k.operation.TimeReference clock
      • timing

        protected Timing<K,​V> timing
      • lock

        public final Object lock
        Structure lock of the cache. Every operation that needs a consistent structure of the cache or modifies it needs to synchronize on this. Since this is a global lock, locking on it should be avoided and any operation under the lock should be quick.
      • keyMutationCnt

        protected volatile long keyMutationCnt
        Counts the number of key mutations. The count is not guarded and racy, but does not need to be exact. We don't put it to the metrics, because we do not want to have this disabled.
      • clearedTime

        protected long clearedTime
      • startedTime

        protected long startedTime
      • clearRemovedCnt

        protected long clearRemovedCnt
        Number of entries removed by clear. Guarded by: lock
      • clearCnt

        protected long clearCnt
        Number of clear operations. Guarded by: lock
      • hash

        protected final Hash2<K,​V> hash
      • keyType

        protected org.cache2k.config.CacheType keyType
      • valueType

        protected org.cache2k.config.CacheType valueType
      • exceptionPropagator

        protected final org.cache2k.io.ExceptionPropagator<K,​V> exceptionPropagator
    • Method Detail

      • getTiming

        public Timing<K,​V> getTiming()
        Used for tests
      • getLoaderExecutor

        public Executor getLoaderExecutor()
      • isKeepAfterExpired

        protected final boolean isKeepAfterExpired()
      • isRejectNullValues

        protected final boolean isRejectNullValues()
      • isRefreshAhead

        public final boolean isRefreshAhead()
      • isUpdateTimeNeeded

        protected final boolean isUpdateTimeNeeded()
        No need to update the entry last modification time. False, if no time dependent expiry calculations are done.
      • isRecordRefreshTime

        protected final boolean isRecordRefreshTime()
      • getLog

        public Log getLog()
        Normally a cache itself logs nothing, so just construct when needed. Not requesting the log at startup means that the potential log target is not showing up in some management interfaces. This is intentional, since if caches are created and closed dynamically, we would have a memory leak, since logs can not be closed.
        Specified by:
        getLog in interface InternalCache<K,​V>
      • setTiming

        public void setTiming​(Timing<K,​V> rh)
      • getKeyType

        public org.cache2k.config.CacheType getKeyType()
        Specified by:
        getKeyType in interface InternalCache<K,​V>
      • init

        public void init()
      • initWithoutTimerHandler

        public void initWithoutTimerHandler()
      • checkClosed

        public void checkClosed()
      • clear

        public final void clear()
        Specified by:
        clear in interface org.cache2k.Cache<K,​V>
      • clearLocalCache

        public final void clearLocalCache()
      • cancelTimerJobs

        public void cancelTimerJobs()
        Preparation for shutdown. Cancel all pending timer jobs e.g. for expiry/refresh or flushing the storage.
        Specified by:
        cancelTimerJobs in interface InternalCache<K,​V>
      • isClosed

        public boolean isClosed()
        Specified by:
        isClosed in interface org.cache2k.Cache<K,​V>
      • close

        public void close()
        Specified by:
        close in interface AutoCloseable
        Specified by:
        close in interface org.cache2k.Cache<K,​V>
      • closePart2

        public void closePart2​(InternalCache userCache)
      • recordHit

        protected void recordHit​(Entry e)
        Increment the hit counter, because entry was accessed.

        The hit counter is a dirty counter. In case of multiple CPU cores incrementing the same entry counter, increments will be lost. For the functionality of the eviction algorithm this is not a real loss, since still the most accessed entries will have more counts then the others. On 32 bit systems word tearing may occur. This will also have no real observable negative impact on the eviction, so we do not compensate for it.

        The hit count is also used for access statistics. The dirty counting will effect the exact correctness of the access statistics.

        Using a 64 bit counter per entry is basically a big waste of memory. When reducing to a 32 bit value is has approximately a negative performance impact of 30%.

      • get

        public V get​(K key)
        Specified by:
        get in interface org.cache2k.Cache<K,​V>
        Specified by:
        get in interface org.cache2k.KeyValueSource<K,​V>
      • returnEntry

        protected org.cache2k.CacheEntry<K,​V> returnEntry​(ExaminationEntry<K,​V> e)
        Wrap entry in a separate object instance. We can return the entry directly, however we lock on the entry object.
      • returnCacheEntry

        public org.cache2k.CacheEntry<K,​V> returnCacheEntry​(ExaminationEntry<K,​V> entry)
        Construct a new CacheEntry for the cache client. We cannot return an internal cache entry object since this it is mutable.
        Specified by:
        returnCacheEntry in interface InternalCache<K,​V>
      • returnCacheEntry

        public org.cache2k.CacheEntry<K,​V> returnCacheEntry​(K key,
                                                                  Object valueOrException)
        In case of an exception we can return the wrapper directly since it implements the CacheEntry interface and is immutable. If it is not a wrapper we construct a CacheEntry object.
      • getEntry

        public org.cache2k.CacheEntry<K,​V> getEntry​(K key)
        Specified by:
        getEntry in interface org.cache2k.Cache<K,​V>
      • getEntryInternal

        protected Entry<K,​V> getEntryInternal​(K key)
      • getEntryInternal

        protected Entry<K,​V> getEntryInternal​(K key,
                                                    int hc,
                                                    int val)
      • finishLoadOrEviction

        protected void finishLoadOrEviction​(Entry<K,​V> e,
                                            long nextRefreshTime)
      • removeEntry

        protected boolean removeEntry​(Entry<K,​V> e)
        Remove the entry from the hash and the replacement list. There is a race condition to catch: The eviction may run in a parallel thread and may have already selected this entry.
      • peekAndPut

        public V peekAndPut​(K key,
                            V value)
        Specified by:
        peekAndPut in interface org.cache2k.Cache<K,​V>
      • peekAndReplace

        public V peekAndReplace​(K key,
                                V value)
        Specified by:
        peekAndReplace in interface org.cache2k.Cache<K,​V>
      • putValue

        protected final void putValue​(Entry<K,​V> e,
                                      V value)
        Update the value directly within entry lock. Since we did not start entry processing we do not need to notify any waiting threads.
      • replace

        public boolean replace​(K key,
                               V newValue)
        Specified by:
        replace in interface org.cache2k.Cache<K,​V>
      • replaceIfEquals

        public boolean replaceIfEquals​(K key,
                                       V oldValue,
                                       V newValue)
        Specified by:
        replaceIfEquals in interface org.cache2k.Cache<K,​V>
      • replace

        protected boolean replace​(K key,
                                  boolean compare,
                                  V oldValue,
                                  V newValue)
        replace if value matches. if value not matches, return the existing entry or the dummy entry.
      • peekEntryInternal

        protected final Entry<K,​V> peekEntryInternal​(K key)
        Return the entry, if it is in the cache, without invoking the cache source.

        The cache storage is asked whether the entry is present. If the entry is not present, this result is cached in the local cache.

      • peekEntryInternal

        protected final Entry<K,​V> peekEntryInternal​(K key,
                                                           int hc,
                                                           int val)
      • containsKey

        public boolean containsKey​(K key)
        Specified by:
        containsKey in interface org.cache2k.Cache<K,​V>
      • peek

        public V peek​(K key)
        Specified by:
        peek in interface org.cache2k.Cache<K,​V>
      • peekEntry

        public org.cache2k.CacheEntry<K,​V> peekEntry​(K key)
        Specified by:
        peekEntry in interface org.cache2k.Cache<K,​V>
      • computeIfAbsent

        public V computeIfAbsent​(K key,
                                 Function<? super K,​? extends V> function)
        Code duplicates with Cache.get(Object)
        Specified by:
        computeIfAbsent in interface org.cache2k.Cache<K,​V>
      • putIfAbsent

        public boolean putIfAbsent​(K key,
                                   V value)
        Specified by:
        putIfAbsent in interface org.cache2k.Cache<K,​V>
      • put

        public void put​(K key,
                        V value)
        Specified by:
        put in interface org.cache2k.Cache<K,​V>
      • containsAndRemove

        public boolean containsAndRemove​(K key)
        Specified by:
        containsAndRemove in interface org.cache2k.Cache<K,​V>
      • removeIfEquals

        public boolean removeIfEquals​(K key,
                                      V value)
        Remove the object from the cache.
        Specified by:
        removeIfEquals in interface org.cache2k.Cache<K,​V>
      • remove

        public void remove​(K key)
        Specified by:
        remove in interface org.cache2k.Cache<K,​V>
      • peekAndRemove

        public V peekAndRemove​(K key)
        Specified by:
        peekAndRemove in interface org.cache2k.Cache<K,​V>
      • getRefreshExecutor

        public Executor getRefreshExecutor()
      • executeLoader

        public void executeLoader​(Runnable r)
        Execute with loader executor and back pressure. In case the execution is rejected because there are not enough threads available, the task is executed in the calling thread to produce back pressure. If callers should never block upon a loadAll the executor must have a unbound queue.
      • generateKeySet

        public static <K> Set<K> generateKeySet​(Iterable<? extends K> keys)
        Generate a set of unique keys from the iterable. Optimize if its already a set or an collection.
      • checkAllPresent

        public Set<K> checkAllPresent​(Iterable<? extends K> keys)
        Checks for entries being present and fresh. Used by loadAll and prefetchAll
        Parameters:
        keys - keys to check for
        Returns:
        keys not present in the cache
      • loadAndReplace

        protected Entry<K,​V> loadAndReplace​(K key)
        Always fetch the value from the source. That is a copy of getEntryInternal without freshness checks.
      • lookupOrNewEntry

        protected Entry<K,​V> lookupOrNewEntry​(K key)
        Lookup or create a new entry. The new entry is created, because we need it for locking within the data fetch.
      • lookupOrNewEntry

        protected Entry<K,​V> lookupOrNewEntry​(K key,
                                                    int hc,
                                                    int val)
      • lookupOrNewEntryNoHitRecord

        protected Entry<K,​V> lookupOrNewEntryNoHitRecord​(K key)
      • returnValue

        public static <V> V returnValue​(Object v)
      • returnValue

        protected V returnValue​(Entry<K,​V> e)
      • lookupEntry

        protected Entry<K,​V> lookupEntry​(K key)
      • lookupEntryNoHitRecord

        protected Entry<K,​V> lookupEntryNoHitRecord​(K key)
      • lookupEntry

        protected final Entry<K,​V> lookupEntry​(K key,
                                                     int hc,
                                                     int val)
      • lookupEntryNoHitRecord

        protected final Entry<K,​V> lookupEntryNoHitRecord​(K key,
                                                                int hc,
                                                                int val)
      • insertNewEntry

        protected Entry<K,​V> insertNewEntry​(K key,
                                                  int hc,
                                                  int val)
        Insert new entry in all structures (hash and eviction). The insert at the eviction needs to be done under the same lock, to allow a check of the consistency.
      • removeEntryForEviction

        public void removeEntryForEviction​(Entry<K,​V> e)
        Remove the entry from the hash table. The entry is already removed from the replacement list. Stop the timer, if needed. The remove races with a clear. The clear is not updating each entry state to e.isGone() but just drops the whole hash table instead.

        With completion of the method the entry content is no more visible. "Nulling" out the key or value of the entry is incorrect, since there can be another thread which is just about to return the entry contents.

        Specified by:
        removeEntryForEviction in interface HeapCacheForEviction<K,​V>
      • load

        protected void load​(Entry<K,​V> e)
      • insertOrUpdateAndCalculateExpiry

        protected final void insertOrUpdateAndCalculateExpiry​(Entry<K,​V> e,
                                                              V v,
                                                              long t0,
                                                              long t,
                                                              long refreshTime,
                                                              byte updateStatistics)
        Calculate the next refresh time if a timer / expiry is needed and call insert.
      • returnNullValueDetectedException

        public RuntimeException returnNullValueDetectedException()
      • insert

        protected final void insert​(Entry<K,​V> e,
                                    V value,
                                    long t0,
                                    long t,
                                    long refreshTime,
                                    byte updateStatistics,
                                    long nextRefreshTime)
      • startRefreshProbationTimer

        public void startRefreshProbationTimer​(Entry<K,​V> e,
                                               long nextRefreshTime)
      • timerEventExpireEntry

        public void timerEventExpireEntry​(Entry<K,​V> e,
                                          Object task)
        Description copied from interface: TimerEventListener
        Called by the timer when an entry is expired or before actual expiry when the entry needs to switch into sharp expiry mode. The actual action to be performed is detected by checking the Entry.getNextRefreshTime()
        Specified by:
        timerEventExpireEntry in interface TimerEventListener<K,​V>
        task - timer task as returned by Entry.getTask() to check whether the timer task is still valid after we obtained the entry lock
      • expireEntry

        protected void expireEntry​(Entry<K,​V> e)
      • iterateAllHeapEntries

        public final ConcurrentEntryIterator<K,​V> iterateAllHeapEntries()
        Returns all cache entries within the heap cache. Entries that are expired or contain no valid data are not filtered out.
      • getAll

        public Map<K,​V> getAll​(Iterable<? extends K> inputKeys)
        JSR107 bulk interface. The behaviour is compatible to the JSR107 TCK. We also need to be compatible to the exception handling policy, which says that the exception is to be thrown when most specific. So exceptions are only thrown, when the value which has produced an exception is requested from the map.
        Specified by:
        getAll in interface org.cache2k.Cache<K,​V>
      • convertValueMap

        public Map<K,​V> convertValueMap​(Map<K,​Object> map)
      • convertCacheEntry2ValueMap

        public Map<K,​V> convertCacheEntry2ValueMap​(Map<K,​org.cache2k.CacheEntry<K,​V>> map)
      • peekAll

        public Map<K,​V> peekAll​(Iterable<? extends K> inputKeys)
        Specified by:
        peekAll in interface org.cache2k.Cache<K,​V>
      • putAll

        public void putAll​(Map<? extends K,​? extends V> valueMap)
        Specified by:
        putAll in interface org.cache2k.Cache<K,​V>
      • invoke

        public <R> R invoke​(K key,
                            org.cache2k.processor.EntryProcessor<K,​V,​R> processor)
        Simply the EntryAction based code to provide the entry processor. If we code it directly this might be a little bit more efficient, but it gives quite a code bloat which has lots of corner cases for loader and exception handling.
        Specified by:
        invoke in interface org.cache2k.Cache<K,​V>
      • checkIntegrity

        public final void checkIntegrity()
        Check internal data structures and throw and exception if something is wrong, used for unit testing
        Specified by:
        checkIntegrity in interface InternalCache<K,​V>
      • getInfo

        public final InternalCacheInfo getInfo()
        Description copied from interface: InternalCache
        Return cache statistic counters. This method is intended for regular statistics polling. No extensive locking is performed to extract a consistent set of counters.
        Specified by:
        getInfo in interface InternalCache<K,​V>
      • getConsistentInfo

        public final InternalCacheInfo getConsistentInfo()
        Description copied from interface: InternalCache
        Generate fresh statistics within a global cache lock. This version is used by internal consistency tests. This method is not intended to be called at high frequencies or for attaching monitoring or logging. Use the InternalCache.getInfo() method for requesting information for monitoring.
        Specified by:
        getConsistentInfo in interface InternalCache<K,​V>
      • executeWithGlobalLock

        public <T> T executeWithGlobalLock​(Supplier<T> job)
        Execute job while making sure that no other operations are going on. In case the eviction is connected via a queue we need to stop the queue processing. On the other hand we needs to make sure that the queue is drained because this method is used to access the recent statistics or check integrity. Draining the queue is a two phase job: The draining may not do eviction since we hold the locks, after lifting the lock with do eviction and lock again. This ensures that all queued entries are processed up to the point when the method was called.
      • getClock

        public final org.cache2k.operation.TimeReference getClock()
        Description copied from interface: InternalCache
        Time reference for the cache.
        Specified by:
        getClock in interface InternalCache<K,​V>
      • modifiedHash

        public static int modifiedHash​(int h)
        This function calculates a modified hash code. The intention is to "rehash" the incoming integer hash codes to overcome weak hash code implementations. Identical to latest Java VMs.

        The mapping needs to be unique, so we can skip equals() check for integer key optimizations.

        See Also:
        HashMap.hash(java.lang.Object), ConcurrentHashMap.spread(int)
      • extractIntKeyValue

        public int extractIntKeyValue​(K key,
                                      int hc)
        Modified hash code or integer value for integer keyed caches
      • extractIntKeyObj

        public K extractIntKeyObj​(K key)
        The key object or null, for integer keyed caches
      • extractModifiedHash

        public int extractModifiedHash​(Entry e)
      • extractKeyObj

        public K extractKeyObj​(Entry<K,​V> e)
      • createHashTable

        public Hash2<K,​V> createHashTable()