CacheEntryMetricData class

Пакет: com.hypixel.hytale.server.core.universe.world.storage.provider

Файл: com/hypixel/hytale/server/core/universe/world/storage/provider/IndexedStorageChunkStorageProvider.java

Поля (3)

МодификаторыТипИмя
private static final Codec<IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData> CODEC
private long key
private IndexedStorageFile value

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.universe.world.storage.provider;

class="kw">import com.hypixel.fastutil.longs.Long2ObjectConcurrentHashMap;
class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.codec.KeyedCodec;
class="kw">import com.hypixel.hytale.codec.builder.BuilderCodec;
class="kw">import com.hypixel.hytale.codec.codecs.array.ArrayCodec;
class="kw">import com.hypixel.hytale.component.Resource;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.metrics.MetricProvider;
class="kw">import com.hypixel.hytale.metrics.MetricResults;
class="kw">import com.hypixel.hytale.metrics.MetricsRegistry;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.BufferChunkLoader;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.BufferChunkSaver;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.IChunkLoader;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.IChunkSaver;
class="kw">import com.hypixel.hytale.server.core.util.io.FileUtil;
class="kw">import com.hypixel.hytale.sneakythrow.SneakyThrow;
class="kw">import com.hypixel.hytale.storage.IndexedStorageFile;
class="kw">import it.unimi.dsi.fastutil.ints.IntList;
class="kw">import it.unimi.dsi.fastutil.ints.IntListIterator;
class="kw">import it.unimi.dsi.fastutil.longs.LongArrayList;
class="kw">import it.unimi.dsi.fastutil.longs.LongIterator;
class="kw">import it.unimi.dsi.fastutil.longs.LongList;
class="kw">import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
class="kw">import it.unimi.dsi.fastutil.longs.LongSet;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
class="kw">import java.io.Closeable;
class="kw">import java.io.FileNotFoundException;
class="kw">import java.io.IOException;
class="kw">import java.nio.ByteBuffer;
class="kw">import java.nio.file.FileAlreadyExistsException;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.nio.file.StandardOpenOption;
class="kw">import java.util.Iterator;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.stream.Stream;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">import org.checkerframework.checker.nullness.compatqual.NonNullDecl;

class="kw">public class IndexedStorageChunkStorageProvider class="kw">implements IChunkStorageProvider<IndexedStorageChunkStorageProvider.IndexedStorageCache> {
   class="kw">public class="kw">static class="kw">final String ID = "IndexedStorage";
   @Nonnull
   class="kw">public class="kw">static class="kw">final BuilderCodec<IndexedStorageChunkStorageProvider> CODEC = BuilderCodec.builder(
         IndexedStorageChunkStorageProvider.class, IndexedStorageChunkStorageProvider::new
      )
      .documentation("Uses the indexed storage file format to store chunks.")
      .<Boolean>appendInherited(
         new KeyedCodec<>("FlushOnWrite", Codec.BOOLEAN),
         (var0, var1) -> var0.flushOnWrite = var1,
         var0 -> var0.flushOnWrite,
         (var0, var1) -> var0.flushOnWrite = var1.flushOnWrite
      )
      .documentation(
         "Controls whether the indexed storage flushes during writes.\nRecommended to be enabled to prevent corruption of chunks during unclean shutdowns."
      )
      .add()
      .build();
   class="kw">private boolean flushOnWrite = false;

   class="kw">public IndexedStorageChunkStorageProvider() {
   }

   class="kw">public IndexedStorageChunkStorageProvider.IndexedStorageCache initialize(@NonNullDecl Store<ChunkStore> var1) class="kw">throws IOException {
      World var2 = var1.getExternalData().getWorld();
      IndexedStorageChunkStorageProvider.IndexedStorageCache var3 = new IndexedStorageChunkStorageProvider.IndexedStorageCache();
      var3.path = var2.getSavePath().resolve("chunks");
      class="kw">return var3;
   }

   class="kw">public void delete(@Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache var1, @Nonnull Store<ChunkStore> var2) class="kw">throws IOException {
      var1.close();
      FileUtil.deleteDirectory(var1.path);
   }

   class="kw">public void close(@NonNullDecl IndexedStorageChunkStorageProvider.IndexedStorageCache var1, @NonNullDecl Store<ChunkStore> var2) class="kw">throws IOException {
      var1.close();
   }

   @Nonnull
   class="kw">public IChunkLoader getLoader(@Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache var1, @Nonnull Store<ChunkStore> var2) {
      class="kw">return new IndexedStorageChunkStorageProvider.IndexedStorageChunkLoader(var2, var1, this.flushOnWrite, false);
   }

