IndexedStorageChunkLoader class

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

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

extends: BufferChunkLoader

implements: MetricProvider

Поля (9)

МодификаторыТипИмя
private final IndexedStorageChunkStorageProvider.IndexedStorageCache cache
private final boolean flushOnWrite
private final boolean ownsCache
int var3
int var4
IndexedStorageFile var4
int var5
int var6
int var7

Методы (6)

МодификаторыВозвратСигнатура
public void closepublic void close()
public LongList getIndexespublic LongList getIndexes()
if if(this.ownsCache)
public CompletableFuture<ByteBuffer> loadBufferpublic CompletableFuture<ByteBuffer> loadBuffer(int var1, int var2)
abstract super super(var1)
public MetricResults toMetricResultspublic MetricResults toMetricResults()

Исходный код

Показать/скрыть
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();
      }
   }
}