From be9866ddb3ecd90e7e422779f2db0f586023d6f1 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 13 Jan 2021 19:02:51 +0000 Subject: [PATCH] Fix a lot of FAWE-freezing properly - Add a "loadPrivately" method to be used when GetChunks are called to avoid synchronocity issues with super classes being used on different threads - Synchronise the call method so we're not attempting to call whilst also loading/updating --- .../adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java | 16 ++++++++++++---- .../adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java | 16 ++++++++++++---- .../adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java | 16 ++++++++++++---- .../adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java | 16 ++++++++++++---- .../beta/implementation/blocks/CharBlocks.java | 2 -- .../queue/SingleThreadQueueExtent.java | 15 ++------------- 6 files changed, 50 insertions(+), 31 deletions(-) diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java index 6a23beeee..a2ab70498 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_15_2/BukkitGetBlocks_1_15_2.java @@ -376,7 +376,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl } @Override - public > T call(IChunkSet set, Runnable finalizer) { + public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null; try { @@ -424,7 +424,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl char[] setArr = set.load(layer).clone(); if (createCopy) { - copy.storeSection(layer, load(layer).clone()); + copy.storeSection(layer, loadPrivately(layer).clone()); } ChunkSection newSection; @@ -458,12 +458,12 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { + } else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) { this.reset(layer); } else if (lock.isModified()) { this.reset(layer); } - newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode); + newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::loadPrivately, setArr, fastmode); if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); } else { @@ -676,6 +676,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl } } + private char[] loadPrivately(int layer) { + if (super.sections[layer].isFull()) { + return super.blocks[layer]; + } else { + return BukkitGetBlocks_1_15_2.this.update(layer, null); + } + } + @Override public synchronized void send(int mask, boolean lighting) { BukkitAdapter_1_15_2.sendChunk(world, chunkX, chunkZ, mask, lighting); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java index 5baadd20a..1656fcb60 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_1/BukkitGetBlocks_1_16_1.java @@ -376,7 +376,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl } @Override - public > T call(IChunkSet set, Runnable finalizer) { + public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null; try { @@ -424,7 +424,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl char[] setArr = set.load(layer).clone(); if (createCopy) { - copy.storeSection(layer, load(layer).clone()); + copy.storeSection(layer, loadPrivately(layer).clone()); } ChunkSection newSection; @@ -458,13 +458,13 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { + } else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) { this.reset(layer); } else if (lock.isModified()) { this.reset(layer); } newSection = BukkitAdapter_1_16_1 - .newChunkSection(layer, this::load, setArr, fastmode); + .newChunkSection(layer, this::loadPrivately, setArr, fastmode); if (!BukkitAdapter_1_16_1 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); @@ -678,6 +678,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl } } + private char[] loadPrivately(int layer) { + if (super.sections[layer].isFull()) { + return super.blocks[layer]; + } else { + return BukkitGetBlocks_1_16_1.this.update(layer, null); + } + } + @Override public synchronized void send(int mask, boolean lighting) { BukkitAdapter_1_16_1.sendChunk(world, chunkX, chunkZ, mask, lighting); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java index 8e62d54db..4e7167274 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_2/BukkitGetBlocks_1_16_2.java @@ -379,7 +379,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl } @Override - public > T call(IChunkSet set, Runnable finalizer) { + public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null; try { @@ -427,7 +427,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl char[] setArr = set.load(layer).clone(); if (createCopy) { - copy.storeSection(layer, load(layer).clone()); + copy.storeSection(layer, loadPrivately(layer).clone()); } ChunkSection newSection; @@ -461,13 +461,13 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { + } else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) { this.reset(layer); } else if (lock.isModified()) { this.reset(layer); } newSection = BukkitAdapter_1_16_2 - .newChunkSection(layer, this::load, setArr, fastmode); + .newChunkSection(layer, this::loadPrivately, setArr, fastmode); if (!BukkitAdapter_1_16_2 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); @@ -681,6 +681,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl } } + private char[] loadPrivately(int layer) { + if (super.sections[layer].isFull()) { + return super.blocks[layer]; + } else { + return BukkitGetBlocks_1_16_2.this.update(layer, null); + } + } + @Override public synchronized void send(int mask, boolean lighting) { BukkitAdapter_1_16_2.sendChunk(world, chunkX, chunkZ, mask, lighting); diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java index c78063452..2a6d84bfa 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/adapter/mc1_16_4/BukkitGetBlocks_1_16_4.java @@ -379,7 +379,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl } @Override - public > T call(IChunkSet set, Runnable finalizer) { + public synchronized > T call(IChunkSet set, Runnable finalizer) { forceLoadSections = false; copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world) : null; try { @@ -427,7 +427,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl char[] setArr = set.load(layer).clone(); if (createCopy) { - copy.storeSection(layer, load(layer).clone()); + copy.storeSection(layer, loadPrivately(layer).clone()); } ChunkSection newSection; @@ -461,13 +461,13 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl } else if (existingSection != getSections(false)[layer]) { this.sections[layer] = existingSection; this.reset(); - } else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) { + } else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) { this.reset(layer); } else if (lock.isModified()) { this.reset(layer); } newSection = BukkitAdapter_1_16_4 - .newChunkSection(layer, this::load, setArr, fastmode); + .newChunkSection(layer, this::loadPrivately, setArr, fastmode); if (!BukkitAdapter_1_16_4 .setSectionAtomic(sections, existingSection, newSection, layer)) { log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer); @@ -681,6 +681,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl } } + private char[] loadPrivately(int layer) { + if (super.sections[layer].isFull()) { + return super.blocks[layer]; + } else { + return BukkitGetBlocks_1_16_4.this.update(layer, null); + } + } + @Override public synchronized void send(int mask, boolean lighting) { BukkitAdapter_1_16_4.sendChunk(world, chunkX, chunkZ, mask, lighting); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java index 4a10276e5..e656cdb9d 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/blocks/CharBlocks.java @@ -9,8 +9,6 @@ import org.jetbrains.annotations.Range; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.locks.ReentrantLock; - public abstract class CharBlocks implements IBlocks { public static final Logger logger = LoggerFactory.getLogger(CharBlocks.class); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/SingleThreadQueueExtent.java index 6569ec61c..25c64cbcf 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/queue/SingleThreadQueueExtent.java @@ -250,19 +250,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen // - memory is low & queue size > num threads + 8 // - queue size > target size and primary queue has less than num threads submissions if (enabledQueue && ((lowMem && size > Settings.IMP.QUEUE.PARALLEL_THREADS + 8) || (size > Settings.IMP.QUEUE.TARGET_SIZE && Fawe.get().getQueueHandler().isUnderutilized()))) { - int i = 0; - boolean found = false; - while (i < chunks.size() && (chunk = chunks.get(i)) != null) { - if (Thread.holdsLock(chunk)) { - found = true; - break; - } - i++; - } - Future future = null; - if (found) { - future = submitUnchecked(chunk); - } + chunk = chunks.removeFirst(); + final Future future = submitUnchecked(chunk); if (future != null && !future.isDone()) { final int targetSize; if (lowMem) {