WorldCrashRecoveryHandler class

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

Файл: com/hypixel/hytale/server/core/universe/WorldCrashRecoveryHandler.java

Поля (20)

МодификаторыТипИмя
final HytaleLogger LOGGER
private int attempts
private long lastCrashNanos
private boolean loading
WorldCrashRecovery var1
World var2
HytaleServerConfig var2
WorldCrashRecoveryHandler.RecoveryState var2
String var3
String var3
WorldCrashRecoveryHandler.ResolvedPolicy var4
boolean var4
WorldCrashRecoveryHandler.RecoveryState var4
WorldCrashRecoveryHandler.RecoveryState var5
CrashRecoveryConfig var5
long var5
WorldCrashRecoveryHandler.RecoveryState var5
WorldCrashRecovery var6
var6
long var7

Методы (25)

МодификаторыВозвратСигнатура
private RecoveryStateprivate RecoveryState()
private record ResolvedPolicyrecord ResolvedPolicy(@Nonnull WorldCrashRecovery mode, int maxAttempts, int retryDelaySeconds, @Nonnull WorldCrashRecovery fallback)
private void applyFallbackvoid applyFallback(@Nonnull String var1, @Nonnull WorldCrashRecovery var2)
private void clearStatevoid clearState(@Nonnull String var1)
if if(!var5.loading)
if if(var2 == null)
if if(var5 != null)
if if(var6 == null)
if if(var1 != null)
if if(var3.pending != null)
if if(var4 != null)
if if(var5 != null)
if if(var4 != null)
if if(var2 != null)
if if(var2.pending != null)
if if(var2 == WorldCrashRecovery.Shutdown)
private static WorldCrashRecoveryHandler.ResolvedPolicy ofprivate static WorldCrashRecoveryHandler.ResolvedPolicy of(@Nonnull CrashRecoveryConfig var0, @Nonnull WorldCrashRecovery var1)
private void onReloadCompletevoid onReloadComplete(@Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var3, @Nullable Throwable var4)
void onRemoveWorldvoid onRemoveWorld(@Nonnull RemoveWorldEvent var1)
private void reloadNowvoid reloadNow(@Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var3)
private void scheduleReloadvoid scheduleReload(@Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.RecoveryState var3, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var4)
synchronized synchronized(var5)
synchronized synchronized(var4)
synchronized synchronized(var5)
synchronized synchronized(var2)

Исходный код

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

