mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-13 21:13:53 +00:00
fix: vastly superier handling of queue chunks (#2461)
- remove ChunkHolder locking concept as this is no longer needed - previously we obtained the copy from chunk GET on finalize, meaning the copy could be replaced by a "newer" one (bad) - work around this issue by introducing concept of "unique" keys to map chunk GET copies to - correctly handle resetting of various chunk-related classes to actually allow pooling to work - remove chunks as they are submitted when flushing a SingleThreadQueueExtenting
This commit is contained in:
@ -14,7 +14,6 @@ import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||
import com.fastasyncworldedit.core.util.MathMan;
|
||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.jnbt.StringTag;
|
||||
@ -66,7 +65,6 @@ import javax.annotation.Nonnull;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -76,13 +74,14 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBlocks {
|
||||
|
||||
@ -95,6 +94,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
.getInstance()
|
||||
.getBukkitImplAdapter());
|
||||
private final ReadWriteLock sectionLock = new ReentrantReadWriteLock();
|
||||
private final ReentrantLock callLock = new ReentrantLock();
|
||||
private final ServerLevel serverLevel;
|
||||
private final int chunkX;
|
||||
private final int chunkZ;
|
||||
@ -104,15 +104,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
private final int maxSectionPosition;
|
||||
private final Registry<Biome> biomeRegistry;
|
||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||
private final Object sendLock = new Object();
|
||||
private LevelChunkSection[] sections;
|
||||
private LevelChunk levelChunk;
|
||||
private DataLayer[] blockLight;
|
||||
private DataLayer[] skyLight;
|
||||
private boolean createCopy = false;
|
||||
private PaperweightGetBlocks_Copy copy = null;
|
||||
private boolean forceLoadSections = true;
|
||||
private boolean lightUpdate = false;
|
||||
private int copyKey = 0;
|
||||
|
||||
public PaperweightGetBlocks(World world, int chunkX, int chunkZ) {
|
||||
this(((CraftWorld) world).getHandle(), chunkX, chunkZ);
|
||||
@ -147,13 +148,27 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
public int setCreateCopy(boolean createCopy) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempting to set if chunk GET should create copy, but it is not call-locked.");
|
||||
}
|
||||
this.createCopy = createCopy;
|
||||
return ++this.copyKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCopy() {
|
||||
return copy;
|
||||
public IChunkGet getCopy(final int key) {
|
||||
return copies.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lockCall() {
|
||||
this.callLock.lock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unlockCall() {
|
||||
this.callLock.unlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -388,8 +403,17 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
|
||||
if (!callLock.isHeldByCurrentThread()) {
|
||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||
}
|
||||
forceLoadSections = false;
|
||||
copy = createCopy ? new PaperweightGetBlocks_Copy(getChunk()) : null;
|
||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
||||
if (createCopy) {
|
||||
if (copies.containsKey(copyKey)) {
|
||||
throw new IllegalStateException("Copy key already used.");
|
||||
}
|
||||
copies.put(copyKey, copy);
|
||||
}
|
||||
try {
|
||||
ServerLevel nmsWorld = serverLevel;
|
||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
||||
@ -883,9 +907,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
if (super.sections[layer] != null) {
|
||||
synchronized (super.sectionLocks[layer]) {
|
||||
if (super.sections[layer].isFull() && super.blocks[layer] != null) {
|
||||
char[] blocks = new char[4096];
|
||||
System.arraycopy(super.blocks[layer], 0, blocks, 0, 4096);
|
||||
return blocks;
|
||||
return super.blocks[layer];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1007,9 +1029,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
||||
|
||||
public LevelChunkSection[] getSections(boolean force) {
|
||||
force &= forceLoadSections;
|
||||
sectionLock.readLock().lock();
|
||||
LevelChunkSection[] tmp = sections;
|
||||
sectionLock.readLock().unlock();
|
||||
if (tmp == null || force) {
|
||||
try {
|
||||
sectionLock.writeLock().lock();
|
||||
|
@ -11,7 +11,6 @@ import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2.nbt.PaperweightLazyCompoundTag;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||
@ -24,6 +23,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -101,7 +101,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCreateCopy(boolean createCopy) {
|
||||
public int setCreateCopy(boolean createCopy) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -187,6 +188,10 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
layer -= getMinSectionPosition();
|
||||
if (blocks[layer] == null) {
|
||||
blocks[layer] = new char[4096];
|
||||
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
|
||||
}
|
||||
return blocks[layer];
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user