package org.terracotta.offheapstore.concurrent;
import org.terracotta.offheapstore.Metadata;
import org.terracotta.offheapstore.Segment;
import org.terracotta.offheapstore.exceptions.OversizeMappingException;
import org.terracotta.offheapstore.pinning.PinnableCache;
import org.terracotta.offheapstore.pinning.PinnableSegment;
import org.terracotta.offheapstore.util.Factory;
import java.util.Arrays;
import java.util.Comparator;
public abstract class AbstractConcurrentOffHeapCache<K, V> extends AbstractConcurrentOffHeapMap<K, V> implements PinnableCache<K, V> {
private static final Comparator<Segment<?, ?>> SIZE_COMPARATOR = (o1, o2) -> (int) (o2.getSize() - o1.getSize());
public AbstractConcurrentOffHeapCache(Factory<? extends PinnableSegment<K, V>> segmentFactory) {
super(segmentFactory);
}
public AbstractConcurrentOffHeapCache(Factory<? extends Segment<K, V>> segmentFactory, int concurrency) {
super(segmentFactory, concurrency);
}
@Override
public V fill(K key, V value) {
try {
return super.fill(key, value);
} catch (OversizeMappingException e) {
return null;
}
}
@Override
public V getAndPin(final K key) {
return segmentFor(key).getValueAndSetMetadata(key, Metadata.PINNED, Metadata.PINNED);
}
@Override
public V putPinned(final K key, final V value) {
try {
return segmentFor(key).putPinned(key, value);
} catch (OversizeMappingException e) {
if (handleOversizeMappingException(key.hashCode())) {
try {
return segmentFor(key).putPinned(key, value);
} catch (OversizeMappingException ex) {
}
}
writeLockAll();
try {
do {
try {
return segmentFor(key).putPinned(key, value);
} catch (OversizeMappingException ex) {
e = ex;
}
} while (handleOversizeMappingException(key.hashCode()));
throw e;
} finally {
writeUnlockAll();
}
}
}
@Override
public boolean isPinned(Object key) {
return segmentFor(key).isPinned(key);
}
@Override
public void setPinning(K key, boolean pinned) {
segmentFor(key).setPinning(key, pinned);
}
@Override
protected PinnableSegment<K, V> segmentFor(Object key) {
return (PinnableSegment<K, V>) super.segmentFor(key);
}
public boolean shrink() {
Segment<?, ?>[] sorted = segments.clone();
Arrays.sort(sorted, SIZE_COMPARATOR);
for (Segment<?, ?> s : sorted) {
if (s.shrink()) {
return true;
}
}
return false;
}
public boolean shrinkOthers(final int excludedHash) {
boolean evicted = false;
Segment<?, ?> target = segmentFor(excludedHash);
for (Segment<?, ?> s : segments) {
if (s == target) {
continue;
}
evicted |= s.shrink();
}
return evicted;
}
}