ConcurrentSizedTimeoutCache class
Пакет: com.hypixel.hytale.server.worldgen.util.cache
Файл: com/hypixel/hytale/server/worldgen/util/cache/ConcurrentSizedTimeoutCache.java
implements: Cache<K, V>
Поля (34)
| Модификаторы | Тип | Имя |
|---|---|---|
final |
int |
BUCKET_MIN_CAPACITY |
|
private static final VarHandle |
TIMESTAMP |
|
|
TIMESTAMP |
|
private final int |
capacity |
|
public K |
key |
|
private final StampedLock |
lock |
|
private final Object2ObjectOpenHashMap<K, ConcurrentSizedTimeoutCache.CacheEntry<K, V>> |
map |
|
private final ArrayDeque<ConcurrentSizedTimeoutCache.CacheEntry<K, V>> |
pool |
|
private final long |
timeout_ns |
|
public long |
timestamp |
|
private final int |
trimThreshold |
|
public V |
value |
|
Object |
var10 |
|
int |
var11 |
|
Object |
var11 |
|
|
var11 |
|
int |
var12 |
|
long |
var12 |
|
ConcurrentSizedTimeoutCache.CacheEntry |
var14 |
|
ConcurrentSizedTimeoutCache.CacheEntry |
var15 |
|
int |
var2 |
|
long |
var2 |
|
long |
var2 |
|
Object |
var23 |
|
boolean |
var4 |
|
ObjectIterator |
var4 |
|
long |
var5 |
|
long |
var5 |
|
ConcurrentSizedTimeoutCache.CacheEntry |
var5 |
|
long |
var7 |
|
ObjectIterator |
var7 |
|
ConcurrentSizedTimeoutCache.CacheEntry |
var8 |
|
long |
var9 |
|
ConcurrentSizedTimeoutCache.CacheEntry |
var9 |
Методы (17)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
|
public |
Bucketpublic Bucket(int var1, long var2) |
|
private |
CacheEntryprivate CacheEntry() |
abstract |
throw new |
ExceptionInInitializerErrorthrow new ExceptionInInitializerError(var1) |
abstract |
throw new |
IllegalStateExceptionthrow new IllegalStateException("Cache has been shutdown!") |
|
public void |
cleanuppublic void cleanup(@Nullable BiConsumer<K, V> var1) |
|
public void |
clearpublic void clear(@Nonnull BiConsumer<K, V> var1) |
|
public V |
computepublic V compute(@Nonnull K var1, @Nonnull Function<K, K> var2, @Nonnull Function<K, V> var3, @Nonnull BiConsumer<K, V> var4) |
|
|
for for(int var13 = 0; var13 < var11; var13++) |
|
|
for for(ConcurrentSizedTimeoutCache.Bucket var4 : this.buckets) |
|
|
for for(ConcurrentSizedTimeoutCache.Bucket var4 : this.buckets) |
|
|
if if(var9 != null) |
|
|
if if(var15 != null) |
|
|
if if(var10 != var11) |
|
|
if if(var8 == null) |
|
|
if if(var1 != null) |
|
protected V |
markAndGetprotected V markAndGet(long var1) |
static |
<K, V> void |
noopDestroy<K, V> void noopDestroy(K var0, V var1) |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.server.worldgen.util.cache;
class="kw">import com.hypixel.hytale.math.util.MathUtil;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.worldgen.util.LogUtil;
class="kw">import it.unimi.dsi.fastutil.HashCommon;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectIterator;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry;
class="kw">import java.lang.invoke.MethodHandles;
class="kw">import java.lang.invoke.VarHandle;
class="kw">import java.lang.ref.WeakReference;
class="kw">import java.lang.ref.Cleaner.Cleanable;
class="kw">import java.util.ArrayDeque;
class="kw">import java.util.Objects;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.concurrent.locks.StampedLock;
class="kw">import java.util.function.BiConsumer;
class="kw">import java.util.function.Function;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">public class ConcurrentSizedTimeoutCache<K, V> class="kw">implements Cache<K, V> {
class="kw">private class="kw">static class="kw">final int BUCKET_MIN_CAPACITY = 16;
class="kw">private class="kw">static class="kw">final float BUCKET_LOAD_FACTOR = 0.75F;
class="kw">private class="kw">final int bucketMask;
@Nonnull
class="kw">private class="kw">final ConcurrentSizedTimeoutCache.Bucket<K, V>[] buckets;
@Nonnull
class="kw">private class="kw">final Function<K, K> computeKey;
@Nonnull
class="kw">private class="kw">final Function<K, V> computeValue;
@Nonnull
class="kw">private class="kw">final BiConsumer<K, V> destroyer;
@Nonnull
class="kw">private class="kw">final ScheduledFuture<?> future;
@Nonnull
class="kw">private class="kw">final Cleanable cleanable;
class="kw">public ConcurrentSizedTimeoutCache(
int var1, int var2, long var3, @Nonnull TimeUnit var5, @Nonnull Function<K, K> var6, @Nonnull Function<K, V> var7, @Nullable BiConsumer<K, V> var8
) {
long var9 = var5.toNanos(var3);
int var11 = HashCommon.nextPowerOfTwo(var2);
int var12 = Math.max(16, HashCommon.nextPowerOfTwo(var1 / var11));
this.bucketMask = var11 - 1;
this.buckets = new ConcurrentSizedTimeoutCache.Bucket[var11];
for (int var13 = 0; var13 < var11; var13++) {
this.buckets[var13] = new ConcurrentSizedTimeoutCache.Bucket<>(var12, var9);
}
this.computeKey = var6;
this.computeValue = var7;
this.destroyer = var8 != null ? var8 : ConcurrentSizedTimeoutCache::noopDestroy;
this.future = HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(new CleanupRunnable(new WeakReference<>(this)), var3, var3, var5);
this.cleanable = CleanupFutureAction.CLEANER.register(this, new CleanupFutureAction(this.future));
}
@Override
class="kw">public void shutdown() {
this.cleanable.clean();
for (ConcurrentSizedTimeoutCache.Bucket var4 : this.buckets) {
var4.clear(this.destroyer);
}
}
@Override
class="kw">public void cleanup() {
for (ConcurrentSizedTimeoutCache.Bucket var4 : this.buckets) {
var4.cleanup(this.destroyer);
}
}
@Nonnull
@Override
class="kw">public V get(K var1) {
if (this.future.isCancelled()) {
throw new IllegalStateException("Cache has been shutdown!");
}
int var2 = HashCommon.mix(var1.hashCode());
class="kw">return this.buckets[var2 & this.bucketMask].compute(var1, this.computeKey, this.computeValue, this.destroyer);
}
class="kw">private class="kw">static <K, V> void noopDestroy(K var0, V var1) {
}
class="kw">private class="kw">static class Bucket<K, V> {
class="kw">private class="kw">final int capacity;
class="kw">private class="kw">final int trimThreshold;
class="kw">private class="kw">final long timeout_ns;
class="kw">private class="kw">final ArrayDeque<ConcurrentSizedTimeoutCache.CacheEntry<K, V>> pool;
class="kw">private class="kw">final Object2ObjectOpenHashMap<K, ConcurrentSizedTimeoutCache.CacheEntry<K, V>> map;
class="kw">private class="kw">final StampedLock lock = new StampedLock();
class="kw">public Bucket(int var1, long var2) {
this.capacity = var1;
this.trimThreshold = MathUtil.fastFloor(var1 * 0.75F);
this.timeout_ns = var2;
this.pool = new ArrayDeque<>(var1);
this.map = new Object2ObjectOpenHashMap(var1, 0.75F);
}
@Nonnull
class="kw">public V compute(@Nonnull K var1, @Nonnull Function<K, K> var2, @Nonnull Function<K, V> var3, @Nonnull BiConsumer<K, V> var4) {
long var5 = System.nanoTime();
long var7 = this.lock.readLock();
try {
ConcurrentSizedTimeoutCache.CacheEntry var9 = (ConcurrentSizedTimeoutCache.CacheEntry<K, V>)this.map.get(var1);
if (var9 != null) {
class="kw">return var9.markAndGet(var5);
}
} class="kw">finally {
this.lock.unlockRead(var7);
}
Object var23 = var2.apply(var1);
Object var10 = var3.apply(var1);
Object var11 = var10;
long var12 = this.lock.writeLock();
try {
ConcurrentSizedTimeoutCache.CacheEntry var14 = this.pool.isEmpty() ? new ConcurrentSizedTimeoutCache.CacheEntry<>() : this.pool.poll();
Objects.requireNonNull(var14, "CacheEntry pool returned null entry!");
var14.key = (K)var23;
var14.value = var10;
var14.timestamp = var5;
ConcurrentSizedTimeoutCache.CacheEntry var15 = (ConcurrentSizedTimeoutCache.CacheEntry<K, V>)this.map.putIfAbsent(var23, var14);
if (var15 != null) {
Objects.requireNonNull(var15.value);
var11 = var15.value;
var15.timestamp = var5;
var14.key = null;
var14.value = null;
if (this.pool.size() < this.capacity) {
this.pool.offer(var14);
}
}
} class="kw">finally {
this.lock.unlockWrite(var12);
}
if (var10 != var11) {
var4.accept((K)var23, var10);
}
class="kw">return (V)var11;
}
class="kw">public void cleanup(@Nullable BiConsumer<K, V> var1) {
long var2 = this.lock.writeLock();
try {
boolean var4 = this.map.size() >= this.trimThreshold;
long var5 = System.nanoTime() - this.timeout_ns;
ObjectIterator var7 = this.map.object2ObjectEntrySet().fastIterator();
while (var7.hasNext()) {
ConcurrentSizedTimeoutCache.CacheEntry var8 = (ConcurrentSizedTimeoutCache.CacheEntry<K, V>)((Entry)var7.next()).getValue();
if (var8 == null) {
LogUtil.getLogger().at(Level.SEVERE).log("Found null entry in cache bucket during cleanup!");
var7.remove();
} else if (var8.timestamp < var5) {
var7.remove();
if (var1 != null) {
var1.accept(var8.key, var8.value);
}
var8.key = null;
var8.value = null;
if (this.pool.size() < this.capacity) {
this.pool.offer(var8);
}
}
}
if (var4 && this.map.size() < this.capacity) {
this.map.trim(this.capacity);
}
} class="kw">finally {
this.lock.unlockWrite(var2);
}
}
class="kw">public void clear(@Nonnull BiConsumer<K, V> var1) {
long var2 = this.lock.writeLock();
try {
ObjectIterator var4 = this.map.object2ObjectEntrySet().fastIterator();
while (var4.hasNext()) {
ConcurrentSizedTimeoutCache.CacheEntry var5 = (ConcurrentSizedTimeoutCache.CacheEntry<K, V>)((Entry)var4.next()).getValue();
var1.accept(var5.key, var5.value);
var4.remove();
}
} class="kw">finally {
this.lock.unlockWrite(var2);
}
}
}
class="kw">private class="kw">static class CacheEntry<K, V> {
class="kw">private class="kw">static class="kw">final VarHandle TIMESTAMP;
@Nullable
class="kw">public K key = (K)null;
@Nullable
class="kw">public V value = (V)null;
class="kw">public long timestamp = 0L;
class="kw">private CacheEntry() {
}
@Nonnull
class="kw">protected V markAndGet(long var1) {
Objects.requireNonNull(this.value);
TIMESTAMP.setVolatile((ConcurrentSizedTimeoutCache.CacheEntry)this, (long)var1);
class="kw">return this.value;
}
class="kw">static {
try {
TIMESTAMP = MethodHandles.lookup().findVarHandle(ConcurrentSizedTimeoutCache.CacheEntry.class, "timestamp", long.class);
} catch (ReflectiveOperationException var1) {
throw new ExceptionInInitializerError(var1);
}
}
}
}