Skip to content

Commit

Permalink
Preload important classes such as Logger and JLine
Browse files Browse the repository at this point in the history
This is for 2 reasons:
1) Ensuring our log4j is mostly loaded at OUR version.
   I've seen stack traces with line numbers that do not match our version. This means that some
   plugin has shaded in log4j and their loaded version is mixing with ours....
   So by at least trying to load a bunch of log4j classes before we load plugins, we can be
   more sure mixed versions are not loading.

2) If the jar file is replaced while the server is runnimg class not found errors galore
   This will preloaod a bunch of classes commonly seen to error during shutdown due to this.

   The goal here is to help let the server shutdown gracefully as possible. Some plugins will
   still blow up here if they access a class that hadn't been loaded yet, but goal is to at least
   stop freezing the shutdown process as it does with JLine and Log4j errors requiring an external kill.

   Ideally you should not replace jars while the server is running, but it is something that happens in
   development for testing.

Updated test server to do a copy though to avoid this happening in Paper development.
  • Loading branch information
aikar committed May 24, 2020
1 parent ea1a909 commit b6cf80e
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 39 deletions.
7 changes: 4 additions & 3 deletions Spigot-API-Patches/0004-Timings-v2.patch
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ Subject: [PATCH] Timings v2

diff --git a/src/main/java/co/aikar/timings/FullServerTickHandler.java b/src/main/java/co/aikar/timings/FullServerTickHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..64531fcce1c8aaa24567c2995c1faac64b88f7d5
index 0000000000000000000000000000000000000000..65ff5403cbc894215089626450252a050dd13119
--- /dev/null
+++ b/src/main/java/co/aikar/timings/FullServerTickHandler.java
@@ -0,0 +1,84 @@
@@ -0,0 +1,85 @@
+package co.aikar.timings;
+
+import static co.aikar.timings.TimingsManager.*;
+
+import org.bukkit.Bukkit;
+import org.jetbrains.annotations.NotNull;
+
+public class FullServerTickHandler extends TimingHandler {
Expand Down Expand Up @@ -42,7 +43,7 @@ index 0000000000000000000000000000000000000000..64531fcce1c8aaa24567c2995c1faac6
+ @Override
+ public void stopTiming() {
+ super.stopTiming();
+ if (!isEnabled()) {
+ if (!isEnabled() || Bukkit.isStopping()) {
+ return;
+ }
+ if (TimingHistory.timedTicks % 20 == 0) {
Expand Down
22 changes: 22 additions & 0 deletions Spigot-Server-Patches/0003-MC-Dev-fixes.patch
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,28 @@ index 1e1f7ec6e6e6fc698a8a5118ce21321d104dc5eb..75d9065b32731dc635d9d09c48fb9643
j = SectionPosition.a(j, EnumDirection.UP);
++k;
if (k >= l) {
diff --git a/src/main/java/net/minecraft/server/LightEngineThreaded.java b/src/main/java/net/minecraft/server/LightEngineThreaded.java
index ef315377579ca425ecb8d41aaf59eb1dd5b39e12..8776799de033f02b0f87e9ea7e4a4ce912e94dd4 100644
--- a/src/main/java/net/minecraft/server/LightEngineThreaded.java
+++ b/src/main/java/net/minecraft/server/LightEngineThreaded.java
@@ -110,7 +110,7 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable {
}

private void a(int i, int j, IntSupplier intsupplier, LightEngineThreaded.Update lightenginethreaded_update, Runnable runnable) {
- this.e.a((Object) ChunkTaskQueueSorter.a(() -> {
+ this.e.a(ChunkTaskQueueSorter.a(() -> { // Paper - decompile error
this.c.add(Pair.of(lightenginethreaded_update, runnable));
if (this.c.size() >= this.f) {
this.b();
@@ -167,7 +167,7 @@ public class LightEngineThreaded extends LightEngine implements AutoCloseable {

public void queueUpdate() {
if ((!this.c.isEmpty() || super.a()) && this.g.compareAndSet(false, true)) {
- this.b.a((Object) (() -> {
+ this.b.a((() -> { // Paper - decompile error
this.b();
this.g.set(false);
}));
diff --git a/src/main/java/net/minecraft/server/LootSelectorEntry.java b/src/main/java/net/minecraft/server/LootSelectorEntry.java
index 59bb53543113660cd2514350a24a4908a8464f24..3ed6a1e785f68c4bb6c5afe024c43150915968a3 100644
--- a/src/main/java/net/minecraft/server/LootSelectorEntry.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Other changes:
configuration

diff --git a/pom.xml b/pom.xml
index aec55b0b78fa47d427652d402cfbb61295672b11..48f5ed765cab101633efdcdd9118fd3cb5f97914 100644
index 3554314526b3f33ad02df2adfd42d45118d75526..aeaceac771644ece5365d07be77f4481ced2fe13 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,10 +44,27 @@
Expand Down Expand Up @@ -54,7 +54,7 @@ index aec55b0b78fa47d427652d402cfbb61295672b11..48f5ed765cab101633efdcdd9118fd3c
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
@@ -264,10 +281,18 @@
@@ -265,10 +282,18 @@
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/java.sql.Driver</resource>
</transformer>
Expand Down
137 changes: 137 additions & 0 deletions Spigot-Server-Patches/0467-Improved-Watchdog-Support.patch
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ This is to ensure that if main isn't truely stuck, it's not manipulating state w
This also moves all plugins who register "delayed init" tasks to occur just before "Done" so they
are properly accounted for and wont trip watchdog on init.

diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
index e257d6b36e0e78dac5b8320017d92776171e1bb0..24641501aeae0f2c2c5ce877775c7b971fb051bf 100644
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -86,6 +86,9 @@ public class Metrics {
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
+ if (MinecraftServer.getServer().hasStopped()) {
+ return;
+ }
submitData();
}
}, 1000 * 60 * 5, 1000 * 60 * 30);
diff --git a/src/main/java/net/minecraft/server/CrashReport.java b/src/main/java/net/minecraft/server/CrashReport.java
index 3de19c998b749ccf74958c2412a8c9506457383e..c7dc8787cc3456c5540d6a00a6ff051533edc25a 100644
--- a/src/main/java/net/minecraft/server/CrashReport.java
Expand Down Expand Up @@ -210,6 +224,27 @@ index b701db638370c0d07d5be0f61c6cbf19168cde8e..4ea3468614df36e1c148a44bb15d2201
return new TickTask(this.ticks, runnable);
}

diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 75906f794205f5b7fe894163e1b13bfd85c2b419..485e5d2778064c64c8dc8375b18c785649049184 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -485,6 +485,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
MutableBoolean mutableboolean = new MutableBoolean();

do {
+ boolean isShuttingDown = world.getMinecraftServer().hasStopped(); // Paper
mutableboolean.setFalse();
list.stream().map((playerchunk) -> {
CompletableFuture completablefuture;
@@ -497,7 +498,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return (IChunkAccess) completablefuture.join();
}).filter((ichunkaccess) -> {
return ichunkaccess instanceof ProtoChunkExtension || ichunkaccess instanceof Chunk;
- }).filter(this::saveChunk).forEach((ichunkaccess) -> {
+ }).filter(ichunkaccess1 -> saveChunk(ichunkaccess1, !isShuttingDown)).forEach((ichunkaccess) -> { // Paper - dont save async during shutdown
mutableboolean.setTrue();
});
} while (mutableboolean.isTrue());
diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java
index ab2831830ad3a4cec0671d189e0534c843b47f5e..78040e83899f1ef1a6d5c456beb9d13959307c18 100644
--- a/src/main/java/net/minecraft/server/PlayerList.java
Expand Down Expand Up @@ -268,6 +303,108 @@ index b627180729a24a83ca383f83aee53133ea1b398e..f49193d9d7cd9655fdedf64bebdcf4e1
}

@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 093dbeae2784d51dae74f66e3e1ce5bf6a370428..c47988c676ae2981e20980b47d58cd81ca68bb9c 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -150,6 +150,37 @@ public class Main {

OptionSet options = null;

+ // Paper start - preload logger classes to avoid plugins mixing versions
+ tryPreloadClass("com.destroystokyo.paper.log.LogFullPolicy");
+ tryPreloadClass("org.apache.logging.log4j.core.Core");
+ tryPreloadClass("org.apache.logging.log4j.core.Appender");
+ tryPreloadClass("org.apache.logging.log4j.core.ContextDataInjector");
+ tryPreloadClass("org.apache.logging.log4j.core.Filter");
+ tryPreloadClass("org.apache.logging.log4j.core.ErrorHandler");
+ tryPreloadClass("org.apache.logging.log4j.core.LogEvent");
+ tryPreloadClass("org.apache.logging.log4j.core.Logger");
+ tryPreloadClass("org.apache.logging.log4j.core.LoggerContext");
+ tryPreloadClass("org.apache.logging.log4j.core.LogEventListener");
+ tryPreloadClass("org.apache.logging.log4j.core.AbstractLogEvent");
+ tryPreloadClass("org.apache.logging.log4j.message.AsynchronouslyFormattable");
+ tryPreloadClass("org.apache.logging.log4j.message.FormattedMessage");
+ tryPreloadClass("org.apache.logging.log4j.message.ParameterizedMessage");
+ tryPreloadClass("org.apache.logging.log4j.message.Message");
+ tryPreloadClass("org.apache.logging.log4j.message.MessageFactory");
+ tryPreloadClass("org.apache.logging.log4j.message.TimestampMessage");
+ tryPreloadClass("org.apache.logging.log4j.message.SimpleMessage");
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLogger");
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerContext");
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncQueueFullPolicy");
+ tryPreloadClass("org.apache.logging.log4j.core.async.AsyncLoggerDisruptor");
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEvent");
+ tryPreloadClass("org.apache.logging.log4j.core.async.DisruptorUtil");
+ tryPreloadClass("org.apache.logging.log4j.core.async.RingBufferLogEventHandler");
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ThrowableProxy");
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ThrowableProxy$CacheEntry");
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedClassInfo");
+ tryPreloadClass("org.apache.logging.log4j.core.impl.ExtendedStackTraceElement");
+ // Paper end
try {
options = parser.parse(args);
} catch (joptsimple.OptionException ex) {
@@ -245,8 +276,59 @@ public class Main {
} catch (Throwable t) {
t.printStackTrace();
}
+ // Paper start
+ // load some required classes to avoid errors during shutdown if jar is replaced
+ // also to guarantee our version loads over plugins
+ tryPreloadClass("com.destroystokyo.paper.util.SneakyThrow");
+ tryPreloadClass("com.google.common.collect.Iterators$PeekingImpl");
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$Values");
+ tryPreloadClass("com.google.common.collect.MapMakerInternalMap$ValueIterator");
+ tryPreloadClass("com.google.common.collect.Iterables");
+ for (int i = 1; i <= 15; i++) {
+ tryPreloadClass("com.google.common.collect.Iterables$" + i, false);
+ }
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableBoolean");
+ tryPreloadClass("org.apache.commons.lang3.mutable.MutableInt");
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport");
+ tryPreloadClass("org.jline.terminal.impl.MouseSupport$1");
+ tryPreloadClass("org.jline.terminal.Terminal$MouseTracking");
+ tryPreloadClass("co.aikar.timings.TimingHistory");
+ tryPreloadClass("co.aikar.timings.TimingHistory$MinuteReport");
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext");
+ tryPreloadClass("io.netty.channel.AbstractChannelHandlerContext$11");
+ tryPreloadClass("io.netty.channel.AbstractChannel$AbstractUnsafe$8");
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise");
+ tryPreloadClass("io.netty.util.concurrent.DefaultPromise$1");
+ tryPreloadClass("io.netty.util.internal.PromiseNotificationUtil");
+ tryPreloadClass("io.netty.util.internal.SystemPropertyUtil");
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler");
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$1");
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$2");
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$3");
+ tryPreloadClass("org.bukkit.craftbukkit.scheduler.CraftScheduler$4");
+ tryPreloadClass("org.slf4j.helpers.MessageFormatter");
+ tryPreloadClass("org.slf4j.helpers.FormattingTuple");
+ tryPreloadClass("org.slf4j.helpers.BasicMarker");
+ tryPreloadClass("org.slf4j.helpers.Util");
+ // Minecraft, seen during saving
+ tryPreloadClass("net.minecraft.server.LightEngineLayerEventListener$Void");
+ tryPreloadClass("net.minecraft.server.LightEngineLayerEventListener");
+ // Paper end
+ }
+ }
+
+ // Paper start
+ private static void tryPreloadClass(String className) {
+ tryPreloadClass(className, true);
+ }
+ private static void tryPreloadClass(String className, boolean printError) {
+ try {
+ Class.forName(className);
+ } catch (ClassNotFoundException e) {
+ if (printError) System.err.println("An expected class " + className + " was not found for preloading: " + e.getMessage());
}
}
+ // Paper end

private static List<String> asList(String... params) {
return Arrays.asList(params);
diff --git a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java b/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
index 449e99d1b673870ed6892f6ab2c715a2db35c35d..899a525209cfe047ce57e758c6328a130f916dc6 100644
--- a/src/main/java/org/bukkit/craftbukkit/util/ServerShutdownThread.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ index 722db939971fe395d8250c388fbd7f3b5e87804d..ba99e9949c6fdfc4f49b6b6716100eb5
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 75906f794205f5b7fe894163e1b13bfd85c2b419..9adb858f0f86dbe9defb2247dc9e6a4795fe640f 100644
index 485e5d2778064c64c8dc8375b18c785649049184..a9f6c0835c3ae37b12d6b8b7ea59ccba7651a82a 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -131,6 +131,8 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
Expand All @@ -49,7 +49,7 @@ index 75906f794205f5b7fe894163e1b13bfd85c2b419..9adb858f0f86dbe9defb2247dc9e6a47
// Paper start - distance maps
private final com.destroystokyo.paper.util.misc.PooledLinkedHashSets<EntityPlayer> pooledLinkedPlayerHashSets = new com.destroystokyo.paper.util.misc.PooledLinkedHashSets<>();

@@ -985,7 +987,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -986,7 +988,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return Either.left(chunk);
});
}, (runnable) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ index 64e00275edf38739fe6e2d79dbcb93243e765678..a87aa07b17205b52e85f7d082fa4d516
// CraftBukkit end
public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 9adb858f0f86dbe9defb2247dc9e6a4795fe640f..030c980b522c4cada800e5d8ca47f0b8733bf5b6 100644
index a9f6c0835c3ae37b12d6b8b7ea59ccba7651a82a..72d080fc3e5cec2310fd44ecf3acf11fb1d6d175 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -1537,6 +1537,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1538,6 +1538,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
.printStackTrace();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ index 3a88c9a67062eb73ad8257ea786efca7e7e99f65..6d3b34ead9cc95dcc1152dffa8c6c4a8
List<Entity> list = this.tracker.getPassengers();

diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833408f1fdc 100644
index 1031f19b60fd3e2d4e567007f6989417248a1200..c6b1b5d83ee4d91ccf939b8ae3d188f6694e50cd 100644
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
@@ -143,21 +143,51 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
Expand Down Expand Up @@ -145,7 +145,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833
}

public void updatePlayerMobTypeMap(Entity entity) {
@@ -1434,17 +1502,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1435,17 +1503,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
}

public void movePlayer(EntityPlayer entityplayer) {
Expand All @@ -164,7 +164,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833

int i = MathHelper.floor(entityplayer.locX()) >> 4;
int j = MathHelper.floor(entityplayer.locZ()) >> 4;
@@ -1561,7 +1619,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1562,7 +1620,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {

entity.tracker = playerchunkmap_entitytracker; // Paper - Fast access to tracker
this.trackedEntities.put(entity.getId(), playerchunkmap_entitytracker);
Expand All @@ -173,7 +173,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833
if (entity instanceof EntityPlayer) {
EntityPlayer entityplayer = (EntityPlayer) entity;

@@ -1605,7 +1663,37 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1606,7 +1664,37 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
entity.tracker = null; // Paper - We're no longer tracked
}

Expand Down Expand Up @@ -211,7 +211,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833
List<EntityPlayer> list = Lists.newArrayList();
List<EntityPlayer> list1 = this.world.getPlayers();

@@ -1673,23 +1761,31 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1674,23 +1762,31 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
PacketDebug.a(this.world, chunk.getPos());
List<Entity> list = Lists.newArrayList();
List<Entity> list1 = Lists.newArrayList();
Expand Down Expand Up @@ -255,7 +255,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833

Iterator iterator;
Entity entity1;
@@ -1727,7 +1823,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1728,7 +1824,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {

public class EntityTracker {

Expand All @@ -264,7 +264,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833
private final Entity tracker;
private final int trackingDistance;
private SectionPosition e;
@@ -1744,6 +1840,42 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1745,6 +1841,42 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
this.e = SectionPosition.a(entity);
}

Expand Down Expand Up @@ -307,7 +307,7 @@ index 4d591d620262e8c4ed0508b01e26ef7355e75e88..9a25874a97f9d3f516e074a7ec32c833
public boolean equals(Object object) {
return object instanceof PlayerChunkMap.EntityTracker ? ((PlayerChunkMap.EntityTracker) object).tracker.getId() == this.tracker.getId() : false;
}
@@ -1840,7 +1972,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@@ -1841,7 +1973,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
int j = entity.getEntityType().getChunkRange() * 16;
j = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, j); // Paper

Expand Down
Loading

0 comments on commit b6cf80e

Please sign in to comment.