com.fasterxml.cachemate.pojo.POJOCacheElement Maven / Gradle / Ivy
Show all versions of cachemate Show documentation
package com.fasterxml.cachemate.pojo;
import com.fasterxml.cachemate.KeyConverter;
import com.fasterxml.cachemate.PlatformConstants;
import com.fasterxml.cachemate.CacheElement;
/**
* Special data structure used as an element of a cache (or in simplest cases,
* as simple single-level in-memory object cachje). Evictions are based both on
* staleness/insertion-time limit and capacity limitations (with LRU eviction).
* Keys and values are POJOs (as opposed to being serialized byte sequences);
* and only single _key is used.
*
* Note on implementation: hash area is allocated on construction based on specified
* maximum number of entries (allocate chunk with size that is next biggest power of two),
* and remains static in size unless explicit resizing is requested.
* Because of this, it makes sense to use sensible maximum entry count, as well as
* maximum weight (rough memory usage estimation)
*
* @author Tatu Saloranta
*
* @param Type of keys cache element contains
* @param Type of values cache element containts
*/
public class POJOCacheElement
extends POJOCacheElementBase>
implements CacheElement
{
/**
* This base class has this many fields; count is
* used for estimating rough in-memory size
* for the cache as total.
*/
protected final static int IMPL_FIELD_COUNT = BASE_FIELD_COUNT + 1;
private final static int BASE_MEM_USAGE = PlatformConstants.BASE_OBJECT_MEMORY_USAGE
+ (IMPL_FIELD_COUNT * PlatformConstants.BASE_FIELD_MEMORY_USAGE);
// // // Actual entries
/**
* Maximum weight (approximate size) of all entries cache can contain.
* Set to maximum weight allowed minus overhead of the cache structure
* itself.
*/
protected long _maxContentsWeight;
/*
/**********************************************************************
/* Construction
/**********************************************************************
*/
/**
* @param timeToLiveSecs Amount of time entries will remain fresh (non-stale) in
* cache; in seconds.
*/
@SuppressWarnings("unchecked")
public POJOCacheElement(KeyConverter keyConverter,
int maxEntries, long maxWeight,
long timeToLiveSecs)
{
super(keyConverter, maxEntries, timeToLiveSecs,
(POJOCacheEntry[]) new POJOCacheEntry,?>[calcHashAreaSize(maxEntries)]);
_resetOldestAndNewest(); // to set oldest/newest (head/tail) linked
// take into account base mem usage of the cache (crude, but...), including hash area
_maxContentsWeight = maxWeight - BASE_MEM_USAGE - (_entries.length * PlatformConstants.BASE_FIELD_MEMORY_USAGE);
}
/*
/**********************************************************************
/* Public methods, other
/**********************************************************************
*/
@Override
public final long weight() {
return BASE_MEM_USAGE + _currentContentsWeight
+ (_entries.length * PlatformConstants.BASE_FIELD_MEMORY_USAGE);
}
@Override
public long maxContentsWeight() {
return _maxContentsWeight;
}
/*
/**********************************************************************
/* Overridden/implemented base class methods
/**********************************************************************
*/
@Override
protected POJOCacheEntry _createDummyEntry() {
return new POJOCacheEntry();
}
@Override
protected POJOCacheEntry _createEntry(K key, int keyHash, V value, int timestamp, int weight,
POJOCacheEntry nextCollision) {
return new POJOCacheEntry(key, keyHash, value, timestamp, weight, nextCollision);
}
@Override
protected void _removeEntry(POJOCacheEntry entry)
{
// Ok, need to locate entry in hash...
int index = _primaryHashIndex(entry._keyHash);
POJOCacheEntry curr = _entries[index];
POJOCacheEntry prev = null;
while (curr != null) {
if (curr == entry) {
_removeEntry(entry, index, prev);
return;
}
prev = curr;
curr = curr._primaryCollision;
}
// should never occur, so:
throw new IllegalStateException("Internal data error: could not find entry (index "+index+"/"+_entries.length+"), _key "+entry.getKey());
}
protected final POJOCacheEntry _removeByPrimary(long currentTime, K key, int keyHash)
{
int index = (keyHash & (_entries.length - 1));
// First, locate the entry
POJOCacheEntry prev = null;
POJOCacheEntry entry = _entries[index];
if (entry != null) {
while (entry != null) {
if ((entry._keyHash == keyHash) && _keyConverter.keysEqual(key, entry.getKey())) {
_removeEntry(entry, index, prev);
return entry;
}
prev = entry;
entry = entry._primaryCollision;
}
}
return null;
}
}