mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
3fe4a2dd2f
If a chunk load comes in on a chunk load or gen thread, execute it synchronously on that thread instead of enqueueing it. It doesn't make sense to enqueue it as that thread is then going to future.join() it and block until it's ready anyways. This opens risk to a deadlock if every load or gen thread is waiting on a recursive chunk but it will never finish because all of the threads are waiting.
117 lines
No EOL
4.9 KiB
Diff
117 lines
No EOL
4.9 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Sat, 11 Aug 2018 00:49:20 -0400
|
|
Subject: [PATCH] Detect and repair corrupt Region Files
|
|
|
|
If the file has partial data written but not the full 8192 bytes,
|
|
then the server will be unable to load that region file...
|
|
|
|
I don't know why mojang only checks for 4096, when anything less than 8192 is a crash.
|
|
|
|
But to be safe, it will attempt to back up the file.
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/RegionFile.java b/src/main/java/net/minecraft/server/RegionFile.java
|
|
index 5d2853b9ce..6a2edfd1e1 100644
|
|
--- a/src/main/java/net/minecraft/server/RegionFile.java
|
|
+++ b/src/main/java/net/minecraft/server/RegionFile.java
|
|
@@ -0,0 +0,0 @@ import javax.annotation.Nullable;
|
|
|
|
public class RegionFile {
|
|
private static final byte[] a = new byte[4096];
|
|
- private final File b;
|
|
- private RandomAccessFile c;
|
|
- private final int[] d = new int[1024];
|
|
- private final int[] e = new int[1024];
|
|
+ private final File b;private File getFile() { return b; } // Paper - OBFHELPER
|
|
+ private RandomAccessFile c;private RandomAccessFile getDataFile() { return c; } // Paper - OBFHELPER
|
|
+ private final int[] d = new int[1024];private int[] offsets = d; // Paper - OBFHELPER
|
|
+ private final int[] e = new int[1024];private int[] timestamps = e; // Paper - OBFHELPER
|
|
private List<Boolean> f;
|
|
private int g;
|
|
private long h;
|
|
@@ -0,0 +0,0 @@ public class RegionFile {
|
|
}
|
|
|
|
this.c = new RandomAccessFile(file1, "rw");
|
|
- if (this.c.length() < 4096L) {
|
|
+ if (this.c.length() < 8192L) { // Paper - headers should be 8192
|
|
this.c.write(a);
|
|
this.c.write(a);
|
|
this.g += 8192;
|
|
@@ -0,0 +0,0 @@ public class RegionFile {
|
|
for(int j1 = 0; j1 < 1024; ++j1) {
|
|
int k = headerAsInts.get(); // Paper
|
|
this.d[j1] = k;
|
|
- if (k != 0 && (k >> 8) + (k & 255) <= this.f.size()) {
|
|
+ if (k > 0 && (k >> 8) > 1 && (k >> 8) + (k & 255) <= this.f.size()) { // Paper >= 1 as 0/1 are the headers, and negative isnt valid
|
|
for(int l = 0; l < (k & 255); ++l) {
|
|
this.f.set((k >> 8) + l, false);
|
|
}
|
|
- }
|
|
+ } else if (k != 0) deleteChunk(j1); // Paper
|
|
}
|
|
|
|
for(int k1 = 0; k1 < 1024; ++k1) {
|
|
int l1 = headerAsInts.get(); // Paper
|
|
- this.e[k1] = l1;
|
|
+ if (offsets[k1] != 0) this.timestamps[k1] = l1; // Paper - don't set timestamp if it got 0'd above due to corruption
|
|
}
|
|
} catch (IOException ioexception) {
|
|
ioexception.printStackTrace();
|
|
@@ -0,0 +0,0 @@ public class RegionFile {
|
|
|
|
}
|
|
|
|
+ // Paper start
|
|
+ public synchronized void deleteChunk(int j1) {
|
|
+ backup();
|
|
+ int k = offsets[j1];
|
|
+ int x = j1 & 1024;
|
|
+ int z = j1 >> 2;
|
|
+ int offset = (k >> 8);
|
|
+ int len = (k & 255);
|
|
+ org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger();
|
|
+ String debug = "idx:" + + j1 + " - " + x + "," + z + " - offset: " + offset + " - len: " + len;
|
|
+ try {
|
|
+ RandomAccessFile file = getDataFile();
|
|
+ file.seek(j1 * 4);
|
|
+ file.writeInt(0);
|
|
+ // clear the timestamp
|
|
+ file.seek(4096 + j1 * 4);
|
|
+ file.writeInt(0);
|
|
+ timestamps[j1] = 0;
|
|
+ offsets[j1] = 0;
|
|
+ logger.error("Deleted corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e);
|
|
+ } catch (IOException e) {
|
|
+
|
|
+ logger.error("Error deleting corrupt chunk (" + debug + ") " + getFile().getAbsolutePath(), e);
|
|
+ }
|
|
+ }
|
|
+ private boolean backedUp = false;
|
|
+ private synchronized void backup() {
|
|
+ if (backedUp) {
|
|
+ return;
|
|
+ }
|
|
+ backedUp = true;
|
|
+ File file = this.getFile();
|
|
+ java.text.DateFormat formatter = new java.text.SimpleDateFormat("yyyy-MM-dd");
|
|
+ java.util.Date today = new java.util.Date();
|
|
+ File corrupt = new File(file.getParentFile(), file.getName() + "." + formatter.format(today) + ".corrupt");
|
|
+ if (corrupt.exists()) {
|
|
+ return;
|
|
+ }
|
|
+ org.apache.logging.log4j.Logger logger = org.apache.logging.log4j.LogManager.getLogger();
|
|
+ logger.error("Region file " + file.getAbsolutePath() + " was corrupt. Backing up to " + corrupt.getAbsolutePath() + " and repairing");
|
|
+ try {
|
|
+ java.nio.file.Files.copy(file.toPath(), corrupt.toPath());
|
|
+
|
|
+ } catch (IOException e) {
|
|
+ logger.error("Error backing up corrupt file" + file.getAbsolutePath(), e);
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
class ChunkBuffer extends ByteArrayOutputStream {
|
|
private final int b;
|
|
private final int c;
|
|
--
|