From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: wangxyper Date: Mon, 9 Jan 2023 12:35:11 +0800 Subject: [PATCH] Hearse: Complete half of the code and fix some problems Original license: MIT Original project: https://github.com/NaturalCodeClub/HearseRewrite diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java index 2a43625d13d7aa253c15aba8092ac9361785a5f0..52f0c9dddf29a28cc360fbacb923445e5c3f82a6 100644 --- a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java +++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java @@ -4,12 +4,19 @@ import io.papermc.paper.util.TickThread; public class WorkerThread extends TickThread { + public WorkerThread(String name) { super(name); this.setDaemon(true); this.setPriority(Thread.NORM_PRIORITY - 2); } + public WorkerThread(Runnable run, String name) { + super(run, name); + this.setDaemon(true); + this.setPriority(Thread.NORM_PRIORITY - 2); + } + public static boolean isWorker(){ return Thread.currentThread() instanceof WorkerThread; } diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java index f7ca6d650d9089b65137d61acca64c89e5b4db22..8899c02a2242b51097a03c7e3ca03b8768c60117 100644 --- a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java +++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java @@ -10,11 +10,11 @@ public class WorkerThreadPoolExecutor extends ThreadPoolExecutor { private final Queue taskEntries = new ConcurrentLinkedQueue<>(); public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull WorkerThreadFactory workerThreadFactory) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r)); + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, workerThreadFactory::getNewThread); } public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull WorkerThreadFactory workerThreadFactory, @NotNull RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r), handler); + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, workerThreadFactory::getNewThread, handler); } public void executeWithSubTask(Runnable mainTask,Runnable subTask){ diff --git a/src/main/java/co/earthme/hearse/server/ServerHook.java b/src/main/java/co/earthme/hearse/server/ServerHook.java index 22260735664d986fed6bf82e4016b647417e1932..524a55c3298a079e416c742641af55725a602a2b 100644 --- a/src/main/java/co/earthme/hearse/server/ServerHook.java +++ b/src/main/java/co/earthme/hearse/server/ServerHook.java @@ -5,6 +5,8 @@ import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import org.apache.logging.log4j.LogManager; + import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -19,7 +21,7 @@ public class ServerHook { TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), task -> { - WorkerThread workerThread = new WorkerThread("Hearse-Worker-Thread # "+threadId.getAndIncrement()); + WorkerThread workerThread = new WorkerThread(task,"Hearse-Worker-Thread # "+threadId.getAndIncrement()); return workerThread; } ); diff --git a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java index f72d99bea1c78c8882793fa8ee3dc3642be1b8c7..62a74cbdb7f04b652dddac9e9c6191d5b86c3323 100644 --- a/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java +++ b/src/main/java/io/papermc/paper/chunk/PlayerChunkLoader.java @@ -37,11 +37,11 @@ public final class PlayerChunkLoader { public static final int LOADED_TICKET_LEVEL = 33; public static int getTickViewDistance(final Player player) { - return getTickViewDistance(((CraftPlayer)player).getHandle()); + return getTickViewDistance(((CraftPlayer) player).getHandle()); } public static int getTickViewDistance(final ServerPlayer player) { - final ServerLevel level = (ServerLevel)player.level; + final ServerLevel level = (ServerLevel) player.level; final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); if (data == null) { return level.chunkSource.chunkMap.playerChunkManager.getTargetTickViewDistance(); @@ -50,11 +50,11 @@ public final class PlayerChunkLoader { } public static int getLoadViewDistance(final Player player) { - return getLoadViewDistance(((CraftPlayer)player).getHandle()); + return getLoadViewDistance(((CraftPlayer) player).getHandle()); } public static int getLoadViewDistance(final ServerPlayer player) { - final ServerLevel level = (ServerLevel)player.level; + final ServerLevel level = (ServerLevel) player.level; final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); if (data == null) { return level.chunkSource.chunkMap.playerChunkManager.getLoadDistance(); @@ -63,11 +63,11 @@ public final class PlayerChunkLoader { } public static int getSendViewDistance(final Player player) { - return getSendViewDistance(((CraftPlayer)player).getHandle()); + return getSendViewDistance(((CraftPlayer) player).getHandle()); } public static int getSendViewDistance(final ServerPlayer player) { - final ServerLevel level = (ServerLevel)player.level; + final ServerLevel level = (ServerLevel) player.level; final PlayerLoaderData data = level.chunkSource.chunkMap.playerChunkManager.getData(player); if (data == null) { return level.chunkSource.chunkMap.playerChunkManager.getTargetSendDistance(); @@ -75,9 +75,6 @@ public final class PlayerChunkLoader { return data.getTargetSendViewDistance(); } - private final StampedLock sendLock = new StampedLock(); - private final StampedLock loadLock = new StampedLock(); - protected final ChunkMap chunkMap; protected final Reference2ObjectLinkedOpenHashMap playerMap = new Reference2ObjectLinkedOpenHashMap<>(512, 0.7f); protected final ReferenceLinkedOpenHashSet chunkSendQueue = new ReferenceLinkedOpenHashSet<>(512, 0.7f); @@ -376,7 +373,7 @@ public final class PlayerChunkLoader { } return !(data.hasSentChunk(chunkX - 1, chunkZ) && data.hasSentChunk(chunkX + 1, chunkZ) && - data.hasSentChunk(chunkX, chunkZ - 1) && data.hasSentChunk(chunkX, chunkZ + 1)); + data.hasSentChunk(chunkX, chunkZ - 1) && data.hasSentChunk(chunkX, chunkZ + 1)); } protected int getMaxConcurrentChunkSends() { @@ -386,15 +383,15 @@ public final class PlayerChunkLoader { protected int getMaxChunkLoads() { double config = GlobalConfiguration.get().chunkLoading.playerMaxConcurrentLoads; double max = GlobalConfiguration.get().chunkLoading.globalMaxConcurrentLoads; - return (int)Math.ceil(Math.min(config * MinecraftServer.getServer().getPlayerCount(), max <= 1.0 ? Double.MAX_VALUE : max)); + return (int) Math.ceil(Math.min(config * MinecraftServer.getServer().getPlayerCount(), max <= 1.0 ? Double.MAX_VALUE : max)); } protected long getTargetSendPerPlayerAddend() { - return GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate <= 1.0 ? 0L : (long)Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate); + return GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate <= 1.0 ? 0L : (long) Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.targetPlayerChunkSendRate); } protected long getMaxSendAddend() { - return GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate <= 1.0 ? 0L : (long)Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate); + return GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate <= 1.0 ? 0L : (long) Math.round(1.0e9 / GlobalConfiguration.get().chunkLoading.globalMaxChunkSendRate); } public void onChunkPlayerTickReady(final int chunkX, final int chunkZ) { @@ -416,7 +413,7 @@ public final class PlayerChunkLoader { if (!(raw instanceof ServerPlayer)) { continue; } - this.onChunkSendReady((ServerPlayer)raw, chunkX, chunkZ); + this.onChunkSendReady((ServerPlayer) raw, chunkX, chunkZ); } } @@ -485,19 +482,9 @@ public final class PlayerChunkLoader { } loaderData.remove(); - long id1 = this.loadLock.writeLock(); - try { - this.chunkLoadQueue.remove(loaderData); - }finally { - this.loadLock.unlockWrite(id1); - } + this.chunkLoadQueue.remove(loaderData); - final long id = this.sendLock.writeLock(); - try { - this.chunkSendQueue.remove(loaderData); - }finally { - this.sendLock.unlockWrite(id); - } + this.chunkSendQueue.remove(loaderData); this.chunkSendWaitQueue.remove(loaderData); synchronized (this.sendingChunkCounts) { @@ -534,49 +521,34 @@ public final class PlayerChunkLoader { protected static final AtomicInteger concurrentChunkSends = new AtomicInteger(); protected final Reference2IntOpenHashMap sendingChunkCounts = new Reference2IntOpenHashMap<>(); private static long nextChunkSend; + private void trySendChunks() { final long time = System.nanoTime(); if (time < nextChunkSend) { return; } - final long id = this.sendLock.writeLock(); - try { - // drain entries from wait queue - while (!this.chunkSendWaitQueue.isEmpty()) { - final PlayerLoaderData data = this.chunkSendWaitQueue.first(); + // drain entries from wait queue + while (!this.chunkSendWaitQueue.isEmpty()) { + final PlayerLoaderData data = this.chunkSendWaitQueue.first(); - if (data.nextChunkSendTarget > time) { - break; - } + if (data.nextChunkSendTarget > time) { + break; + } - this.chunkSendWaitQueue.pollFirst(); + this.chunkSendWaitQueue.pollFirst(); - this.chunkSendQueue.add(data); - } - }finally { - this.sendLock.unlockWrite(id); + this.chunkSendQueue.add(data); } - long id2 = this.sendLock.readLock(); - try { - if (this.chunkSendQueue.isEmpty()) { - return; - } - }finally { - this.sendLock.unlockRead(id2); + if (this.chunkSendQueue.isEmpty()) { + return; } final int maxSends = this.getMaxConcurrentChunkSends(); final long nextPlayerDeadline = this.getTargetSendPerPlayerAddend() + time; - for (;;) { - - long id3 = this.sendLock.readLock(); - try { - if (this.chunkSendQueue.isEmpty()) { - break; - } - }finally { - this.sendLock.unlockRead(id3); + for (; ; ) { + if (this.chunkSendQueue.isEmpty()) { + break; } final int currSends = concurrentChunkSends.get(); @@ -590,29 +562,17 @@ public final class PlayerChunkLoader { // send chunk - PlayerLoaderData data; - - final long id4 = this.sendLock.writeLock(); - try { - data = this.chunkSendQueue.removeFirst(); - }finally { - this.sendLock.unlockWrite(id4); - } + PlayerLoaderData data = this.chunkSendQueue.removeFirst(); final ChunkPriorityHolder queuedSend = data.sendQueue.pollFirst(); if (queuedSend == null) { concurrentChunkSends.getAndDecrement(); // we never sent, so decrease // stop iterating over players who have nothing to send - final long id5 = this.sendLock.readLock(); - try { - if (this.chunkSendQueue.isEmpty()) { - // nothing left - break; - } - continue; - }finally { - this.sendLock.unlockRead(id5); + if (this.chunkSendQueue.isEmpty()) { + // nothing left + break; } + continue; } if (!this.isChunkPlayerLoaded(queuedSend.chunkX, queuedSend.chunkZ)) { @@ -620,7 +580,6 @@ public final class PlayerChunkLoader { } data.nextChunkSendTarget = nextPlayerDeadline; - this.sendLock.writeLock(); synchronized (this.sendingChunkCounts) { this.sendingChunkCounts.addTo(data, 1); @@ -652,43 +611,27 @@ public final class PlayerChunkLoader { protected int concurrentChunkLoads; // this interval prevents bursting a lot of chunk loads - protected static final IntervalledCounter TICKET_ADDITION_COUNTER_SHORT = new IntervalledCounter((long)(1.0e6 * 50.0)); // 50ms + protected static final IntervalledCounter TICKET_ADDITION_COUNTER_SHORT = new IntervalledCounter((long) (1.0e6 * 50.0)); // 50ms // this interval ensures the rate is kept between ticks correctly - protected static final IntervalledCounter TICKET_ADDITION_COUNTER_LONG = new IntervalledCounter((long)(1.0e6 * 1000.0)); // 1000ms + protected static final IntervalledCounter TICKET_ADDITION_COUNTER_LONG = new IntervalledCounter((long) (1.0e6 * 1000.0)); // 1000ms + private void tryLoadChunks() { - final long id = this.loadLock.writeLock(); - try { - if (this.chunkLoadQueue.isEmpty()) { - return; - } - }finally { - this.loadLock.unlockWrite(id); + if (this.chunkLoadQueue.isEmpty()) { + return; } final int maxLoads = this.getMaxChunkLoads(); final long time = System.nanoTime(); boolean updatedCounters = false; - for (;;) { - PlayerLoaderData data; - - final long id1 = this.loadLock.writeLock(); - try { - data = this.chunkLoadQueue.pollFirst(); - }finally { - this.loadLock.unlock(id1); - } + for (; ; ) { + PlayerLoaderData data = this.chunkLoadQueue.pollFirst(); data.lastChunkLoad = time; final ChunkPriorityHolder queuedLoad = data.loadQueue.peekFirst(); if (queuedLoad == null) { - long id2 = this.loadLock.writeLock(); - try { - if (this.chunkLoadQueue.isEmpty()) { - break; - } - }finally { - this.loadLock.unlockWrite(id2); + if (this.chunkLoadQueue.isEmpty()) { + break; } continue; } @@ -704,12 +647,7 @@ public final class PlayerChunkLoader { if (this.isChunkPlayerLoaded(queuedLoad.chunkX, queuedLoad.chunkZ)) { // already loaded! data.loadQueue.pollFirst(); // already loaded so we just skip - final long id3 = this.loadLock.writeLock(); - try { - this.chunkLoadQueue.add(data); - }finally { - this.loadLock.unlockWrite(id3); - } + this.chunkLoadQueue.add(data); // ensure the chunk is queued to send this.onChunkSendReady(queuedLoad.chunkX, queuedLoad.chunkZ); continue; @@ -739,14 +677,9 @@ public final class PlayerChunkLoader { final int currentChunkLoads = this.concurrentChunkLoads; if (currentChunkLoads >= maxLoads || (GlobalConfiguration.get().chunkLoading.globalMaxChunkLoadRate > 0 && (TICKET_ADDITION_COUNTER_SHORT.getRate() >= GlobalConfiguration.get().chunkLoading.globalMaxChunkLoadRate || TICKET_ADDITION_COUNTER_LONG.getRate() >= GlobalConfiguration.get().chunkLoading.globalMaxChunkLoadRate)) - || (GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate > 0.0 && (data.ticketAdditionCounterShort.getRate() >= GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate || data.ticketAdditionCounterLong.getRate() >= GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate))) { + || (GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate > 0.0 && (data.ticketAdditionCounterShort.getRate() >= GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate || data.ticketAdditionCounterLong.getRate() >= GlobalConfiguration.get().chunkLoading.playerMaxChunkLoadRate))) { // don't poll, we didn't load it - final long id4 = this.loadLock.writeLock(); - try { - this.chunkLoadQueue.add(data); - }finally { - this.loadLock.unlockWrite(id4); - } + this.chunkLoadQueue.add(data); break; } } @@ -755,12 +688,7 @@ public final class PlayerChunkLoader { data.loadQueue.pollFirst(); // now that we've polled we can re-add to load queue - final long id4 = this.loadLock.writeLock(); - try { - this.chunkLoadQueue.add(data); - }finally { - this.loadLock.unlockWrite(id4); - } + this.chunkLoadQueue.add(data); // add necessary tickets to load chunk up to send-ready for (int dz = -1; dz <= 1; ++dz) { @@ -840,7 +768,7 @@ public final class PlayerChunkLoader { protected static final double PRIORITISED_DISTANCE = 12.0 * 16.0; // Player max sprint speed is approximately 8m/s - protected static final double LOOK_PRIORITY_SPEED_THRESHOLD = (10.0/20.0) * (10.0/20.0); + protected static final double LOOK_PRIORITY_SPEED_THRESHOLD = (10.0 / 20.0) * (10.0 / 20.0); protected static final double LOOK_PRIORITY_YAW_DELTA_RECALC_THRESHOLD = 3.0f; protected double lastLocX = Double.NEGATIVE_INFINITY; @@ -887,9 +815,9 @@ public final class PlayerChunkLoader { protected long nextChunkSendTarget; // this interval prevents bursting a lot of chunk loads - protected final IntervalledCounter ticketAdditionCounterShort = new IntervalledCounter((long)(1.0e6 * 50.0)); // 50ms + protected final IntervalledCounter ticketAdditionCounterShort = new IntervalledCounter((long) (1.0e6 * 50.0)); // 50ms // this ensures the rate is kept between ticks correctly - protected final IntervalledCounter ticketAdditionCounterLong = new IntervalledCounter((long)(1.0e6 * 1000.0)); // 1000ms + protected final IntervalledCounter ticketAdditionCounterLong = new IntervalledCounter((long) (1.0e6 * 1000.0)); // 1000ms public long lastChunkLoad; @@ -986,14 +914,14 @@ public final class PlayerChunkLoader { // b = ((p3z - p1z)(targetX - p3x) + (p1x - p3x)(targetZ - p3z)) / d // c = 1.0 - a - b - final double d = (p2z - p3z)*(p1x - p3x) + (p3x - p2x)*(p1z - p3z); - final double a = ((p2z - p3z)*(targetX - p3x) + (p3x - p2x)*(targetZ - p3z)) / d; + final double d = (p2z - p3z) * (p1x - p3x) + (p3x - p2x) * (p1z - p3z); + final double a = ((p2z - p3z) * (targetX - p3x) + (p3x - p2x) * (targetZ - p3z)) / d; if (a < 0.0 || a > 1.0) { return false; } - final double b = ((p3z - p1z)*(targetX - p3x) + (p1x - p3x)*(targetZ - p3z)) / d; + final double b = ((p3z - p1z) * (targetX - p3x) + (p1x - p3x) * (targetZ - p3z)) / d; if (b < 0.0 || b > 1.0) { return false; } @@ -1040,14 +968,14 @@ public final class PlayerChunkLoader { && tickViewDistance == this.lastTickDistance && (this.usingLookingPriority ? ( - // has our block stayed the same (this also accounts for chunk change)? - Mth.floor(this.lastLocX) == Mth.floor(posX) + // has our block stayed the same (this also accounts for chunk change)? + Mth.floor(this.lastLocX) == Mth.floor(posX) && Mth.floor(this.lastLocZ) == Mth.floor(posZ) - ) : ( - // has our chunk stayed the same - (Mth.floor(this.lastLocX) >> 4) == (Mth.floor(posX) >> 4) + ) : ( + // has our chunk stayed the same + (Mth.floor(this.lastLocX) >> 4) == (Mth.floor(posX) >> 4) && (Mth.floor(this.lastLocZ) >> 4) == (Mth.floor(posZ) >> 4) - )) + )) // has our decision about look priority changed? && this.usingLookingPriority == useLookPriority @@ -1096,15 +1024,15 @@ public final class PlayerChunkLoader { final double p1z = posZ; // to the left of the looking direction - final double p2x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector + final double p2x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw + (double) (FOV / 2.0))) // calculate rotated vector + p1x; // offset vector - final double p2z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw + (double)(FOV / 2.0))) // calculate rotated vector + final double p2z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw + (double) (FOV / 2.0))) // calculate rotated vector + p1z; // offset vector // to the right of the looking direction - final double p3x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector + final double p3x = PRIORITISED_DISTANCE * Math.cos(Math.toRadians(yaw - (double) (FOV / 2.0))) // calculate rotated vector + p1x; // offset vector - final double p3z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw - (double)(FOV / 2.0))) // calculate rotated vector + final double p3z = PRIORITISED_DISTANCE * Math.sin(Math.toRadians(yaw - (double) (FOV / 2.0))) // calculate rotated vector + p1z; // offset vector // now that we have all of our points, we can recalculate the load queue @@ -1142,7 +1070,7 @@ public final class PlayerChunkLoader { p1x, p1z, p2x, p2z, p3x, p3z, // center of chunk - (double)((chunkX << 4) | 8), (double)((chunkZ << 4) | 8) + (double) ((chunkX << 4) | 8), (double) ((chunkZ << 4) | 8) ); final int manhattanDistance = Math.abs(dx) + Math.abs(dz); @@ -1157,9 +1085,9 @@ public final class PlayerChunkLoader { if (prioritised) { // we don't prioritise these chunks above others because we also want to make sure some chunks // will be loaded if the player changes direction - priority = (double)manhattanDistance / 6.0; + priority = (double) manhattanDistance / 6.0; } else { - priority = (double)manhattanDistance; + priority = (double) manhattanDistance; } } @@ -1186,23 +1114,13 @@ public final class PlayerChunkLoader { }); // we're modifying loadQueue, must remove - final long id3 = this.loader.loadLock.writeLock(); - try { - this.loader.chunkLoadQueue.remove(this); - }finally { - this.loader.loadLock.unlockWrite(id3); - } + this.loader.chunkLoadQueue.remove(this); this.loadQueue.clear(); this.loadQueue.addAll(loadQueue); - final long id4 = this.loader.loadLock.writeLock(); - try { - // must re-add - this.loader.chunkLoadQueue.add(this); - }finally { - this.loader.loadLock.unlockWrite(id4); - } + // must re-add + this.loader.chunkLoadQueue.add(this); // update the chunk center // this must be done last so that the client does not ignore any of our unload chunk packets diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java index 36d3b0d0e1e716cb0e5a2e98c37a834776e26c20..26e1b4060f2a93cb659170f83e6ce64086e0eb0c 100644 --- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java @@ -6,8 +6,14 @@ import io.papermc.paper.util.CoordinateUtils; import io.papermc.paper.util.TickThread; import io.papermc.paper.util.WorldUtil; import io.papermc.paper.world.ChunkEntitySlices; +import it.unimi.dsi.fastutil.ints.Int2ReferenceMap; +import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps; import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMaps; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; +import it.unimi.dsi.fastutil.objects.Object2ReferenceMaps; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import net.minecraft.core.BlockPos; import io.papermc.paper.chunk.system.ChunkSystem; @@ -49,17 +55,16 @@ public final class EntityLookup implements LevelEntityGetter { private final StampedLock entityByLock = new StampedLock(); private final StampedLock stateLock = new StampedLock(); + //Hearse -- Just for multithreaded entity ticking - private final ReadWriteLock paraEntityLock = new ReentrantReadWriteLock(false); //Hearse -- Just for multithreaded entity ticking - - protected final Long2ObjectOpenHashMap regions = new Long2ObjectOpenHashMap<>(128, 0.5f); + protected final Long2ObjectMap regions = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>(128, 0.5f)); private final int minSection; // inclusive private final int maxSection; // inclusive private final LevelCallback worldCallback; - private final Int2ReferenceOpenHashMap entityById = new Int2ReferenceOpenHashMap<>(); - private final Object2ReferenceOpenHashMap entityByUUID = new Object2ReferenceOpenHashMap<>(); + private final Int2ReferenceMap entityById = Int2ReferenceMaps.synchronize(new Int2ReferenceOpenHashMap<>()); + private final Object2ReferenceMap entityByUUID = Object2ReferenceMaps.synchronize(new Object2ReferenceOpenHashMap<>()); private final EntityList accessibleEntities = new EntityList(); public EntityLookup(final ServerLevel world, final LevelCallback worldCallback) { @@ -80,61 +85,51 @@ public final class EntityLookup implements LevelEntityGetter { @Nullable @Override public Entity get(final int id) { - this.paraEntityLock.readLock().lock();//Hearse - try { - final long attempt = this.entityByLock.tryOptimisticRead(); - if (attempt != 0L) { - try { - final Entity ret = this.entityById.get(id); + final long attempt = this.entityByLock.tryOptimisticRead(); + if (attempt != 0L) { + try { + final Entity ret = this.entityById.get(id); - if (this.entityByLock.validate(attempt)) { - return maskNonAccessible(ret); - } - } catch (final Error error) { - throw error; - } catch (final Throwable thr) { - // ignore + if (this.entityByLock.validate(attempt)) { + return maskNonAccessible(ret); } + } catch (final Error error) { + throw error; + } catch (final Throwable thr) { + // ignore } + } - this.entityByLock.readLock(); - try { - return maskNonAccessible(this.entityById.get(id)); - } finally { - this.entityByLock.tryUnlockRead(); - } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse + this.entityByLock.readLock(); + try { + return maskNonAccessible(this.entityById.get(id)); + } finally { + this.entityByLock.tryUnlockRead(); } } @Nullable @Override public Entity get(final UUID id) { - this.paraEntityLock.readLock().lock();//Hearse - try { - final long attempt = this.entityByLock.tryOptimisticRead(); - if (attempt != 0L) { - try { - final Entity ret = this.entityByUUID.get(id); - if (this.entityByLock.validate(attempt)) { - return maskNonAccessible(ret); - } - } catch (final Error error) { - throw error; - } catch (final Throwable thr) { - // ignore + final long attempt = this.entityByLock.tryOptimisticRead(); + if (attempt != 0L) { + try { + final Entity ret = this.entityByUUID.get(id); + if (this.entityByLock.validate(attempt)) { + return maskNonAccessible(ret); } + } catch (final Error error) { + throw error; + } catch (final Throwable thr) { + // ignore } + } - this.entityByLock.readLock(); - try { - return maskNonAccessible(this.entityByUUID.get(id)); - } finally { - this.entityByLock.tryUnlockRead(); - } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse + this.entityByLock.readLock(); + try { + return maskNonAccessible(this.entityByUUID.get(id)); + } finally { + this.entityByLock.tryUnlockRead(); } } @@ -143,12 +138,7 @@ public final class EntityLookup implements LevelEntityGetter { } public String getDebugInfo() { - this.paraEntityLock.readLock();//Hearse - try { - return "count_id:" + this.entityById.size() + ",count_uuid:" + this.entityByUUID.size() + ",region_count:" + this.regions.size(); - }finally { - this.paraEntityLock.readLock().unlock();//Hearse - } + return "count_id:" + this.entityById.size() + ",count_uuid:" + this.entityByUUID.size() + ",region_count:" + this.regions.size(); } static final class ArrayIterable implements Iterable { @@ -206,30 +196,20 @@ public final class EntityLookup implements LevelEntityGetter { @Override public Iterable getAll() { - this.paraEntityLock.readLock().lock();//Hearse - try { - return new ArrayIterable<>(this.accessibleEntities.getRawData(), 0, this.accessibleEntities.size()); - }finally { - this.paraEntityLock.readLock().unlock();//Hearse - } + return new ArrayIterable<>(this.accessibleEntities.getRawData(), 0, this.accessibleEntities.size()); } @Override public void get(final EntityTypeTest filter, final AbortableIterationConsumer action) { - this.paraEntityLock.readLock().lock();//Hearse - try { - for (final Entity entity : this.entityById.values()) { - final Visibility visibility = EntityLookup.getEntityStatus(entity); - if (!visibility.isAccessible()) { - continue; - } - final U casted = filter.tryCast(entity); - if (casted != null && action.accept(casted).shouldAbort()) { - break; - } + for (final Entity entity : this.entityById.values()) { + final Visibility visibility = EntityLookup.getEntityStatus(entity); + if (!visibility.isAccessible()) { + continue; + } + final U casted = filter.tryCast(entity); + if (casted != null && action.accept(casted).shouldAbort()) { + break; } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -257,55 +237,50 @@ public final class EntityLookup implements LevelEntityGetter { public void entityStatusChange(final Entity entity, final ChunkEntitySlices slices, final Visibility oldVisibility, final Visibility newVisibility, final boolean moved, final boolean created, final boolean destroyed) { TickThread.ensureTickThread(entity, "Entity status change must only happen on the main thread"); - this.paraEntityLock.writeLock().lock();//Hearse + final Boolean ticketBlockBefore = this.world.chunkTaskScheduler.chunkHolderManager.blockTicketUpdates(); try { - final Boolean ticketBlockBefore = this.world.chunkTaskScheduler.chunkHolderManager.blockTicketUpdates(); - try { - if (created) { - EntityLookup.this.worldCallback.onCreated(entity); - } + if (created) { + EntityLookup.this.worldCallback.onCreated(entity); + } - if (oldVisibility == newVisibility) { - if (moved && newVisibility.isAccessible()) { - EntityLookup.this.worldCallback.onSectionChange(entity); - } - return; + if (oldVisibility == newVisibility) { + if (moved && newVisibility.isAccessible()) { + EntityLookup.this.worldCallback.onSectionChange(entity); } + return; + } - if (newVisibility.ordinal() > oldVisibility.ordinal()) { - // status upgrade - if (!oldVisibility.isAccessible() && newVisibility.isAccessible()) { - this.accessibleEntities.add(entity); - EntityLookup.this.worldCallback.onTrackingStart(entity); - } - - if (!oldVisibility.isTicking() && newVisibility.isTicking()) { - EntityLookup.this.worldCallback.onTickingStart(entity); - } - } else { - // status downgrade - if (oldVisibility.isTicking() && !newVisibility.isTicking()) { - EntityLookup.this.worldCallback.onTickingEnd(entity); - } - - if (oldVisibility.isAccessible() && !newVisibility.isAccessible()) { - this.accessibleEntities.remove(entity); - EntityLookup.this.worldCallback.onTrackingEnd(entity); - } + if (newVisibility.ordinal() > oldVisibility.ordinal()) { + // status upgrade + if (!oldVisibility.isAccessible() && newVisibility.isAccessible()) { + this.accessibleEntities.add(entity); + EntityLookup.this.worldCallback.onTrackingStart(entity); } - if (moved && newVisibility.isAccessible()) { - EntityLookup.this.worldCallback.onSectionChange(entity); + if (!oldVisibility.isTicking() && newVisibility.isTicking()) { + EntityLookup.this.worldCallback.onTickingStart(entity); + } + } else { + // status downgrade + if (oldVisibility.isTicking() && !newVisibility.isTicking()) { + EntityLookup.this.worldCallback.onTickingEnd(entity); } - if (destroyed) { - EntityLookup.this.worldCallback.onDestroyed(entity); + if (oldVisibility.isAccessible() && !newVisibility.isAccessible()) { + this.accessibleEntities.remove(entity); + EntityLookup.this.worldCallback.onTrackingEnd(entity); } - } finally { - this.world.chunkTaskScheduler.chunkHolderManager.unblockTicketUpdates(ticketBlockBefore); + } + + if (moved && newVisibility.isAccessible()) { + EntityLookup.this.worldCallback.onSectionChange(entity); + } + + if (destroyed) { + EntityLookup.this.worldCallback.onDestroyed(entity); } } finally { - this.paraEntityLock.writeLock().lock();//Hearse + this.world.chunkTaskScheduler.chunkHolderManager.unblockTicketUpdates(ticketBlockBefore); } } @@ -350,53 +325,48 @@ public final class EntityLookup implements LevelEntityGetter { final int sectionZ = pos.getZ() >> 4; TickThread.ensureTickThread(this.world, sectionX, sectionZ, "Cannot add entity off-main thread"); - this.paraEntityLock.writeLock().lock();//Hearse - try { + if (entity.isRemoved()) { + LOGGER.warn("Refusing to add removed entity: " + entity); + return false; + } + + if (fromDisk) { + ChunkSystem.onEntityPreAdd(this.world, entity); if (entity.isRemoved()) { - LOGGER.warn("Refusing to add removed entity: " + entity); + // removed from checkDupeUUID call return false; } + } - if (fromDisk) { - ChunkSystem.onEntityPreAdd(this.world, entity); - if (entity.isRemoved()) { - // removed from checkDupeUUID call - return false; - } + this.entityByLock.writeLock(); + try { + if (this.entityById.containsKey(entity.getId())) { + LOGGER.warn("Entity id already exists: " + entity.getId() + ", mapped to " + this.entityById.get(entity.getId()) + ", can't add " + entity); + return false; } - - this.entityByLock.writeLock(); - try { - if (this.entityById.containsKey(entity.getId())) { - LOGGER.warn("Entity id already exists: " + entity.getId() + ", mapped to " + this.entityById.get(entity.getId()) + ", can't add " + entity); - return false; - } - if (this.entityByUUID.containsKey(entity.getUUID())) { - LOGGER.warn("Entity uuid already exists: " + entity.getUUID() + ", mapped to " + this.entityByUUID.get(entity.getUUID()) + ", can't add " + entity); - return false; - } - this.entityById.put(entity.getId(), entity); - this.entityByUUID.put(entity.getUUID(), entity); - } finally { - this.entityByLock.tryUnlockWrite(); + if (this.entityByUUID.containsKey(entity.getUUID())) { + LOGGER.warn("Entity uuid already exists: " + entity.getUUID() + ", mapped to " + this.entityByUUID.get(entity.getUUID()) + ", can't add " + entity); + return false; } + this.entityById.put(entity.getId(), entity); + this.entityByUUID.put(entity.getUUID(), entity); + } finally { + this.entityByLock.tryUnlockWrite(); + } - entity.sectionX = sectionX; - entity.sectionY = sectionY; - entity.sectionZ = sectionZ; - final ChunkEntitySlices slices = this.getOrCreateChunk(sectionX, sectionZ); - if (!slices.addEntity(entity, sectionY)) { - LOGGER.warn("Entity " + entity + " added to world '" + this.world.getWorld().getName() + "', but was already contained in entity chunk (" + sectionX + "," + sectionZ + ")"); - } + entity.sectionX = sectionX; + entity.sectionY = sectionY; + entity.sectionZ = sectionZ; + final ChunkEntitySlices slices = this.getOrCreateChunk(sectionX, sectionZ); + if (!slices.addEntity(entity, sectionY)) { + LOGGER.warn("Entity " + entity + " added to world '" + this.world.getWorld().getName() + "', but was already contained in entity chunk (" + sectionX + "," + sectionZ + ")"); + } - entity.setLevelCallback(new EntityCallback(entity)); + entity.setLevelCallback(new EntityCallback(entity)); - this.entityStatusChange(entity, slices, Visibility.HIDDEN, getEntityStatus(entity), false, !fromDisk, false); + this.entityStatusChange(entity, slices, Visibility.HIDDEN, getEntityStatus(entity), false, !fromDisk, false); - return true; - }finally { - this.paraEntityLock.writeLock().unlock();//Hearse - } + return true; } private void removeEntity(final Entity entity) { @@ -407,32 +377,27 @@ public final class EntityLookup implements LevelEntityGetter { if (!entity.isRemoved()) { throw new IllegalStateException("Only call Entity#setRemoved to remove an entity"); } - this.paraEntityLock.writeLock().lock();//Hearse - try { - final ChunkEntitySlices slices = this.getChunk(sectionX, sectionZ); - // all entities should be in a chunk - if (slices == null) { - LOGGER.warn("Cannot remove entity " + entity + " from null entity slices (" + sectionX + "," + sectionZ + ")"); - } else { - if (!slices.removeEntity(entity, sectionY)) { - LOGGER.warn("Failed to remove entity " + entity + " from entity slices (" + sectionX + "," + sectionZ + ")"); - } + final ChunkEntitySlices slices = this.getChunk(sectionX, sectionZ); + // all entities should be in a chunk + if (slices == null) { + LOGGER.warn("Cannot remove entity " + entity + " from null entity slices (" + sectionX + "," + sectionZ + ")"); + } else { + if (!slices.removeEntity(entity, sectionY)) { + LOGGER.warn("Failed to remove entity " + entity + " from entity slices (" + sectionX + "," + sectionZ + ")"); } - entity.sectionX = entity.sectionY = entity.sectionZ = Integer.MIN_VALUE; + } + entity.sectionX = entity.sectionY = entity.sectionZ = Integer.MIN_VALUE; - this.entityByLock.writeLock(); - try { - if (!this.entityById.remove(entity.getId(), entity)) { - LOGGER.warn("Failed to remove entity " + entity + " by id, current entity mapped: " + this.entityById.get(entity.getId())); - } - if (!this.entityByUUID.remove(entity.getUUID(), entity)) { - LOGGER.warn("Failed to remove entity " + entity + " by uuid, current entity mapped: " + this.entityByUUID.get(entity.getUUID())); - } - } finally { - this.entityByLock.tryUnlockWrite(); + this.entityByLock.writeLock(); + try { + if (!this.entityById.remove(entity.getId(), entity)) { + LOGGER.warn("Failed to remove entity " + entity + " by id, current entity mapped: " + this.entityById.get(entity.getId())); + } + if (!this.entityByUUID.remove(entity.getUUID(), entity)) { + LOGGER.warn("Failed to remove entity " + entity + " by uuid, current entity mapped: " + this.entityByUUID.get(entity.getUUID())); } - }finally { - this.paraEntityLock.writeLock().unlock();//Hearse + } finally { + this.entityByLock.tryUnlockWrite(); } } @@ -455,27 +420,22 @@ public final class EntityLookup implements LevelEntityGetter { // ensure the old section is owned by this tick thread TickThread.ensureTickThread(this.world, entity.sectionX, entity.sectionZ, "Cannot move entity off-main"); - this.paraEntityLock.writeLock().lock();//Hearse - try { - final ChunkEntitySlices old = this.getChunk(entity.sectionX, entity.sectionZ); - final ChunkEntitySlices slices = this.getOrCreateChunk(newSectionX, newSectionZ); + final ChunkEntitySlices old = this.getChunk(entity.sectionX, entity.sectionZ); + final ChunkEntitySlices slices = this.getOrCreateChunk(newSectionX, newSectionZ); - if (!old.removeEntity(entity, entity.sectionY)) { - LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section"); - } + if (!old.removeEntity(entity, entity.sectionY)) { + LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section"); + } - if (!slices.addEntity(entity, newSectionY)) { - LOGGER.warn("Could not add entity " + entity + " to its new chunk section (" + newSectionX + "," + newSectionY + "," + newSectionZ + ") as it is already contained in the section"); - } + if (!slices.addEntity(entity, newSectionY)) { + LOGGER.warn("Could not add entity " + entity + " to its new chunk section (" + newSectionX + "," + newSectionY + "," + newSectionZ + ") as it is already contained in the section"); + } - entity.sectionX = newSectionX; - entity.sectionY = newSectionY; - entity.sectionZ = newSectionZ; + entity.sectionX = newSectionX; + entity.sectionY = newSectionY; + entity.sectionZ = newSectionZ; - return slices; - }finally { - this.paraEntityLock.writeLock().unlock();//Hearse - } + return slices; } public void getEntitiesWithoutDragonParts(final Entity except, final AABB box, final List into, final Predicate predicate) { @@ -489,36 +449,31 @@ public final class EntityLookup implements LevelEntityGetter { final int maxRegionX = maxChunkX >> REGION_SHIFT; final int maxRegionZ = maxChunkZ >> REGION_SHIFT; - this.paraEntityLock.readLock().lock();//Hearse - try { - for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { - final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; - final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; + for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { + final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; + final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { - final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); + for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { + final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); - if (region == null) { - continue; - } - - final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; - final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; + if (region == null) { + continue; + } - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - for (int currX = minX; currX <= maxX; ++currX) { - final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); - if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { - continue; - } + final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; + final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; - chunk.getEntitiesWithoutDragonParts(except, box, into, predicate); + for (int currZ = minZ; currZ <= maxZ; ++currZ) { + for (int currX = minX; currX <= maxX; ++currX) { + final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); + if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { + continue; } + + chunk.getEntitiesWithoutDragonParts(except, box, into, predicate); } } } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -533,36 +488,31 @@ public final class EntityLookup implements LevelEntityGetter { final int maxRegionX = maxChunkX >> REGION_SHIFT; final int maxRegionZ = maxChunkZ >> REGION_SHIFT; - this.paraEntityLock.readLock().lock();//Hearse - try { - for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { - final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; - final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - - for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { - final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); + for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { + final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; + final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - if (region == null) { - continue; - } + for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { + final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); - final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; - final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; + if (region == null) { + continue; + } - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - for (int currX = minX; currX <= maxX; ++currX) { - final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); - if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { - continue; - } + final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; + final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; - chunk.getEntities(except, box, into, predicate); + for (int currZ = minZ; currZ <= maxZ; ++currZ) { + for (int currX = minX; currX <= maxX; ++currX) { + final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); + if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { + continue; } + + chunk.getEntities(except, box, into, predicate); } } } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -577,36 +527,31 @@ public final class EntityLookup implements LevelEntityGetter { final int maxRegionX = maxChunkX >> REGION_SHIFT; final int maxRegionZ = maxChunkZ >> REGION_SHIFT; - this.paraEntityLock.readLock().lock();//Hearse - try { - for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { - final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; - final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - - for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { - final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); + for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { + final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; + final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - if (region == null) { - continue; - } + for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { + final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); - final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; - final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; + if (region == null) { + continue; + } - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - for (int currX = minX; currX <= maxX; ++currX) { - final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); - if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { - continue; - } + final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; + final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; - chunk.getHardCollidingEntities(except, box, into, predicate); + for (int currZ = minZ; currZ <= maxZ; ++currZ) { + for (int currX = minX; currX <= maxX; ++currX) { + final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); + if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { + continue; } + + chunk.getHardCollidingEntities(except, box, into, predicate); } } } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -622,36 +567,31 @@ public final class EntityLookup implements LevelEntityGetter { final int maxRegionX = maxChunkX >> REGION_SHIFT; final int maxRegionZ = maxChunkZ >> REGION_SHIFT; - this.paraEntityLock.readLock().lock();//Hearse - try { - for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { - final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; - final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - - for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { - final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); + for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { + final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; + final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - if (region == null) { - continue; - } + for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { + final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); - final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; - final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; + if (region == null) { + continue; + } - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - for (int currX = minX; currX <= maxX; ++currX) { - final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); - if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { - continue; - } + final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; + final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; - chunk.getEntities(type, box, (List)into, (Predicate)predicate); + for (int currZ = minZ; currZ <= maxZ; ++currZ) { + for (int currX = minX; currX <= maxX; ++currX) { + final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); + if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { + continue; } + + chunk.getEntities(type, box, (List) into, (Predicate) predicate); } } } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -667,36 +607,31 @@ public final class EntityLookup implements LevelEntityGetter { final int maxRegionX = maxChunkX >> REGION_SHIFT; final int maxRegionZ = maxChunkZ >> REGION_SHIFT; - this.paraEntityLock.readLock().unlock();//Hearse - try { - for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { - final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; - final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - - for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { - final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); + for (int currRegionZ = minRegionZ; currRegionZ <= maxRegionZ; ++currRegionZ) { + final int minZ = currRegionZ == minRegionZ ? minChunkZ & REGION_MASK : 0; + final int maxZ = currRegionZ == maxRegionZ ? maxChunkZ & REGION_MASK : REGION_MASK; - if (region == null) { - continue; - } + for (int currRegionX = minRegionX; currRegionX <= maxRegionX; ++currRegionX) { + final ChunkSlicesRegion region = this.getRegion(currRegionX, currRegionZ); - final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; - final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; + if (region == null) { + continue; + } - for (int currZ = minZ; currZ <= maxZ; ++currZ) { - for (int currX = minX; currX <= maxX; ++currX) { - final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); - if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { - continue; - } + final int minX = currRegionX == minRegionX ? minChunkX & REGION_MASK : 0; + final int maxX = currRegionX == maxRegionX ? maxChunkX & REGION_MASK : REGION_MASK; - chunk.getEntities(clazz, except, box, into, predicate); + for (int currZ = minZ; currZ <= maxZ; ++currZ) { + for (int currX = minX; currX <= maxX; ++currX) { + final ChunkEntitySlices chunk = region.get(currX | (currZ << REGION_SHIFT)); + if (chunk == null || !chunk.status.isOrAfter(ChunkHolder.FullChunkStatus.BORDER)) { + continue; } + + chunk.getEntities(clazz, except, box, into, predicate); } } } - }finally { - this.paraEntityLock.readLock().unlock();//Hearse } } @@ -875,9 +810,11 @@ public final class EntityLookup implements LevelEntityGetter { public static final NoOpCallback INSTANCE = new NoOpCallback(); @Override - public void onMove() {} + public void onMove() { + } @Override - public void onRemove(final Entity.RemovalReason reason) {} + public void onRemove(final Entity.RemovalReason reason) { + } } } diff --git a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java index 0fd814f1d65c111266a2b20f86561839a4cef755..fe4d76875462ac9d408c972b968647af78f2ed14 100644 --- a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java +++ b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java @@ -94,7 +94,7 @@ public final class IteratorSafeOrderedReferenceSet { return 1.0 - ((double)this.indexMap.size() / (double)this.listSize); } - public int createRawIterator() { + public synchronized int createRawIterator() { if (this.allowSafeIteration()) { ++this.iteratorCount; } @@ -105,7 +105,7 @@ public final class IteratorSafeOrderedReferenceSet { } } - public int advanceRawIterator(final int index) { + public synchronized int advanceRawIterator(final int index) { final E[] elements = this.listElements; int ret = index + 1; for (int len = this.listSize; ret < len; ++ret) { @@ -117,7 +117,7 @@ public final class IteratorSafeOrderedReferenceSet { return -1; } - public void finishRawIterator() { + public synchronized void finishRawIterator() { if (this.allowSafeIteration() && --this.iteratorCount == 0) { if (this.getFragFactor() >= this.maxFragFactor) { this.defrag(); @@ -125,7 +125,7 @@ public final class IteratorSafeOrderedReferenceSet { } } - public boolean remove(final E element) { + public synchronized boolean remove(final E element) { final int index = this.indexMap.removeInt(element); if (index >= 0) { if (this.firstInvalidIndex < 0 || index < this.firstInvalidIndex) { @@ -144,11 +144,11 @@ public final class IteratorSafeOrderedReferenceSet { return false; } - public boolean contains(final E element) { + public synchronized boolean contains(final E element) { return this.indexMap.containsKey(element); } - public boolean add(final E element) { + public synchronized boolean add(final E element) { final int listSize = this.listSize; final int previous = this.indexMap.putIfAbsent(element, listSize); @@ -223,30 +223,30 @@ public final class IteratorSafeOrderedReferenceSet { //this.check(); } - public E rawGet(final int index) { + public synchronized E rawGet(final int index) { return this.listElements[index]; } - public int size() { + public synchronized int size() { // always returns the correct amount - listSize can be different return this.indexMap.size(); } - public IteratorSafeOrderedReferenceSet.Iterator iterator() { + public synchronized IteratorSafeOrderedReferenceSet.Iterator iterator() { return this.iterator(0); } - public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { + public synchronized IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { if (this.allowSafeIteration()) { ++this.iteratorCount; } return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); } - public java.util.Iterator unsafeIterator() { + public synchronized java.util.Iterator unsafeIterator() { return this.unsafeIterator(0); } - public java.util.Iterator unsafeIterator(final int flags) { + public synchronized java.util.Iterator unsafeIterator(final int flags) { return new BaseIterator<>(this, false, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); } @@ -273,7 +273,7 @@ public final class IteratorSafeOrderedReferenceSet { } @Override - public boolean hasNext() { + public synchronized boolean hasNext() { if (this.finished) { return false; } @@ -297,7 +297,7 @@ public final class IteratorSafeOrderedReferenceSet { } @Override - public E next() { + public synchronized E next() { if (!this.hasNext()) { throw new NoSuchElementException(); } @@ -310,7 +310,7 @@ public final class IteratorSafeOrderedReferenceSet { } @Override - public void remove() { + public synchronized void remove() { final E lastReturned = this.lastReturned; if (lastReturned == null) { throw new IllegalStateException(); @@ -320,7 +320,7 @@ public final class IteratorSafeOrderedReferenceSet { } @Override - public void finishedIterating() { + public synchronized void finishedIterating() { if (this.finished || !this.canFinish) { throw new IllegalStateException(); } diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java index f6c8dccb7f7cd287f1ebdf46481365b952baa891..ae22ca9ea5fd3d78d8c5bf9f1ab96f1129fddc11 100644 --- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java +++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java @@ -4,6 +4,7 @@ import com.destroystokyo.paper.util.maplist.EntityList; import io.papermc.paper.chunk.system.entity.EntityLookup; import io.papermc.paper.util.TickThread; import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectMaps; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ChunkHolder; @@ -35,7 +36,7 @@ public final class ChunkEntitySlices { protected final EntityCollectionBySection allEntities; protected final EntityCollectionBySection hardCollidingEntities; - protected final Reference2ObjectOpenHashMap, EntityCollectionBySection> entitiesByClass; + protected final Reference2ObjectMap, EntityCollectionBySection> entitiesByClass; protected final EntityList entities = new EntityList(); public ChunkHolder.FullChunkStatus status; @@ -62,7 +63,7 @@ public final class ChunkEntitySlices { this.allEntities = new EntityCollectionBySection(this); this.hardCollidingEntities = new EntityCollectionBySection(this); - this.entitiesByClass = new Reference2ObjectOpenHashMap<>(); + this.entitiesByClass = Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>()); this.status = status; } @@ -199,7 +200,7 @@ public final class ChunkEntitySlices { } for (final Iterator, EntityCollectionBySection>> iterator = - this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { + this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) { final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); if (entry.getKey().isInstance(entity)) { @@ -224,7 +225,7 @@ public final class ChunkEntitySlices { } for (final Iterator, EntityCollectionBySection>> iterator = - this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) { + this.entitiesByClass.reference2ObjectEntrySet().iterator(); iterator.hasNext();) { final Reference2ObjectMap.Entry, EntityCollectionBySection> entry = iterator.next(); if (entry.getKey().isInstance(entity)) { @@ -302,11 +303,11 @@ public final class ChunkEntitySlices { this.storage = (E[])(cap <= 0 ? EMPTY : new Entity[cap]); } - public boolean isEmpty() { + public synchronized boolean isEmpty() { return this.size == 0; } - public int size() { + public synchronized int size() { return this.size; } @@ -318,7 +319,7 @@ public final class ChunkEntitySlices { } } - public void add(final E entity) { + public synchronized void add(final E entity) { final int idx = this.size++; if (idx >= this.storage.length) { this.resize(); @@ -328,7 +329,7 @@ public final class ChunkEntitySlices { } } - public int indexOf(final E entity) { + public synchronized int indexOf(final E entity) { final E[] storage = this.storage; for (int i = 0, len = Math.min(this.storage.length, this.size); i < len; ++i) { @@ -340,7 +341,7 @@ public final class ChunkEntitySlices { return -1; } - public boolean remove(final E entity) { + public synchronized boolean remove(final E entity) { final int idx = this.indexOf(entity); if (idx == -1) { return false; @@ -357,7 +358,7 @@ public final class ChunkEntitySlices { return true; } - public boolean has(final E entity) { + public synchronized boolean has(final E entity) { return this.indexOf(entity) != -1; } } diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java index 10c7d776ca0d959541d3110c75ceb45a340278ac..a23379120ddc3653b58bdb08f9c837c60b6b83ca 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1,10 +1,7 @@ package net.minecraft.server.level; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.*; import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; -import com.google.common.collect.Queues; import com.google.gson.JsonElement; import com.mojang.datafixers.DataFixer; import com.mojang.datafixers.util.Either; @@ -103,7 +100,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public final StructureTemplateManager structureTemplateManager; // Paper - rewrite chunk system private final String storageName; private final PlayerMap playerMap; - public final Int2ObjectMap entityMap; + public final Map entityMap; private final Long2ByteMap chunkTypeCache; private final Long2LongMap chunkSaveCooldowns; private final Queue unloadQueue; @@ -251,7 +248,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper - rewrite chunk system this.tickingGenerated = new AtomicInteger(); this.playerMap = new PlayerMap(); - this.entityMap = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap()); + this.entityMap = Maps.newConcurrentMap(); this.chunkTypeCache = Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); this.chunkSaveCooldowns = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); this.unloadQueue = Queues.newConcurrentLinkedQueue(); @@ -1165,11 +1162,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ServerPlayer entityplayer = (ServerPlayer) entity; this.updatePlayerStatus(entityplayer, true); - ObjectIterator objectiterator = this.entityMap.values().iterator(); - - while (objectiterator.hasNext()) { - ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) objectiterator.next(); + for (TrackedEntity playerchunkmap_entitytracker1 : this.entityMap.values()) { if (playerchunkmap_entitytracker1.entity != entityplayer) { playerchunkmap_entitytracker1.updatePlayer(entityplayer); } @@ -1187,11 +1181,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider ServerPlayer entityplayer = (ServerPlayer) entity; this.updatePlayerStatus(entityplayer, false); - ObjectIterator objectiterator = this.entityMap.values().iterator(); - - while (objectiterator.hasNext()) { - ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); + for (TrackedEntity playerchunkmap_entitytracker : this.entityMap.values()) { playerchunkmap_entitytracker.removePlayer(entityplayer); } } @@ -1237,7 +1228,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end - optimized tracker List list = Lists.newArrayList(); List list1 = this.level.players(); - ObjectIterator objectiterator = this.entityMap.values().iterator(); + Iterator objectiterator = this.entityMap.values().iterator(); //level.timings.tracker1.startTiming(); // Paper // Purpur ChunkMap.TrackedEntity playerchunkmap_entitytracker; diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java index 0c70810edace99bb5037d927388e055a514fcbde..0eadacb873658a0c7bd9ab24f191bc75eaebcaca 100644 --- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java +++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java @@ -3,9 +3,12 @@ package net.minecraft.util.thread; import com.google.common.collect.ImmutableList; import com.google.common.collect.Queues; import com.mojang.logging.LogUtils; + +import java.util.Deque; import java.util.List; import java.util.Queue; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.Executor; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.StampedLock; @@ -20,7 +23,7 @@ import org.slf4j.Logger; public abstract class BlockableEventLoop implements ProfilerMeasured, ProcessorHandle, Executor { private final String name; private static final Logger LOGGER = LogUtils.getLogger(); - private final Queue pendingRunnables = Queues.newConcurrentLinkedQueue(); + private final Deque pendingRunnables = new ConcurrentLinkedDeque<>(); private final StampedLock lock = new StampedLock(); private int blockingCount; @@ -44,12 +47,7 @@ public abstract class BlockableEventLoop implements Profiler } public int getPendingTasksCount() { - final long id = this.lock.readLock(); - try{ - return this.pendingRunnables.size(); - }finally { - this.lock.unlockRead(id); - } + return this.pendingRunnables.size(); } @Override @@ -95,12 +93,7 @@ public abstract class BlockableEventLoop implements Profiler @Override public void tell(R runnable) { - final long id = this.lock.writeLock(); - try { - this.pendingRunnables.add(runnable); - }finally { - this.lock.unlockWrite(id); - } + this.pendingRunnables.add(runnable); LockSupport.unpark(this.getRunningThread()); } @@ -119,12 +112,7 @@ public abstract class BlockableEventLoop implements Profiler } protected void dropAllTasks() { - final long id = this.lock.writeLock(); - try { - this.pendingRunnables.clear(); - }finally { - this.lock.unlockWrite(id); - } + this.pendingRunnables.clear(); } protected void runAllTasks() { @@ -134,19 +122,15 @@ public abstract class BlockableEventLoop implements Profiler } public boolean pollTask() { - final long id = this.lock.writeLock(); - try { - R runnable = this.pendingRunnables.peek(); - if (runnable == null) { - return false; - } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) { - return false; - } else { - this.doRunTask(this.pendingRunnables.remove()); - return true; - } - }finally { - this.lock.unlockWrite(id); + R runnable = this.pendingRunnables.poll(); + if (runnable == null) { + return false; + } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) { + this.pendingRunnables.addFirst(runnable); + return false; + } else { + this.doRunTask(runnable); + return true; } } diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java index 00f7b58db5948f4d7c7f07736d8fcf1972009c77..dca7c7f83043452b5fef3c1d24a99f08dfaf242a 100644 --- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java +++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java @@ -1,14 +1,15 @@ package net.minecraft.world.level.entity; -import java.util.Iterator; -import java.util.Set; +import java.util.*; import java.util.function.Consumer; + +import com.google.common.collect.Lists; import it.unimi.dsi.fastutil.objects.ObjectArraySet; import it.unimi.dsi.fastutil.objects.ObjectSets; import net.minecraft.world.entity.Entity; public class EntityTickList { - public final Set entities = ObjectSets.synchronize(new ObjectArraySet<>()); + public final List entities = Lists.newCopyOnWriteArrayList(); public void add(Entity entity) { io.papermc.paper.util.TickThread.ensureTickThread("Asynchronous entity ticklist addition"); // Paper diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java index a097e00bd62f53630568f68854d3a34300012277..799cd9d04d156ed87e9b1dfde75ae15280c9eb0d 100644 --- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java @@ -22,8 +22,6 @@ public class CollectingNeighborUpdater implements NeighborUpdater { private final List addedThisLayer = new CopyOnWriteArrayList<>(); private int count = 0; - private final StampedLock lock = new StampedLock(); - public CollectingNeighborUpdater(Level world, int maxChainDepth) { this.level = world; this.maxChainedNeighborUpdates = maxChainDepth; @@ -49,23 +47,18 @@ public class CollectingNeighborUpdater implements NeighborUpdater { this.addAndRun(pos, new CollectingNeighborUpdater.MultiNeighborUpdate(pos.immutable(), sourceBlock, except)); } - private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates entry) { + private synchronized void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates entry) { boolean bl = this.count > 0; boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; ++this.count; - final long lockId = this.lock.writeLock(); - try { - if (!bl2) { - if (bl) { - this.addedThisLayer.add(entry); - } else { - this.stack.push(entry); - } - } else if (this.count - 1 == this.maxChainedNeighborUpdates) { - LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString()); + if (!bl2) { + if (bl) { + this.addedThisLayer.add(entry); + } else { + this.stack.push(entry); } - }finally { - this.lock.unlockWrite(lockId); + } else if (this.count - 1 == this.maxChainedNeighborUpdates) { + LOGGER.error("Too many chained neighbor updates. Skipping the rest. First skipped position: " + pos.toShortString()); } if (!bl) { @@ -75,30 +68,25 @@ public class CollectingNeighborUpdater implements NeighborUpdater { } private void runUpdates() { - final long lockid = this.lock.writeLock(); try { - try { - while(!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) { - for(int i = this.addedThisLayer.size() - 1; i >= 0; --i) { - this.stack.push(this.addedThisLayer.get(i)); - } - this.addedThisLayer.clear(); - CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek(); - - while(this.addedThisLayer.isEmpty()) { - if (!neighborUpdates.runNext(this.level)) { - this.stack.pop(); - break; - } - } + while (!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) { + for (int i = this.addedThisLayer.size() - 1; i >= 0; --i) { + this.stack.push(this.addedThisLayer.get(i)); } - } finally { - this.stack.clear(); this.addedThisLayer.clear(); - this.count = 0; + CollectingNeighborUpdater.NeighborUpdates neighborUpdates = this.stack.peek(); + + while (this.addedThisLayer.isEmpty()) { + if (!neighborUpdates.runNext(this.level)) { + this.stack.pop(); + break; + } + } } - }finally { - this.lock.unlockWrite(lockid); + } finally { + this.stack.clear(); + this.addedThisLayer.clear(); + this.count = 0; } }