mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-24 17:39:15 +00:00
Updated Upstream (Hearse)
This commit is contained in:
@@ -7,27 +7,6 @@ Subject: [PATCH] Hearse: Move player ticking to main thread and add lock in
|
||||
Original license: MIT
|
||||
Original project: https://github.com/NaturalCodeClub/HearseRewrite
|
||||
|
||||
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
index 9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5..86f8afd54c0cbb449403c3f43e6880ade13cfecc 100644
|
||||
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
@@ -8,6 +8,7 @@ import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
+import net.minecraft.world.entity.player.Player;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -87,7 +88,7 @@ public class ServerEntityTickHook {
|
||||
}
|
||||
}
|
||||
};
|
||||
- if (!asyncEntityEnabled){
|
||||
+ if (!asyncEntityEnabled || entity instanceof Player){
|
||||
task.run();
|
||||
return;
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
index ae22ca9ea5fd3d78d8c5bf9f1ab96f1129fddc11..1012b8d1d192a946b0982c88c12a0fc0e6051972 100644
|
||||
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: wangxyper <wangxyper@163.com>
|
||||
Date: Fri, 13 Jan 2023 15:25:47 +0800
|
||||
Subject: [PATCH] Hearse: Change something
|
||||
|
||||
Original license: MIT
|
||||
Original project: https://github.com/NaturalCodeClub/HearseRewrite
|
||||
|
||||
diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
index 86f8afd54c0cbb449403c3f43e6880ade13cfecc..c0e7a9cf79ddf00827daba0aa9c7a32fa76b0c7c 100644
|
||||
--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
+++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java
|
||||
@@ -88,7 +88,7 @@ public class ServerEntityTickHook {
|
||||
}
|
||||
}
|
||||
};
|
||||
- if (!asyncEntityEnabled || entity instanceof Player){
|
||||
+ if (!asyncEntityEnabled){
|
||||
task.run();
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: wangxyper <wangxyper@163.com>
|
||||
Date: Sat, 14 Jan 2023 09:27:14 +0800
|
||||
Subject: [PATCH] Hearse: Fix a NoSuchElementError in Delayed8 and Delayed26
|
||||
distance propagators
|
||||
|
||||
Original license: MIT
|
||||
Original project: https://github.com/NaturalCodeClub/HearseRewrite
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
|
||||
index 762f09c8f374fbccc9f5be985401ad334e1655a0..e831738a2988746fe4e065f6ded811a8bdf5dabe 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/misc/Delayed26WayDistancePropagator3D.java
|
||||
@@ -94,24 +94,42 @@ public final class Delayed26WayDistancePropagator3D {
|
||||
|
||||
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
|
||||
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelIncreaseWorkQueueBitset |= (1L << level);
|
||||
}
|
||||
|
||||
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
|
||||
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelIncreaseWorkQueueBitset |= (1L << index);
|
||||
}
|
||||
|
||||
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
|
||||
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelRemoveWorkQueueBitset |= (1L << level);
|
||||
}
|
||||
@@ -163,9 +181,20 @@ public final class Delayed26WayDistancePropagator3D {
|
||||
this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) {
|
||||
|
||||
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
|
||||
- while (!queue.queuedLevels.isEmpty()) {
|
||||
- final long coordinate = queue.queuedCoordinates.removeFirst();
|
||||
- byte level = queue.queuedLevels.removeFirst();
|
||||
+ while (true) {
|
||||
+
|
||||
+ long coordinate;
|
||||
+ byte level;
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ if (queue.queuedLevels.isEmpty()){
|
||||
+ break;
|
||||
+ }
|
||||
+ coordinate = queue.queuedCoordinates.removeFirst();
|
||||
+ level = queue.queuedLevels.removeFirst();
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
final boolean neighbourCheck = level < 0;
|
||||
|
||||
@@ -232,9 +261,19 @@ public final class Delayed26WayDistancePropagator3D {
|
||||
this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) {
|
||||
|
||||
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
|
||||
- while (!queue.queuedLevels.isEmpty()) {
|
||||
- final long coordinate = queue.queuedCoordinates.removeFirst();
|
||||
- final byte level = queue.queuedLevels.removeFirst();
|
||||
+ while (true) {
|
||||
+ long coordinate;
|
||||
+ byte level;
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ if (queue.queuedLevels.isEmpty()){
|
||||
+ break;
|
||||
+ }
|
||||
+ coordinate = queue.queuedCoordinates.removeFirst();
|
||||
+ level = queue.queuedLevels.removeFirst();
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
|
||||
if (currentLevel == 0) {
|
||||
diff --git a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
|
||||
index 8c5a51b5992eccf3627f326e164288b5f6bbcff6..0fa95d81bafc7fe5c1bede7a0608b54795a78fa0 100644
|
||||
--- a/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
|
||||
+++ b/src/main/java/io/papermc/paper/util/misc/Delayed8WayDistancePropagator2D.java
|
||||
@@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
+import java.util.concurrent.locks.StampedLock;
|
||||
|
||||
public final class Delayed8WayDistancePropagator2D {
|
||||
|
||||
@@ -357,24 +358,42 @@ public final class Delayed8WayDistancePropagator2D {
|
||||
|
||||
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
|
||||
final WorkQueue queue = this.levelIncreaseWorkQueues[level];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelIncreaseWorkQueueBitset |= (1L << level);
|
||||
}
|
||||
|
||||
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
|
||||
final WorkQueue queue = this.levelIncreaseWorkQueues[index];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelIncreaseWorkQueueBitset |= (1L << index);
|
||||
}
|
||||
|
||||
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
|
||||
final WorkQueue queue = this.levelRemoveWorkQueues[level];
|
||||
- queue.queuedCoordinates.add(coordinate);
|
||||
- queue.queuedLevels.add(level);
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ queue.queuedCoordinates.add(coordinate);
|
||||
+ queue.queuedLevels.add(level);
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
this.levelRemoveWorkQueueBitset |= (1L << level);
|
||||
}
|
||||
@@ -426,9 +445,19 @@ public final class Delayed8WayDistancePropagator2D {
|
||||
this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) {
|
||||
|
||||
final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
|
||||
- while (!queue.queuedLevels.isEmpty()) {
|
||||
- final long coordinate = queue.queuedCoordinates.removeFirst();
|
||||
- byte level = queue.queuedLevels.removeFirst();
|
||||
+ while (true) {
|
||||
+ byte level;
|
||||
+ long coordinate;
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ if (queue.queuedLevels.isEmpty()){
|
||||
+ break;
|
||||
+ }
|
||||
+ coordinate = queue.queuedCoordinates.removeFirst();
|
||||
+ level = queue.queuedLevels.removeFirst();
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
final boolean neighbourCheck = level < 0;
|
||||
|
||||
@@ -492,9 +521,20 @@ public final class Delayed8WayDistancePropagator2D {
|
||||
this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) {
|
||||
|
||||
final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
|
||||
- while (!queue.queuedLevels.isEmpty()) {
|
||||
- final long coordinate = queue.queuedCoordinates.removeFirst();
|
||||
- final byte level = queue.queuedLevels.removeFirst();
|
||||
+ while (true) {
|
||||
+ long coordinate;
|
||||
+ byte level;
|
||||
+
|
||||
+ final long id = queue.lock.writeLock();
|
||||
+ try {
|
||||
+ if (queue.queuedLevels.isEmpty()){
|
||||
+ break;
|
||||
+ }
|
||||
+ coordinate = queue.queuedCoordinates.removeFirst();
|
||||
+ level = queue.queuedLevels.removeFirst();
|
||||
+ }finally {
|
||||
+ queue.lock.unlockWrite(id);
|
||||
+ }
|
||||
|
||||
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
|
||||
if (currentLevel == 0) {
|
||||
@@ -681,6 +721,7 @@ public final class Delayed8WayDistancePropagator2D {
|
||||
protected static final class WorkQueue {
|
||||
public final Deque<Long> queuedCoordinates = new ConcurrentLinkedDeque<>();
|
||||
public final Deque<Byte> queuedLevels = new ConcurrentLinkedDeque<>();
|
||||
+ public final StampedLock lock = new StampedLock();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: wangxyper <wangxyper@163.com>
|
||||
Date: Sat, 14 Jan 2023 10:14:54 +0800
|
||||
Subject: [PATCH] Hearse: Optimized some locks in ChunkEntitySlices
|
||||
|
||||
Original license: MIT
|
||||
Original project: https://github.com/NaturalCodeClub/HearseRewrite
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
index 122699937606f5e00e356f5c1ea12db0563508a3..b12c02962e9dad92ae79d762887c65db10765488 100644
|
||||
--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java
|
||||
@@ -66,50 +66,67 @@ public final class ChunkEntitySlices {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
+ private org.bukkit.entity.Entity[] getChunkEntitiesUnsafe(){
|
||||
+ List<org.bukkit.entity.Entity> ret = new java.util.ArrayList<>();
|
||||
+ final Entity[] entities = this.entities.getRawData();
|
||||
+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
|
||||
+ final Entity entity = entities[i];
|
||||
+ if (entity == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity();
|
||||
+ if (bukkit != null && bukkit.isValid()) {
|
||||
+ ret.add(bukkit);
|
||||
+ }
|
||||
+ }
|
||||
+ return ret.toArray(new org.bukkit.entity.Entity[0]);
|
||||
+ }
|
||||
+
|
||||
// Paper start - optimise CraftChunk#getEntities
|
||||
public org.bukkit.entity.Entity[] getChunkEntities() {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)) {
|
||||
+ return this.getChunkEntitiesUnsafe();
|
||||
+ }
|
||||
+
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
- List<org.bukkit.entity.Entity> ret = new java.util.ArrayList<>();
|
||||
- final Entity[] entities = this.entities.getRawData();
|
||||
- for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
|
||||
- final Entity entity = entities[i];
|
||||
- if (entity == null) {
|
||||
- continue;
|
||||
- }
|
||||
- final org.bukkit.entity.Entity bukkit = entity.getBukkitEntity();
|
||||
- if (bukkit != null && bukkit.isValid()) {
|
||||
- ret.add(bukkit);
|
||||
- }
|
||||
- }
|
||||
- return ret.toArray(new org.bukkit.entity.Entity[0]);
|
||||
+ return this.getChunkEntitiesUnsafe();
|
||||
} finally {
|
||||
this.accessLock.unlockRead(id);
|
||||
}
|
||||
}
|
||||
|
||||
- public CompoundTag save() {
|
||||
- final long id = this.accessLock.readLock();
|
||||
- try {
|
||||
- final int len = this.entities.size();
|
||||
- if (len == 0) {
|
||||
- return null;
|
||||
- }
|
||||
+ private CompoundTag saveUnsafe(){
|
||||
+ final int len = this.entities.size();
|
||||
+ if (len == 0) {
|
||||
+ return null;
|
||||
+ }
|
||||
|
||||
- final Entity[] rawData = this.entities.getRawData();
|
||||
- final List<Entity> collectedEntities = new ArrayList<>(len);
|
||||
- for (int i = 0; i < len; ++i) {
|
||||
- final Entity entity = rawData[i];
|
||||
- if (entity.shouldBeSaved()) {
|
||||
- collectedEntities.add(entity);
|
||||
- }
|
||||
+ final Entity[] rawData = this.entities.getRawData();
|
||||
+ final List<Entity> collectedEntities = new ArrayList<>(len);
|
||||
+ for (int i = 0; i < len; ++i) {
|
||||
+ final Entity entity = rawData[i];
|
||||
+ if (entity.shouldBeSaved()) {
|
||||
+ collectedEntities.add(entity);
|
||||
}
|
||||
+ }
|
||||
|
||||
- if (collectedEntities.isEmpty()) {
|
||||
- return null;
|
||||
- }
|
||||
+ if (collectedEntities.isEmpty()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return EntityStorage.saveEntityChunk(collectedEntities, new ChunkPos(this.chunkX, this.chunkZ), this.world);
|
||||
+ }
|
||||
|
||||
- return EntityStorage.saveEntityChunk(collectedEntities, new ChunkPos(this.chunkX, this.chunkZ), this.world);
|
||||
+ public CompoundTag save() {
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ return this.saveUnsafe();
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
+ try {
|
||||
+ return this.saveUnsafe();
|
||||
} finally {
|
||||
this.accessLock.unlockRead(id);
|
||||
}
|
||||
@@ -119,12 +136,18 @@ public final class ChunkEntitySlices {
|
||||
public boolean unload() {
|
||||
Entity[] collectedEntities;
|
||||
int len;
|
||||
- long id = this.accessLock.readLock();
|
||||
- try {
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
len = this.entities.size();
|
||||
collectedEntities = Arrays.copyOf(this.entities.getRawData(), len);
|
||||
- } finally {
|
||||
- this.accessLock.unlockRead(id);
|
||||
+ }else {
|
||||
+ id = this.accessLock.readLock();
|
||||
+ try {
|
||||
+ len = this.entities.size();
|
||||
+ collectedEntities = Arrays.copyOf(this.entities.getRawData(), len);
|
||||
+ } finally {
|
||||
+ this.accessLock.unlockRead(id);
|
||||
+ }
|
||||
}
|
||||
for (int i = 0; i < len; ++i) {
|
||||
final Entity entity = collectedEntities[i];
|
||||
@@ -160,7 +183,12 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public void callEntitiesLoadEvent() {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ CraftEventFactory.callEntitiesLoadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
CraftEventFactory.callEntitiesLoadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
|
||||
} finally {
|
||||
@@ -169,7 +197,12 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public void callEntitiesUnloadEvent() {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ CraftEventFactory.callEntitiesUnloadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
CraftEventFactory.callEntitiesUnloadEvent(this.world, new ChunkPos(this.chunkX, this.chunkZ), this.getAllEntities());
|
||||
} finally {
|
||||
@@ -179,7 +212,11 @@ public final class ChunkEntitySlices {
|
||||
// Paper end - optimise CraftChunk#getEntities
|
||||
|
||||
public boolean isEmpty() {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ return this.entities.size() == 0;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
return this.entities.size() == 0;
|
||||
} finally {
|
||||
@@ -188,16 +225,25 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public void mergeInto(final ChunkEntitySlices slices) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
final List<Entity> cop = new ArrayList<>();
|
||||
- try {
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
final Entity[] entities = this.entities.getRawData();
|
||||
for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
|
||||
final Entity entity = entities[i];
|
||||
cop.add(entity);
|
||||
}
|
||||
- } finally {
|
||||
- this.accessLock.unlockRead(id);
|
||||
+ }else {
|
||||
+ id = this.accessLock.readLock();
|
||||
+ try {
|
||||
+ final Entity[] entities = this.entities.getRawData();
|
||||
+ for (int i = 0, size = Math.min(entities.length, this.entities.size()); i < size; ++i) {
|
||||
+ final Entity entity = entities[i];
|
||||
+ cop.add(entity);
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.accessLock.unlockRead(id);
|
||||
+ }
|
||||
}
|
||||
for (Entity entity : cop){
|
||||
slices.addEntity(entity, entity.sectionY);
|
||||
@@ -209,13 +255,19 @@ public final class ChunkEntitySlices {
|
||||
|
||||
Entity[] entities;
|
||||
|
||||
- final long id = this.accessLock.readLock();
|
||||
- try {
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
entities = Arrays.copyOf(this.entities.getRawData(), this.entities.getRawData().length);
|
||||
- } finally {
|
||||
- this.accessLock.unlockRead(id);
|
||||
+ }else {
|
||||
+ id = this.accessLock.readLock();
|
||||
+ try {
|
||||
+ entities = Arrays.copyOf(this.entities.getRawData(), this.entities.getRawData().length);
|
||||
+ } finally {
|
||||
+ this.accessLock.unlockRead(id);
|
||||
+ }
|
||||
}
|
||||
|
||||
+
|
||||
for (final Entity entity : entities) {
|
||||
final Visibility oldVisibility = EntityLookup.getEntityStatus(entity);
|
||||
entity.chunkStatus = status;
|
||||
@@ -278,7 +330,12 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ this.hardCollidingEntities.getEntities(except, box, into, predicate);
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
this.hardCollidingEntities.getEntities(except, box, into, predicate);
|
||||
} finally {
|
||||
@@ -287,34 +344,46 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
|
||||
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ this.allEntities.getEntitiesWithEnderDragonParts(except, box, into, predicate);
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
this.allEntities.getEntitiesWithEnderDragonParts(except, box, into, predicate);
|
||||
} finally {
|
||||
this.accessLock.unlockRead(id);
|
||||
}
|
||||
-
|
||||
}
|
||||
|
||||
public void getEntitiesWithoutDragonParts(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ this.allEntities.getEntities(except, box, into, predicate);
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
this.allEntities.getEntities(except, box, into, predicate);
|
||||
} finally {
|
||||
this.accessLock.unlockRead(id);
|
||||
}
|
||||
-
|
||||
}
|
||||
|
||||
public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||
final Predicate<? super T> predicate) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ this.allEntities.getEntities(type, box, (List) into, (Predicate) predicate);
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
this.allEntities.getEntities(type, box, (List) into, (Predicate) predicate);
|
||||
} finally {
|
||||
this.accessLock.unlockRead(id);
|
||||
}
|
||||
-
|
||||
}
|
||||
|
||||
protected EntityCollectionBySection initClass(final Class<? extends Entity> clazz) {
|
||||
@@ -342,7 +411,18 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public <T extends Entity> void getEntities(final Class<? extends T> clazz, final Entity except, final AABB box, final List<? super T> into,
|
||||
final Predicate<? super T> predicate) {
|
||||
- final long id = this.accessLock.readLock();
|
||||
+ long id = this.accessLock.tryOptimisticRead();
|
||||
+ if (this.accessLock.validate(id)){
|
||||
+ EntityCollectionBySection collection = this.entitiesByClass.get(clazz);
|
||||
+ if (collection != null) {
|
||||
+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List) into, (Predicate) predicate);
|
||||
+ } else {
|
||||
+ this.entitiesByClass.putIfAbsent(clazz, collection = this.initClass(clazz));
|
||||
+ collection.getEntitiesWithEnderDragonParts(except, clazz, box, (List) into, (Predicate) predicate);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ id = this.accessLock.readLock();
|
||||
try {
|
||||
EntityCollectionBySection collection = this.entitiesByClass.get(clazz);
|
||||
if (collection != null) {
|
||||
@@ -0,0 +1,102 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: wangxyper <wangxyper@163.com>
|
||||
Date: Sat, 14 Jan 2023 14:23:39 +0800
|
||||
Subject: [PATCH] Hearse: Remove a lock in ServerChunkCache
|
||||
|
||||
Original license: MIT
|
||||
Original project: https://github.com/NaturalCodeClub/HearseRewrite
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 85c03dc7c1e714fab281374a177cd4c54e97d939..e311724d2e723115bc9549a61e6206a8aed835d8 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -4,6 +4,9 @@ import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
+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.ObjectArraySet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import net.minecraft.Util;
|
||||
@@ -57,8 +60,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
@VisibleForDebug
|
||||
private NaturalSpawner.SpawnState lastSpawnState;
|
||||
// Paper start
|
||||
- final com.destroystokyo.paper.util.concurrent.WeakSeqLock loadedChunkMapSeqLock = new com.destroystokyo.paper.util.concurrent.WeakSeqLock();
|
||||
- final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<LevelChunk> loadedChunkMap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(8192, 0.5f);
|
||||
+ private final Long2ObjectMap<LevelChunk> loadedChunkMap = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>(8192, 0.5f));
|
||||
|
||||
private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4];
|
||||
|
||||
@@ -70,12 +72,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
}
|
||||
|
||||
public void addLoadedChunk(LevelChunk chunk) {
|
||||
- this.loadedChunkMapSeqLock.acquireWrite();
|
||||
- try {
|
||||
- this.loadedChunkMap.put(chunk.coordinateKey, chunk);
|
||||
- } finally {
|
||||
- this.loadedChunkMapSeqLock.releaseWrite();
|
||||
- }
|
||||
+ this.loadedChunkMap.put(chunk.coordinateKey, chunk);
|
||||
|
||||
// rewrite cache if we have to
|
||||
// we do this since we also cache null chunks
|
||||
@@ -85,13 +82,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
}
|
||||
|
||||
public void removeLoadedChunk(LevelChunk chunk) {
|
||||
- this.loadedChunkMapSeqLock.acquireWrite();
|
||||
- try {
|
||||
- this.loadedChunkMap.remove(chunk.coordinateKey);
|
||||
- } finally {
|
||||
- this.loadedChunkMapSeqLock.releaseWrite();
|
||||
- }
|
||||
-
|
||||
+ this.loadedChunkMap.remove(chunk.coordinateKey);
|
||||
// rewrite cache if we have to
|
||||
// we do this since we also cache null chunks
|
||||
int cacheKey = getChunkCacheKey(chunk.locX, chunk.locZ);
|
||||
@@ -360,22 +351,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
return this.getChunkAtIfLoadedMainThread(x, z);
|
||||
}
|
||||
|
||||
- LevelChunk ret = null;
|
||||
- long readlock;
|
||||
- do {
|
||||
- readlock = this.loadedChunkMapSeqLock.acquireRead();
|
||||
- try {
|
||||
- ret = this.loadedChunkMap.get(k);
|
||||
- } catch (Throwable thr) {
|
||||
- if (thr instanceof ThreadDeath) {
|
||||
- throw (ThreadDeath)thr;
|
||||
- }
|
||||
- // re-try, this means a CME occurred...
|
||||
- continue;
|
||||
- }
|
||||
- } while (!this.loadedChunkMapSeqLock.tryReleaseRead(readlock));
|
||||
-
|
||||
- return ret;
|
||||
+ return this.loadedChunkMap.get(k);
|
||||
}
|
||||
// Paper end
|
||||
// Paper start - async chunk io
|
||||
@@ -436,7 +412,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
// Paper end
|
||||
com.destroystokyo.paper.io.SyncLoadFinder.logSyncLoad(this.level, x1, z1); // Paper - sync load info
|
||||
//this.level.timings.syncChunkLoad.startTiming(); // Paper // Purpur
|
||||
- chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
||||
+ chunkproviderserver_b.managedBlock(completablefuture::isDone);
|
||||
io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.popChunkWait(); // Paper - async chunk debug // Paper - rewrite chunk system
|
||||
//this.level.timings.syncChunkLoad.stopTiming(); // Paper // Purpur
|
||||
} // Paper
|
||||
@@ -495,6 +471,7 @@ public class ServerChunkCache extends ChunkSource {
|
||||
// Paper start - add isUrgent - old sig left in place for dirty nms plugins
|
||||
return getChunkFutureMainThread(chunkX, chunkZ, leastStatus, create, false);
|
||||
}
|
||||
+
|
||||
private CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getChunkFutureMainThread(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create, boolean isUrgent) {
|
||||
// Paper start - rewrite chunk system
|
||||
io.papermc.paper.util.TickThread.ensureTickThread(this.level, chunkX, chunkZ, "Scheduling chunk load off-main");
|
||||
Reference in New Issue
Block a user