Entry class

Пакет: com.hypixel.hytale.builtin.hytalegenerator.cache

Файл: com/hypixel/hytale/builtin/hytalegenerator/cache/ConcurrentSingleFlightCache.java

Поля (5)

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

Методы (3)

МодификаторыВозвратСигнатура
abstract throw new ExceptionInInitializerErrorthrow new ExceptionInInitializerError(var1)
protected void markprotected void mark(long var1)
protected long recencyprotected long recency()

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.builtin.hytalegenerator.cache;

class="kw">import com.hypixel.hytale.math.util.MathUtil;
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 java.lang.invoke.MethodHandles;
class="kw">import java.lang.invoke.VarHandle;
class="kw">import java.util.Objects;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.CompletionException;
class="kw">import java.util.concurrent.locks.StampedLock;
class="kw">import java.util.function.BiConsumer;
class="kw">import java.util.function.BiFunction;
class="kw">import java.util.function.Function;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class ConcurrentSingleFlightCache<K, C, 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 ConcurrentSingleFlightCache.Bucket<K, C, V>[] buckets;
   @Nonnull
   class="kw">private class="kw">final Function<K, K> copyKey;
   @Nonnull
   class="kw">private class="kw">final BiFunction<K, C, V> computeValue;
   @Nonnull
   class="kw">private class="kw">final BiConsumer<K, V> destroyer;

   class="kw">public ConcurrentSingleFlightCache(int var1, int var2, @Nonnull Function<K, K> var3, @Nonnull BiFunction<K, C, V> var4, @Nullable BiConsumer<K, V> var5) {
      int var6 = HashCommon.nextPowerOfTwo(var2);
      int var7 = Math.max(16, HashCommon.nextPowerOfTwo(var1 / var6));
      this.bucketMask = var6 - 1;
      this.buckets = new ConcurrentSingleFlightCache.Bucket[var6];

      for (int var8 = 0; var8 < var6; var8++) {
         this.buckets[var8] = new ConcurrentSingleFlightCache.Bucket<>(var7);
      }

      this.copyKey = var3;
      this.computeValue = var4;
      this.destroyer = var5 != null ? var5 : ConcurrentSingleFlightCache::noopDestroy;
   }

   @Nullable
   class="kw">public V get(@Nonnull K var1, @Nonnull C var2) {
      int var3 = HashCommon.mix(var1.hashCode());
      class="kw">return this.buckets[var3 & this.bucketMask].get(var1, var2, this.copyKey, this.computeValue, this.destroyer);
   }

   class="kw">public void clear() {
      for (ConcurrentSingleFlightCache.Bucket var4 : this.buckets) {
         var4.clear(this.destroyer);
      }
   }

   @Nullable
   class="kw">private class="kw">static <V> V await(@Nonnull CompletableFuture<V> var0) {
      try {
         class="kw">return var0.join();
      } catch (CompletionException var4) {
         Throwable var2 = var4.getCause();
         if (var2 class="kw">instanceof RuntimeException var5) {
            throw var5;
         } else if (var2 class="kw">instanceof Error var3) {
            throw var3;
         } else {
            throw var4;
         }
      }
   }

   class="kw">private class="kw">static <K, V> void noopDestroy(K var0, V var1) {
   }

   class="kw">private class="kw">static class Bucket<K, C, V> {
      class="kw">private class="kw">final int trimThreshold;
      class="kw">private class="kw">final Object2ObjectOpenHashMap<K, ConcurrentSingleFlightCache.Entry<K, V>> map;
      class="kw">private class="kw">final StampedLock lock = new StampedLock();

      class="kw">public Bucket(int var1) {
         this.trimThreshold = MathUtil.fastFloor(var1 * 0.75F);
         this.map = new Object2ObjectOpenHashMap(var1, 0.75F);
      }

      @Nullable
      class="kw">public V get(@Nonnull K var1, @Nonnull C var2, @Nonnull Function<K, K> var3, @Nonnull BiFunction<K, C, V> var4, @Nonnull BiConsumer<K, V> var5) {
         long var6 = System.nanoTime();
         boolean var9 = false;
         Object var10 = null;
         long var11 = this.lock.readLock();

         ConcurrentSingleFlightCache.Entry var8;
         try {
            var8 = (ConcurrentSingleFlightCache.Entry<K, V>)this.map.get(var1);
            if (var8 != null) {
               var8.mark(var6);
            }
         } class="kw">finally {
            this.lock.unlockRead(var11);
         }

         if (var8 == null) {
            long var13 = this.lock.writeLock();

            try {
               var8 = (ConcurrentSingleFlightCache.Entry<K, V>)this.map.get(var1);
               if (var8 == null) {
                  var10 = var3.apply(var1);
                  var8 = new ConcurrentSingleFlightCache.Entry<>(var10, var6);
                  this.map.put(var10, var8);
                  var9 = true;
                  this.trim(var5);
               } else {
                  var8.mark(var6);
               }
            } class="kw">finally {
               this.lock.unlockWrite(var13);
            }
         }

         if (var9) {
            try {
               var8.future.complete(var4.apply(var1, var2));
            } catch (Throwable var22) {
               this.remove(var10, var8);
               var8.future.completeExceptionally(var22);
            }
         }

         class="kw">return ConcurrentSingleFlightCache.await(var8.future);
      }

      class="kw">private void trim(@Nonnull BiConsumer<K, V> var1) {
         while (this.map.size() > this.trimThreshold) {
            ConcurrentSingleFlightCache.Entry var2 = null;
            long var3 = Long.MAX_VALUE;
            ObjectIterator var5 = this.map.object2ObjectEntrySet().fastIterator();

            while (var5.hasNext()) {
               ConcurrentSingleFlightCache.Entry var6 = (ConcurrentSingleFlightCache.Entry<K, V>)((it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry)var5.next())
                  .getValue();
               if (var6.future.isDone()) {
                  long var7 = var6.recency();
                  if (var7 < var3) {
                     var3 = var7;
                     var2 = var6;
                  }
               }
            }

            if (var2 == null) {
               class="kw">return;
            }

            this.map.remove(var2.key);
            destroy(var2, var1);
         }
      }

      class="kw">private void remove(@Nonnull K var1, @Nonnull ConcurrentSingleFlightCache.Entry<K, V> var2) {
         long var3 = this.lock.writeLock();

         try {
            if (this.map.get(var1) == var2) {
               this.map.remove(var1);
            }
         } class="kw">finally {
            this.lock.unlockWrite(var3);
         }
      }

      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()) {
               ConcurrentSingleFlightCache.Entry var5 = (ConcurrentSingleFlightCache.Entry<K, V>)((it.unimi.dsi.fastutil.objects.Object2ObjectMap.Entry)var4.next())
                  .getValue();
               destroy(var5, var1);
               var4.remove();
            }
         } class="kw">finally {
            this.lock.unlockWrite(var2);
         }
      }

      class="kw">private class="kw">static <K, V> void destroy(@Nonnull ConcurrentSingleFlightCache.Entry<K, V> var0, @Nonnull BiConsumer<K, V> var1) {
         if (var0.future.isDone() && !var0.future.isCompletedExceptionally()) {
            var1.accept(var0.key, var0.future.join());
         }
      }
   }

   class="kw">private class="kw">static class Entry<K, V> {
      class="kw">private class="kw">static class="kw">final VarHandle TIMESTAMP;
      @Nonnull
      class="kw">private class="kw">final K key;
      @Nonnull
      class="kw">private class="kw">final CompletableFuture<V> future = new CompletableFuture<>();
      class="kw">private long timestamp;

      class="kw">public Entry(@Nonnull K var1, long var2) {
         this.key = Objects.requireNonNull(var1);
         this.timestamp = var2;
      }

      class="kw">protected void mark(long var1) {
         TIMESTAMP.setVolatile((ConcurrentSingleFlightCache.Entry)this, (long)var1);
      }

      class="kw">protected long recency() {
         class="kw">return (long)TIMESTAMP.getVolatile((ConcurrentSingleFlightCache.Entry)this);
      }

      class="kw">static {
         try {
            TIMESTAMP = MethodHandles.lookup().findVarHandle(ConcurrentSingleFlightCache.Entry.class, "timestamp", long.class);
         } catch (ReflectiveOperationException var1) {
            throw new ExceptionInInitializerError(var1);
         }
      }
   }
}