CacheEntry class

Пакет: com.hypixel.hytale.server.worldgen.util.cache

Файл: com/hypixel/hytale/server/worldgen/util/cache/ConcurrentSizedTimeoutCache.java

Поля (5)

МодификаторыТипИмя
private static final VarHandle TIMESTAMP
TIMESTAMP
public K key
public long timestamp
public V value

Методы (2)

МодификаторыВозвратСигнатура
abstract throw new ExceptionInInitializerErrorthrow new ExceptionInInitializerError(var1)
protected V markAndGetprotected V markAndGet(long 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);
         }
      }
   }
}