diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 4dc63bf9f..956d874a1 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -28,6 +28,23 @@ public class BukkitChunkHolder> extends ChunkHolder { return new BukkitGetBlocks(extent.getNmsWorld(), getX(), getZ()); } + private void updateGet(BukkitGetBlocks get, Chunk nmsChunk, ChunkSection[] sections, ChunkSection section, char[] arr, int layer) { + synchronized (get) { + if (get.nmsChunk != nmsChunk) { + get.nmsChunk = nmsChunk; + get.sections = sections.clone(); + get.reset(); + } + if (get.sections == null) { + get.sections = sections; + } + if (get.sections[layer] != section) { + get.sections[layer] = section; + } + get.blocks[layer] = arr; + } + } + @Override public T call() { BukkitQueue extent = (BukkitQueue) getExtent(); @@ -51,6 +68,7 @@ public class BukkitChunkHolder> extends ChunkHolder { if (existingSection == null) { newSection = extent.newChunkSection(layer, hasSky, setArr); if (BukkitQueue.setSectionAtomic(sections, null, newSection, layer)) { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); continue; } else { existingSection = sections[layer]; @@ -62,10 +80,7 @@ public class BukkitChunkHolder> extends ChunkHolder { } DelegateLock lock = BukkitQueue.applyLock(existingSection); synchronized (lock) { - if (lock.isLocked()) { - lock.lock(); - lock.unlock(); - } + lock.untilFree(); synchronized (get) { ChunkSection getSection; if (get.nmsChunk != nmsChunk) { @@ -95,6 +110,8 @@ public class BukkitChunkHolder> extends ChunkHolder { if (!BukkitQueue.setSectionAtomic(sections, existingSection, newSection, layer)) { System.out.println("Failed to set chunk section:" + X + "," + Z + " layer: " + layer); continue; + } else { + updateGet(get, nmsChunk, sections, newSection, setArr, layer); } } } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java index e0f2328c6..958f5037d 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitGetBlocks.java @@ -64,10 +64,7 @@ public class BukkitGetBlocks extends CharGetBlocks { } DelegateLock lock = BukkitQueue.applyLock(section); synchronized (lock) { - if (lock.isLocked()) { - lock.lock(); - lock.unlock(); - } + lock.untilFree(); lock.setModified(false); // Efficiently convert ChunkSection to raw data try { diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java index 18660c6e6..70971042c 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitQueue.java @@ -39,7 +39,9 @@ import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import sun.misc.Unsafe; @@ -135,6 +137,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { fieldLock = tmp; fieldLock.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); int modifiers = modifiersField.getInt(fieldLock); int newModifiers = modifiers & (~Modifier.FINAL); if (newModifiers != modifiers) modifiersField.setInt(fieldLock, newModifiers); @@ -154,7 +157,7 @@ public class BukkitQueue extends SimpleCharQueueExtent { } } - public static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { + protected static boolean setSectionAtomic(ChunkSection[] sections, ChunkSection expected, ChunkSection value, int layer) { long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { return UnsafeUtils.getUNSAFE().compareAndSwapObject(sections, offset, expected, value); @@ -162,11 +165,11 @@ public class BukkitQueue extends SimpleCharQueueExtent { return false; } - public static DelegateLock applyLock(ChunkSection section) { + protected static DelegateLock applyLock(ChunkSection section) { try { synchronized (section) { DataPaletteBlock blocks = section.getBlocks(); - ReentrantLock currentLock = (ReentrantLock) fieldLock.get(blocks); + Lock currentLock = (Lock) fieldLock.get(blocks); if (currentLock instanceof DelegateLock) { return (DelegateLock) currentLock; } diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java index 20f94166c..6d79d967e 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/DelegateLock.java @@ -1,16 +1,27 @@ package com.boydti.fawe.bukkit.beta; +import org.apache.commons.lang.mutable.MutableInt; + import java.util.Collection; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class DelegateLock extends ReentrantLock { - private final ReentrantLock parent; + private final Lock parent; private volatile boolean modified; + private final AtomicInteger count; - public DelegateLock(ReentrantLock parent) { + public DelegateLock(Lock parent) { this.parent = parent; + if (!(parent instanceof ReentrantLock)) { + count = new AtomicInteger(); + } else { + count = null; + } } public boolean isModified() { @@ -22,9 +33,12 @@ public class DelegateLock extends ReentrantLock { } @Override - public void lock() { + public synchronized void lock() { modified = true; parent.lock(); + if (count != null) { + count.incrementAndGet(); + } } @Override @@ -46,10 +60,14 @@ public class DelegateLock extends ReentrantLock { public void unlock() { modified = true; parent.unlock(); - this.notifyAll(); + if (count != null) { + if (count.getAndDecrement() <= 0) { + count.incrementAndGet(); + } + } } - public ReentrantLock getParent() { + public Lock getParent() { return parent; } @@ -60,27 +78,42 @@ public class DelegateLock extends ReentrantLock { @Override public synchronized int getHoldCount() { - return parent.getHoldCount(); + throw new UnsupportedOperationException(); } @Override public synchronized boolean isHeldByCurrentThread() { - return parent.isHeldByCurrentThread(); + throw new UnsupportedOperationException(); } @Override public synchronized boolean isLocked() { - return parent.isLocked(); + if (parent instanceof ReentrantLock) { + return ((ReentrantLock) parent).isLocked(); + } + return count.get() > 0; + } + + public void untilFree() { + if (parent instanceof ReentrantLock) { + ReentrantLock rl = (ReentrantLock) parent; + if (rl.isLocked()) { + rl.lock(); + rl.unlock(); + } + return; + } + while (count.get() > 0); } @Override public synchronized boolean hasWaiters(Condition condition) { - return parent.hasWaiters(condition); + throw new UnsupportedOperationException(); } @Override public synchronized int getWaitQueueLength(Condition condition) { - return parent.getWaitQueueLength(condition); + throw new UnsupportedOperationException(); } @Override