package org.infinispan.container.entries;
import org.infinispan.commons.util.AbstractEntrySizeCalculatorHelper;
import org.infinispan.commons.util.EntrySizeCalculator;
import org.infinispan.container.entries.metadata.MetadataImmortalCacheEntry;
import org.infinispan.container.entries.metadata.MetadataMortalCacheEntry;
import org.infinispan.container.entries.metadata.MetadataTransientCacheEntry;
import org.infinispan.container.entries.metadata.MetadataTransientMortalCacheEntry;
import org.infinispan.metadata.EmbeddedMetadata;
import org.infinispan.metadata.Metadata;
/**
* Implementation of a size calculator that calcultes only the size of the value assuming it is an InternalCacheEntry.
* This delegates the calculation of the key and the value contained within the InternalCacheEntry to the provided
* SizeCalculator.
* @param <K> The type of the key
* @param <V> The type of the value
* @author William Burns
* @since 8.0
*/
public class CacheEntrySizeCalculator<K, V> extends AbstractEntrySizeCalculatorHelper<K, InternalCacheEntry<K, V>> {
public CacheEntrySizeCalculator(EntrySizeCalculator<? super K, ? super V> calculator) {
this.calculator = calculator;
}
private final EntrySizeCalculator<? super K, ? super V> calculator;
@Override
public long calculateSize(K key, InternalCacheEntry<K, V> ice) {
long objSize = calculator.calculateSize(key, ice.getValue());
long iceSize = 0;
long metadataSize = 0;
// ICE itself is an object and has a reference to it's class
iceSize += OBJECT_SIZE + POINTER_SIZE;
// Each ICE references key and value
iceSize += 2 * POINTER_SIZE;
boolean mortalEntry;
boolean transientEntry;
boolean metadataAware;
// We want to put immortal entries first as they are very common. Also MetadataImmortalCacheEntry extends
// ImmortalCacheEntry so it has to come before
if (ice instanceof MetadataImmortalCacheEntry) {
mortalEntry = false;
transientEntry = false;
metadataAware = true;
} else if (ice instanceof ImmortalCacheEntry) {
mortalEntry = false;
transientEntry = false;
metadataAware = false;
} else if (ice instanceof MortalCacheEntry) {
mortalEntry = true;
transientEntry = false;
metadataAware = false;
} else if (ice instanceof TransientCacheEntry) {
mortalEntry = false;
transientEntry = true;
metadataAware = false;
} else if (ice instanceof TransientMortalCacheEntry) {
mortalEntry = true;
transientEntry = true;
metadataAware = false;
} else if (ice instanceof MetadataMortalCacheEntry) {
mortalEntry = true;
transientEntry = false;
metadataAware = true;
} else if (ice instanceof MetadataTransientCacheEntry) {
mortalEntry = false;
transientEntry = true;
metadataAware = true;
} else if (ice instanceof MetadataTransientMortalCacheEntry) {
mortalEntry = true;
transientEntry = true;
metadataAware = true;
} else {
mortalEntry = false;
transientEntry = false;
metadataAware = false;
}
if (metadataAware) {
// Assume it has a pointer for the metadata
iceSize += POINTER_SIZE;
// The metadata has itself and the class reference
metadataSize += OBJECT_SIZE + POINTER_SIZE;
Metadata metadata = ice.getMetadata();
if (metadata instanceof EmbeddedMetadata) {
// The embedded metadata has a reference and NumericVersion instance
metadataSize += POINTER_SIZE;
metadataSize = roundUpToNearest8(metadataSize);
// This is for the NumericVersion and the long inside of it
metadataSize += OBJECT_SIZE + POINTER_SIZE + 8;
metadataSize = roundUpToNearest8(metadataSize);
} else {
metadataSize = roundUpToNearest8(metadataSize);
}
}
// Mortal uses 2 longs to keep track of created and lifespan
iceSize += mortalEntry ? 16 : 0;
// Transient uses 2 longs to keep track of last access and max idle
iceSize += transientEntry ? 16 : 0;
return objSize + roundUpToNearest8(iceSize) + metadataSize;
}
}