   @Nonnull
   class="kw">public IChunkSaver getSaver(@Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache var1, @Nonnull Store<ChunkStore> var2) {
      class="kw">return new IndexedStorageChunkStorageProvider.IndexedStorageChunkSaver(var2, var1, this.flushOnWrite);
   }

   @Override
   class="kw">public void beginRecovery(Path var1, Path var2) class="kw">throws IOException {
      FileUtil.atomicMove(var1.resolve("chunks"), var2.resolve("chunks"));
   }

   @Override
   class="kw">public void revertRecovery(Path var1, Path var2) class="kw">throws IOException {
      Path var3 = var1.resolve("chunks");
      if (Files.exists(var3)) {
         FileUtil.deleteDirectory(var3);
      }

      FileUtil.atomicMove(var2.resolve("chunks"), var3);
   }

   @Nullable
   @Override
   class="kw">public IChunkLoader getRecoveryLoader(@Nonnull Store<ChunkStore> var1, Path var2) {
      IndexedStorageChunkStorageProvider.IndexedStorageCache var3 = new IndexedStorageChunkStorageProvider.IndexedStorageCache();
      var3.path = var2.resolve("chunks");
      class="kw">return new IndexedStorageChunkStorageProvider.IndexedStorageChunkLoader(var1, var3, false, true);
   }

   @Nonnull
   @Override
   class="kw">public String toString() {
      class="kw">return "IndexedStorageChunkStorageProvider{}";
   }

   @Nonnull
   class="kw">private class="kw">static String toFileName(int var0, int var1) {
      class="kw">return var0 + "." + var1 + ".region.bin";
   }

   class="kw">private class="kw">static long fromFileName(@Nonnull String var0) {
      String[] var1 = var0.split("\\.", -1);
      if (var1.length != 4) {
         throw new IllegalArgumentException("Unexpected file name format!");
      }

      if (!"region".equals(var1[2])) {
         throw new IllegalArgumentException("Unexpected file name format!");
      }

      if (!"bin".equals(var1[3])) {
         throw new IllegalArgumentException("Unexpected file extension!");
      }

      int var2 = Integer.parseInt(var1[0]);
      int var3 = Integer.parseInt(var1[1]);
      class="kw">return ChunkUtil.indexChunk(var2, var3);
   }

   class="kw">public class="kw">static class IndexedStorageCache class="kw">implements Closeable, MetricProvider, Resource<ChunkStore> {
      @Nonnull
      class="kw">public class="kw">static class="kw">final MetricsRegistry<IndexedStorageChunkStorageProvider.IndexedStorageCache> METRICS_REGISTRY = new MetricsRegistry<IndexedStorageChunkStorageProvider.IndexedStorageCache>()
         .register(
            "Files",
            var0 -> var0.cache
               .long2ObjectEntrySet()
               .stream()
               .map(IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData::new)
               .toArray(IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData[]::new),
            new ArrayCodec<>(
               IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData.CODEC,
               IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData[]::new
            )
         );
      class="kw">private class="kw">final Long2ObjectConcurrentHashMap<IndexedStorageFile> cache = new Long2ObjectConcurrentHashMap<>(true, ChunkUtil.NOT_FOUND);
      class="kw">private Path path;

      class="kw">public IndexedStorageCache() {
      }

      @Nonnull
      class="kw">public Long2ObjectConcurrentHashMap<IndexedStorageFile> getCache() {
         class="kw">return this.cache;
      }

      @Override
      class="kw">public void close() class="kw">throws IOException {
         IOException var1 = null;
         Iterator var2 = this.cache.values().iterator();

         while (var2.hasNext()) {
            try {
               var2.next().close();
               var2.remove();
            } catch (Exception var4) {
               if (var1 == null) {
                  var1 = new IOException("Failed to close one or more loaders!");
               }

               var1.addSuppressed(var4);
            }
         }

         if (var1 != null) {
            throw var1;
         }
      }

      @Nullable
      class="kw">public IndexedStorageFile getOrTryOpen(int var1, int var2, boolean var3) {
         class="kw">return this.cache.computeIfAbsent(ChunkUtil.indexChunk(var1, var2), var4 -> {
            Path var6 = this.path.resolve(IndexedStorageChunkStorageProvider.toFileName(var1, var2));
            if (!Files.exists(var6)) {
               class="kw">return null;
            }

            try {
               IndexedStorageFile var7 = IndexedStorageFile.open(var6, StandardOpenOption.READ, StandardOpenOption.WRITE);
               var7.setFlushOnWrite(var3);
               class="kw">return var7;
            } catch (FileNotFoundException var8) {
               class="kw">return null;
            } catch (IOException var9) {
               throw SneakyThrow.sneakyThrow(var9);
            }
         });
      }