class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.server.core.Constants;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.HytaleServerConfig;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.ShutdownReason;
class="kw">import com.hypixel.hytale.server.core.config.CrashRecoveryConfig;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.WorldCrashRecovery;
class="kw">import com.hypixel.hytale.server.core.universe.world.events.RemoveWorldEvent;
class="kw">import java.time.Duration;
class="kw">import java.util.Locale;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">final class WorldCrashRecoveryHandler {
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   class="kw">static class="kw">final long CRASH_WINDOW_NANOS = Duration.ofMinutes(5L).toNanos();
   class="kw">private class="kw">final Universe universe;
   class="kw">private class="kw">final ConcurrentHashMap<String, WorldCrashRecoveryHandler.RecoveryState> states = new ConcurrentHashMap<>();

   WorldCrashRecoveryHandler(@Nonnull Universe var1) {
      this.universe = var1;
   }

   void onRemoveWorld(@Nonnull RemoveWorldEvent var1) {
      World var2 = var1.getWorld();
      String var3 = var2.getName().toLowerCase(Locale.ROOT);
      if (var1.getRemovalReason() != RemoveWorldEvent.RemovalReason.EXCEPTIONAL) {
         this.clearState(var3);
      } else {
         WorldCrashRecoveryHandler.ResolvedPolicy var4 = this.resolve(var2);
         if (var4 != null && var4.mode() != WorldCrashRecovery.None) {
            if (var4.mode() == WorldCrashRecovery.Shutdown) {
               LOGGER.at(Level.WARNING).log("World '%s' crashed, shutting down the server", var2.getName());
               HytaleServer.get()
                  .shutdownServer(
                     ShutdownReason.CRASH.withMessage(Message.translation("server.general.disconnect.worldCrashedShutdown").param("world", var2.getName()))
                  );
            } else if (var2.getWorldConfig().isDeleteOnRemove()) {
               LOGGER.at(Level.INFO).log("Skipping reload of crashed world '%s' because it is set to delete on remove", var2.getName());
               this.clearState(var3);
            } else {
               WorldCrashRecoveryHandler.RecoveryState var5 = this.states.computeIfAbsent(var3, var0 -> new WorldCrashRecoveryHandler.RecoveryState());
               class="kw">synchronized (var5) {
                  if (this.states.get(var3) == var5) {
                     if (!var5.loading) {
                        this.scheduleReload(var2.getName(), var3, var5, var4);
                     }
                  }
               }
            }
         }
      }
   }

   @Nullable
   class="kw">private WorldCrashRecoveryHandler.ResolvedPolicy resolve(@Nonnull World var1) {
      HytaleServerConfig var2 = HytaleServer.get().getConfig();
      if (var2 == null) {
         class="kw">return null;
      }

      String var3 = var2.getDefaults().getWorld();
      boolean var4 = var3 != null && var3.equalsIgnoreCase(var1.getName());
      CrashRecoveryConfig var5 = var1.getWorldConfig().getCrashRecovery();
      if (var5 != null) {
         WorldCrashRecovery var6 = var5.getMode();
         if (var6 == null) {
            var6 = var4 ? defaultWorldMode(var2) : WorldCrashRecovery.Reload;
         }

         class="kw">return WorldCrashRecoveryHandler.ResolvedPolicy.of(var5, var6);
      } else {
         class="kw">return var4 ? WorldCrashRecoveryHandler.ResolvedPolicy.of(var2.getDefaults().getCrashRecovery(), defaultWorldMode(var2)) : null;
      }
   }

   @Nonnull
   class="kw">private class="kw">static WorldCrashRecovery defaultWorldMode(@Nonnull HytaleServerConfig var0) {
      WorldCrashRecovery var1 = var0.getDefaults().getCrashRecovery().getMode();
      if (var1 != null) {
         class="kw">return var1;
      } else {
         class="kw">return Constants.SINGLEPLAYER ? WorldCrashRecovery.None : WorldCrashRecovery.Reload;
      }
   }

   class="kw">private void scheduleReload(
      @Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.RecoveryState var3, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var4
   ) {
      if (var3.pending != null) {
         var3.pending.cancel(false);
         var3.pending = null;
      }

      long var5 = System.nanoTime();
      long var7 = CRASH_WINDOW_NANOS + TimeUnit.SECONDS.toNanos(var4.retryDelaySeconds());
      var3.attempts = var5 - var3.lastCrashNanos > var7 ? 1 : var3.attempts + 1;
      var3.lastCrashNanos = var5;
      if (var3.attempts > var4.maxAttempts()) {
         LOGGER.at(Level.WARNING).log("Gave up recovering world '%s' after %d reload attempt(s)", var1, var4.maxAttempts());
         this.states.remove(var2);
         this.applyFallback(var1, var4.fallback());
      } else {
         LOGGER.at(Level.INFO)
            .log("Reloading crashed world '%s' in %d second(s) (attempt %d of %d)", var1, var4.retryDelaySeconds(), var3.attempts, var4.maxAttempts());
         var3.pending = HytaleServer.SCHEDULED_EXECUTOR.schedule(() -> this.reloadNow(var1, var2, var4), var4.retryDelaySeconds(), TimeUnit.SECONDS);
      }
   }

   class="kw">private void reloadNow(@Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var3) {
      WorldCrashRecoveryHandler.RecoveryState var4 = this.states.get(var2);
      if (var4 != null) {
         class="kw">synchronized (var4) {
            if (this.states.get(var2) == var4) {
               var4.pending = null;
               if (HytaleServer.get().isShuttingDown()) {
                  this.states.remove(var2);
               } else if (this.universe.getWorld(var1) != null) {
                  LOGGER.at(Level.INFO).log("World '%s' is already loaded, crash recovery superseded", var1);
                  this.states.remove(var2);
               } else {
                  var4.loading = true;

                  try {
                     this.universe.loadWorld(var1).whenComplete((var4x, var5) -> this.onReloadComplete(var1, var2, var3, var5));
                  } catch (Throwable var8) {
                     var4.loading = false;
                     ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var8)).log("Failed to start reload of crashed world '%s'", var1);
                     this.scheduleReload(var1, var2, var4, var3);
                  }
               }
            }
         }
      }
   }

   class="kw">private void onReloadComplete(@Nonnull String var1, @Nonnull String var2, @Nonnull WorldCrashRecoveryHandler.ResolvedPolicy var3, @Nullable Throwable var4) {
      WorldCrashRecoveryHandler.RecoveryState var5 = this.states.get(var2);
      if (var5 != null) {
         class="kw">synchronized (var5) {
            if (this.states.get(var2) == var5) {
               var5.loading = false;
               if (HytaleServer.get().isShuttingDown()) {
                  this.states.remove(var2);
               } else {
                  if (var4 != null) {
                     ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to reload crashed world '%s'", var1);
                     this.scheduleReload(var1, var2, var5, var3);
                  } else {
                     LOGGER.at(Level.INFO).log("Reloaded crashed world '%s'", var1);
                  }
               }
            }
         }
      }
   }

   class="kw">private void clearState(@Nonnull String var1) {
      WorldCrashRecoveryHandler.RecoveryState var2 = this.states.remove(var1);
      if (var2 != null) {
         class="kw">synchronized (var2) {
            if (var2.pending != null) {
               var2.pending.cancel(false);
               var2.pending = null;
            }
         }
      }
   }

   class="kw">private void applyFallback(@Nonnull String var1, @Nonnull WorldCrashRecovery var2) {
      if (var2 == WorldCrashRecovery.Shutdown) {
         LOGGER.at(Level.WARNING).log("World '%s' did not recover, shutting down the server", var1);
         HytaleServer.get()
            .shutdownServer(ShutdownReason.CRASH.withMessage(Message.translation("server.general.disconnect.worldNotRecovered").param("world", var1)));
      } else {
         LOGGER.at(Level.WARNING).log("World '%s' did not recover, the server is left without it", var1);
      }
   }

   class="kw">private class="kw">static class="kw">final class RecoveryState {
      class="kw">private int attempts;
      class="kw">private long lastCrashNanos;
      class="kw">private boolean loading;
      @Nullable
      class="kw">private ScheduledFuture<?> pending;

      class="kw">private RecoveryState() {
      }
   }

   class="kw">private record ResolvedPolicy(@Nonnull WorldCrashRecovery mode, int maxAttempts, int retryDelaySeconds, @Nonnull WorldCrashRecovery fallback) {
      class="kw">private ResolvedPolicy {
      }

      @Nonnull
      class="kw">private class="kw">static WorldCrashRecoveryHandler.ResolvedPolicy of(@Nonnull CrashRecoveryConfig var0, @Nonnull WorldCrashRecovery var1) {
         class="kw">return new WorldCrashRecoveryHandler.ResolvedPolicy(var1, var0.getMaxAttempts(), var0.getRetryDelaySeconds(), var0.getFallback());
      }
   }
}