      @Nonnull
      class="kw">public IndexedStorageFile getOrCreate(int var1, int var2, boolean var3) {
         class="kw">return this.cache.computeIfAbsent(ChunkUtil.indexChunk(var1, var2), var4 -> {
            try {
               if (!Files.exists(this.path)) {
                  try {
                     Files.createDirectory(this.path);
                  } catch (FileAlreadyExistsException var8) {
                  }
               }

               Path var6 = this.path.resolve(IndexedStorageChunkStorageProvider.toFileName(var1, var2));
               IndexedStorageFile var7 = IndexedStorageFile.open(var6, StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE);
               var7.setFlushOnWrite(var3);
               class="kw">return var7;
            } catch (IOException var9) {
               throw SneakyThrow.sneakyThrow(var9);
            }
         });
      }

      @Nonnull
      class="kw">public LongList getIndexes() class="kw">throws IOException {
         if (!Files.exists(this.path)) {
            class="kw">return LongList.of();
         }

         LongArrayList var1 = new LongArrayList();

         try (Stream var2 = Files.list(this.path)) {
            var2.forEach(SneakyThrow.sneakyConsumer(var2x -> {
               if (!Files.isDirectory(var2x)) {
                  long var3;
                  try {
                     var3 = IndexedStorageChunkStorageProvider.fromFileName(var2x.getFileName().toString());
                  } catch (IllegalArgumentException var15) {
                     class="kw">return;
                  }

                  int var5 = ChunkUtil.xOfChunkIndex(var3);
                  int var6 = ChunkUtil.zOfChunkIndex(var3);
                  IndexedStorageFile var7 = this.getOrTryOpen(var5, var6, false);
                  if (var7 != null) {
                     IntList var8 = var7.keys();
                     IntListIterator var9 = var8.iterator();

                     while (var9.hasNext()) {
                        int var10 = var9.nextInt();
                        int var11 = ChunkUtil.xFromColumn(var10);
                        int var12 = ChunkUtil.zFromColumn(var10);
                        int var13 = var5 << 5 | var11;
                        int var14 = var6 << 5 | var12;
                        var1.add(ChunkUtil.indexChunk(var13, var14));
                     }
                  }
               }
            }));
         }

         class="kw">return var1;
      }

      class="kw">public void flush() class="kw">throws IOException {
         IOException var1 = null;

         for (IndexedStorageFile var3 : this.cache.values()) {
            try {
               var3.force(false);
            } catch (Exception var5) {
               if (var1 == null) {
                  var1 = new IOException("Failed to close one or more loaders!");
               }

               var1.addSuppressed(var5);
            }
         }

         if (var1 != null) {
            throw var1;
         }
      }

      @Nonnull
      @Override
      class="kw">public MetricResults toMetricResults() {
         class="kw">return METRICS_REGISTRY.toMetricResults(this);
      }

      @Nonnull
      @Override
      class="kw">public Resource<ChunkStore> clone() {
         class="kw">return new IndexedStorageChunkStorageProvider.IndexedStorageCache();
      }

      class="kw">private class="kw">static class CacheEntryMetricData {
         @Nonnull
         class="kw">private class="kw">static class="kw">final Codec<IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData> CODEC = BuilderCodec.builder(
               IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData.class,
               IndexedStorageChunkStorageProvider.IndexedStorageCache.CacheEntryMetricData::new
            )
            .append(new KeyedCodec<>("Key", Codec.LONG), (var0, var1) -> var0.key = var1, var0 -> var0.key)
            .add()
            .append(new KeyedCodec<>("File", IndexedStorageFile.METRICS_REGISTRY), (var0, var1) -> var0.value = var1, var0 -> var0.value)
            .add()
            .build();
         class="kw">private long key;
         class="kw">private IndexedStorageFile value;

         class="kw">public CacheEntryMetricData() {
         }

         class="kw">public CacheEntryMetricData(@Nonnull Entry<IndexedStorageFile> var1) {
            this.key = var1.getLongKey();
            this.value = (IndexedStorageFile)var1.getValue();
         }
      }
   }

   class="kw">public class="kw">static class IndexedStorageChunkLoader class="kw">extends BufferChunkLoader class="kw">implements MetricProvider {
      @Nonnull
      class="kw">private class="kw">final IndexedStorageChunkStorageProvider.IndexedStorageCache cache;
      class="kw">private class="kw">final boolean flushOnWrite;
      class="kw">private class="kw">final boolean ownsCache;

      class="kw">public IndexedStorageChunkLoader(
         @Nonnull Store<ChunkStore> var1, @Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache var2, boolean var3, boolean var4
      ) {
         super(var1);
         this.cache = var2;
         this.flushOnWrite = var3;
         this.ownsCache = var4;
      }

      @Override
      class="kw">public void close() class="kw">throws IOException {
         if (this.ownsCache) {
            this.cache.close();
         }
      }

      @Nonnull
      @Override
      class="kw">public CompletableFuture<ByteBuffer> loadBuffer(int var1, int var2) {
         int var3 = var1 >> 5;
         int var4 = var2 >> 5;
         int var5 = var1 & 31;
         int var6 = var2 & 31;
         int var7 = ChunkUtil.indexColumn(var5, var6);
         class="kw">return CompletableFuture.supplyAsync(SneakyThrow.sneakySupplier(() -> {
            IndexedStorageFile var4 = this.cache.getOrTryOpen(var3, var4, this.flushOnWrite);
            class="kw">return var4 == null ? null : var4.readBlob(var7);
         }));
      }

      @Nonnull
      @Override
      class="kw">public LongList getIndexes() class="kw">throws IOException {
         class="kw">return this.cache.getIndexes();
      }

      @Nullable
      @Override
      class="kw">public MetricResults toMetricResults() {
         class="kw">return this.getStore().getExternalData().getSaver() class="kw">instanceof IndexedStorageChunkStorageProvider.IndexedStorageChunkSaver
            ? null
            : this.cache.toMetricResults();
      }
   }

   class="kw">public class="kw">static class IndexedStorageChunkSaver class="kw">extends BufferChunkSaver class="kw">implements MetricProvider {
      @Nonnull
      class="kw">private class="kw">final IndexedStorageChunkStorageProvider.IndexedStorageCache cache;
      class="kw">private class="kw">final boolean flushOnWrite;

      class="kw">protected IndexedStorageChunkSaver(@Nonnull Store<ChunkStore> var1, @Nonnull IndexedStorageChunkStorageProvider.IndexedStorageCache var2, boolean var3) {
         super(var1);
         this.cache = var2;
         this.flushOnWrite = var3;
      }

      @Override
      class="kw">public void close() class="kw">throws IOException {
      }

      @Nonnull
      @Override
      class="kw">public CompletableFuture<Void> saveBuffer(int var1, int var2, @Nonnull ByteBuffer var3) {
         int var4 = var1 >> 5;
         int var5 = var2 >> 5;
         int var6 = var1 & 31;
         int var7 = var2 & 31;
         int var8 = ChunkUtil.indexColumn(var6, var7);
         class="kw">return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> {
            IndexedStorageFile var5 = this.cache.getOrCreate(var4, var5, this.flushOnWrite);
            var5.writeBlob(var8, var3);
         }));
      }

      @Nonnull
      @Override
      class="kw">public CompletableFuture<Void> removeBuffer(int var1, int var2) {
         int var3 = var1 >> 5;
         int var4 = var2 >> 5;
         int var5 = var1 & 31;
         int var6 = var2 & 31;
         int var7 = ChunkUtil.indexColumn(var5, var6);
         class="kw">return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> {
            IndexedStorageFile var4 = this.cache.getOrTryOpen(var3, var4, this.flushOnWrite);
            if (var4 != null) {
               var4.removeBlob(var7);
            }
         }));
      }

      @Nonnull
      @Override
      class="kw">public LongList getIndexes() class="kw">throws IOException {
         class="kw">return this.cache.getIndexes();
      }

      @Override
      class="kw">public void flush() class="kw">throws IOException {
         this.cache.flush();
      }

      @Nonnull
      @Override
      class="kw">public CompletableFuture<Void> compact(@Nullable long[] var1) {
         class="kw">return CompletableFuture.runAsync(SneakyThrow.sneakyRunnable(() -> {
            LongSet var2 = new LongOpenHashSet();
            if (var1 != null) {
               for (long var6 : var1) {
                  int var8 = ChunkUtil.xOfChunkIndex(var6) >> 5;
                  int var9 = ChunkUtil.zOfChunkIndex(var6) >> 5;
                  var2.add(ChunkUtil.indexChunk(var8, var9));
               }
            } else {
               var2.addAll(this.cache.getCache().keySet());
            }

            LongIterator var10 = var2.iterator();

            while (var10.hasNext()) {
               long var11 = var10.nextLong();
               IndexedStorageFile var12 = this.cache.getCache().get(var11);
               if (var12 != null && var12.getUsedBlobCount() == 0) {
                  int var7 = ChunkUtil.xOfChunkIndex(var11);
                  int var13 = ChunkUtil.zOfChunkIndex(var11);
                  var12.close();
                  this.cache.getCache().remove(var11);
                  Files.deleteIfExists(this.cache.path.resolve(IndexedStorageChunkStorageProvider.toFileName(var7, var13)));
               }
            }
         }));
      }

      @Override
      class="kw">public MetricResults toMetricResults() {
         class="kw">return this.cache.toMetricResults();
      }
   }
}