Reimpliment next-tick-list scale improvements
This commit is contained in:
parent
076af791cc
commit
45cacdd49b
2 changed files with 374 additions and 0 deletions
|
@ -151,6 +151,68 @@ index 0000000..d88f864
|
|||
+ return this.b.getProperty(s + ".name", "");
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java
|
||||
new file mode 100644
|
||||
index 0000000..52a70a1
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/net/minecraft/server/NextTickListEntry.java
|
||||
@@ -0,0 +1,56 @@
|
||||
+package net.minecraft.server;
|
||||
+
|
||||
+public class NextTickListEntry implements Comparable {
|
||||
+
|
||||
+ private static long g = 0L;
|
||||
+ public int a;
|
||||
+ public int b;
|
||||
+ public int c;
|
||||
+ public int d;
|
||||
+ public long e;
|
||||
+ public int f;
|
||||
+ private long h;
|
||||
+
|
||||
+ public NextTickListEntry(int i, int j, int k, int l) {
|
||||
+ this.h = (long) (g++);
|
||||
+ this.a = i;
|
||||
+ this.b = j;
|
||||
+ this.c = k;
|
||||
+ this.d = l;
|
||||
+ }
|
||||
+
|
||||
+ public boolean equals(Object object) {
|
||||
+ if (!(object instanceof NextTickListEntry)) {
|
||||
+ return false;
|
||||
+ } else {
|
||||
+ NextTickListEntry nextticklistentry = (NextTickListEntry) object;
|
||||
+
|
||||
+ return this.a == nextticklistentry.a && this.b == nextticklistentry.b && this.c == nextticklistentry.c && Block.b(this.d, nextticklistentry.d);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public int hashCode() {
|
||||
+ return (this.a * 1024 * 1024 + this.c * 1024 + this.b) * 256;
|
||||
+ }
|
||||
+
|
||||
+ public NextTickListEntry a(long i) {
|
||||
+ this.e = i;
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
+ public void a(int i) {
|
||||
+ this.f = i;
|
||||
+ }
|
||||
+
|
||||
+ public int compareTo(NextTickListEntry nextticklistentry) {
|
||||
+ return this.e < nextticklistentry.e ? -1 : (this.e > nextticklistentry.e ? 1 : (this.f != nextticklistentry.f ? this.f - nextticklistentry.f : (this.h < nextticklistentry.h ? -1 : (this.h > nextticklistentry.h ? 1 : 0))));
|
||||
+ }
|
||||
+
|
||||
+ public String toString() {
|
||||
+ return this.d + ": (" + this.a + ", " + this.b + ", " + this.c + "), " + this.e + ", " + this.f + ", " + this.h;
|
||||
+ }
|
||||
+
|
||||
+ public int compareTo(Object object) {
|
||||
+ return this.compareTo((NextTickListEntry) object);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/NibbleArray.java b/src/main/java/net/minecraft/server/NibbleArray.java
|
||||
new file mode 100644
|
||||
index 0000000..5d75a54
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
From 5cca431dbcda5512e12ccb887ae8e8e741c57b18 Mon Sep 17 00:00:00 2001
|
||||
From: Mike Primm <mike@primmhome.com>
|
||||
Date: Wed, 24 Apr 2013 01:43:33 -0500
|
||||
Subject: [PATCH] Improve next-tick-list performance on chunk unloads, large
|
||||
queues
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/NextTickListEntry.java b/src/main/java/net/minecraft/server/NextTickListEntry.java
|
||||
index 52a70a1..08a4240 100644
|
||||
--- a/src/main/java/net/minecraft/server/NextTickListEntry.java
|
||||
+++ b/src/main/java/net/minecraft/server/NextTickListEntry.java
|
||||
@@ -30,7 +30,7 @@ public class NextTickListEntry implements Comparable {
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
- return (this.a * 1024 * 1024 + this.c * 1024 + this.b) * 256;
|
||||
+ return (this.a * 257) ^ this.b ^ (this.c * 60217); // Spigot - better hash
|
||||
}
|
||||
|
||||
public NextTickListEntry a(long i) {
|
||||
diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
index a2f7fee..b0c2c96 100644
|
||||
--- a/src/main/java/net/minecraft/server/WorldServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/WorldServer.java
|
||||
@@ -28,8 +28,8 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
private final MinecraftServer server;
|
||||
public EntityTracker tracker; // CraftBukkit - private final -> public
|
||||
private final PlayerChunkMap manager;
|
||||
- private Set L;
|
||||
- private TreeSet M;
|
||||
+ private LongObjectHashMap<Set<NextTickListEntry>> tickEntriesByChunk; // Spigot - switch to something better for chunk-wise access
|
||||
+ private TreeSet<NextTickListEntry> tickEntryQueue; // Spigot
|
||||
public ChunkProviderServer chunkProviderServer;
|
||||
public boolean savingDisabled;
|
||||
private boolean N;
|
||||
@@ -38,7 +38,8 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
private NoteDataList[] Q = new NoteDataList[] { new NoteDataList((EmptyClass2) null), new NoteDataList((EmptyClass2) null)};
|
||||
private int R = 0;
|
||||
private static final StructurePieceTreasure[] S = new StructurePieceTreasure[] { new StructurePieceTreasure(Item.STICK.id, 0, 1, 3, 10), new StructurePieceTreasure(Block.WOOD.id, 0, 1, 3, 10), new StructurePieceTreasure(Block.LOG.id, 0, 1, 3, 10), new StructurePieceTreasure(Item.STONE_AXE.id, 0, 1, 1, 3), new StructurePieceTreasure(Item.WOOD_AXE.id, 0, 1, 1, 5), new StructurePieceTreasure(Item.STONE_PICKAXE.id, 0, 1, 1, 3), new StructurePieceTreasure(Item.WOOD_PICKAXE.id, 0, 1, 1, 5), new StructurePieceTreasure(Item.APPLE.id, 0, 2, 3, 5), new StructurePieceTreasure(Item.BREAD.id, 0, 2, 3, 3)};
|
||||
- private ArrayList T = new ArrayList();
|
||||
+ private ArrayList<NextTickListEntry> pendingTickEntries = new ArrayList<NextTickListEntry>(); // Spigot
|
||||
+ private int nextPendingTickEntry; // Spigot
|
||||
private IntHashMap entitiesById;
|
||||
|
||||
// CraftBukkit start
|
||||
@@ -56,13 +57,15 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
this.entitiesById = new IntHashMap();
|
||||
}
|
||||
|
||||
- if (this.L == null) {
|
||||
- this.L = new HashSet();
|
||||
+ // Spigot start
|
||||
+ if (this.tickEntriesByChunk == null) {
|
||||
+ this.tickEntriesByChunk = new LongObjectHashMap<Set<NextTickListEntry>>();
|
||||
}
|
||||
|
||||
- if (this.M == null) {
|
||||
- this.M = new TreeSet();
|
||||
+ if (this.tickEntryQueue == null) {
|
||||
+ this.tickEntryQueue = new TreeSet<NextTickListEntry>();
|
||||
}
|
||||
+ // Spigot end
|
||||
|
||||
this.P = new org.bukkit.craftbukkit.CraftTravelAgent(this); // CraftBukkit
|
||||
this.scoreboard = new ScoreboardServer(minecraftserver);
|
||||
@@ -444,9 +447,16 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
}
|
||||
|
||||
public boolean a(int i, int j, int k, int l) {
|
||||
- NextTickListEntry nextticklistentry = new NextTickListEntry(i, j, k, l);
|
||||
-
|
||||
- return this.T.contains(nextticklistentry);
|
||||
+ // Spigot start
|
||||
+ int te_cnt = this.pendingTickEntries.size();
|
||||
+ for (int idx = this.nextPendingTickEntry; idx < te_cnt; idx++) {
|
||||
+ NextTickListEntry ent = this.pendingTickEntries.get(idx);
|
||||
+ if ((ent.a == i) && (ent.b == j) && (ent.c == k) && Block.b(ent.d, l)) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ // Spigot end
|
||||
}
|
||||
|
||||
public void a(int i, int j, int k, int l, int i1) {
|
||||
@@ -479,10 +489,9 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
nextticklistentry.a(j1);
|
||||
}
|
||||
|
||||
- if (!this.L.contains(nextticklistentry)) {
|
||||
- this.L.add(nextticklistentry);
|
||||
- this.M.add(nextticklistentry);
|
||||
- }
|
||||
+ // Spigot start
|
||||
+ addNextTickIfNeeded(nextticklistentry);
|
||||
+ // Spigot end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,10 +503,9 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
nextticklistentry.a((long) i1 + this.worldData.getTime());
|
||||
}
|
||||
|
||||
- if (!this.L.contains(nextticklistentry)) {
|
||||
- this.L.add(nextticklistentry);
|
||||
- this.M.add(nextticklistentry);
|
||||
- }
|
||||
+ // Spigot start
|
||||
+ addNextTickIfNeeded(nextticklistentry);
|
||||
+ // Spigot end
|
||||
}
|
||||
|
||||
public void tickEntities() {
|
||||
@@ -517,11 +525,12 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
}
|
||||
|
||||
public boolean a(boolean flag) {
|
||||
- int i = this.M.size();
|
||||
+ // Spigot start
|
||||
+ int i = this.tickEntryQueue.size();
|
||||
|
||||
- if (i != this.L.size()) {
|
||||
- throw new IllegalStateException("TickNextTick list out of synch");
|
||||
- } else {
|
||||
+ this.nextPendingTickEntry = 0;
|
||||
+ {
|
||||
+ // Spigot end
|
||||
if (i > 1000) {
|
||||
// CraftBukkit start - If the server has too much to process over time, try to alleviate that
|
||||
if (i > 20 * 1000) {
|
||||
@@ -537,23 +546,24 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
NextTickListEntry nextticklistentry;
|
||||
|
||||
for (int j = 0; j < i; ++j) {
|
||||
- nextticklistentry = (NextTickListEntry) this.M.first();
|
||||
+ nextticklistentry = (NextTickListEntry) this.tickEntryQueue.first(); // Spigot
|
||||
if (!flag && nextticklistentry.e > this.worldData.getTime()) {
|
||||
break;
|
||||
}
|
||||
|
||||
- this.M.remove(nextticklistentry);
|
||||
- this.L.remove(nextticklistentry);
|
||||
- this.T.add(nextticklistentry);
|
||||
+ // Spigot start
|
||||
+ this.removeNextTickIfNeeded(nextticklistentry);
|
||||
+ this.pendingTickEntries.add(nextticklistentry);
|
||||
+ // Spigot end
|
||||
}
|
||||
|
||||
this.methodProfiler.b();
|
||||
this.methodProfiler.a("ticking");
|
||||
- Iterator iterator = this.T.iterator();
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- nextticklistentry = (NextTickListEntry) iterator.next();
|
||||
- iterator.remove();
|
||||
+ // Spigot start
|
||||
+ for (int j = 0, te_cnt = this.pendingTickEntries.size(); j < te_cnt; j++) {
|
||||
+ nextticklistentry = pendingTickEntries.get(j);
|
||||
+ this.nextPendingTickEntry = j + 1; // treat this as dequeued
|
||||
+ // Spigot end
|
||||
byte b0 = 0;
|
||||
|
||||
if (this.e(nextticklistentry.a - b0, nextticklistentry.b - b0, nextticklistentry.c - b0, nextticklistentry.a + b0, nextticklistentry.b + b0, nextticklistentry.c + b0)) {
|
||||
@@ -584,52 +594,18 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
}
|
||||
|
||||
this.methodProfiler.b();
|
||||
- this.T.clear();
|
||||
- return !this.M.isEmpty();
|
||||
- }
|
||||
+ // Spigot start
|
||||
+ this.pendingTickEntries.clear();
|
||||
+ this.nextPendingTickEntry = 0;
|
||||
+ return !this.tickEntryQueue.isEmpty();
|
||||
+ // Spigot end
|
||||
+ }
|
||||
}
|
||||
|
||||
public List a(Chunk chunk, boolean flag) {
|
||||
- ArrayList arraylist = null;
|
||||
- ChunkCoordIntPair chunkcoordintpair = chunk.l();
|
||||
- int i = (chunkcoordintpair.x << 4) - 2;
|
||||
- int j = i + 16 + 2;
|
||||
- int k = (chunkcoordintpair.z << 4) - 2;
|
||||
- int l = k + 16 + 2;
|
||||
-
|
||||
- for (int i1 = 0; i1 < 2; ++i1) {
|
||||
- Iterator iterator;
|
||||
-
|
||||
- if (i1 == 0) {
|
||||
- iterator = this.M.iterator();
|
||||
- } else {
|
||||
- iterator = this.T.iterator();
|
||||
- /* CraftBukkit start - Comment out debug spam
|
||||
- if (!this.T.isEmpty()) {
|
||||
- System.out.println(this.T.size());
|
||||
- }
|
||||
- // CraftBukkit end */
|
||||
- }
|
||||
-
|
||||
- while (iterator.hasNext()) {
|
||||
- NextTickListEntry nextticklistentry = (NextTickListEntry) iterator.next();
|
||||
-
|
||||
- if (nextticklistentry.a >= i && nextticklistentry.a < j && nextticklistentry.c >= k && nextticklistentry.c < l) {
|
||||
- if (flag) {
|
||||
- this.L.remove(nextticklistentry);
|
||||
- iterator.remove();
|
||||
- }
|
||||
-
|
||||
- if (arraylist == null) {
|
||||
- arraylist = new ArrayList();
|
||||
- }
|
||||
-
|
||||
- arraylist.add(nextticklistentry);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return arraylist;
|
||||
+ // Spigot start
|
||||
+ return this.getNextTickEntriesForChunk(chunk, flag);
|
||||
+ // Spigot end
|
||||
}
|
||||
|
||||
public void entityJoinedWorld(Entity entity, boolean flag) {
|
||||
@@ -706,13 +682,15 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
this.entitiesById = new IntHashMap();
|
||||
}
|
||||
|
||||
- if (this.L == null) {
|
||||
- this.L = new HashSet();
|
||||
+ // Spigot start
|
||||
+ if (this.tickEntriesByChunk == null) {
|
||||
+ this.tickEntriesByChunk = new LongObjectHashMap<Set<NextTickListEntry>>();
|
||||
}
|
||||
|
||||
- if (this.M == null) {
|
||||
- this.M = new TreeSet();
|
||||
+ if (this.tickEntryQueue == null) {
|
||||
+ this.tickEntryQueue = new TreeSet<NextTickListEntry>();
|
||||
}
|
||||
+ // Spigot end
|
||||
|
||||
this.b(worldsettings);
|
||||
super.a(worldsettings);
|
||||
@@ -999,4 +977,62 @@ public class WorldServer extends World implements org.bukkit.BlockChangeDelegate
|
||||
return this.setTypeIdAndData(x, y, z, typeId, data, 3);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Spigot start
|
||||
+ private void addNextTickIfNeeded(NextTickListEntry ent) {
|
||||
+ long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4);
|
||||
+ Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
|
||||
+ if (chunkset == null) {
|
||||
+ chunkset = new HashSet<NextTickListEntry>();
|
||||
+ this.tickEntriesByChunk.put(coord, chunkset);
|
||||
+ } else if (chunkset.contains(ent)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ chunkset.add(ent);
|
||||
+ this.tickEntryQueue.add(ent);
|
||||
+ }
|
||||
+
|
||||
+ private void removeNextTickIfNeeded(NextTickListEntry ent) {
|
||||
+ long coord = LongHash.toLong(ent.a >> 4, ent.c >> 4);
|
||||
+ Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
|
||||
+ if (chunkset != null) {
|
||||
+ chunkset.remove(ent);
|
||||
+ if (chunkset.isEmpty()) {
|
||||
+ this.tickEntriesByChunk.remove(coord);
|
||||
+ }
|
||||
+ }
|
||||
+ this.tickEntryQueue.remove(ent);
|
||||
+ }
|
||||
+
|
||||
+ private List<NextTickListEntry> getNextTickEntriesForChunk(Chunk chunk, boolean remove) {
|
||||
+ long coord = LongHash.toLong(chunk.x, chunk.z);
|
||||
+ Set<NextTickListEntry> chunkset = this.tickEntriesByChunk.get(coord);
|
||||
+ List<NextTickListEntry> list = null;
|
||||
+ if (chunkset != null) {
|
||||
+ list = new ArrayList<NextTickListEntry>(chunkset);
|
||||
+ if (remove) {
|
||||
+ this.tickEntriesByChunk.remove(coord);
|
||||
+ this.tickEntryQueue.removeAll(list);
|
||||
+ chunkset.clear();
|
||||
+ }
|
||||
+ }
|
||||
+ // See if any on list of ticks being processed now
|
||||
+ if (this.nextPendingTickEntry < this.pendingTickEntries.size()) {
|
||||
+ int xmin = (chunk.x << 4);
|
||||
+ int xmax = xmin + 16;
|
||||
+ int zmin = (chunk.z << 4);
|
||||
+ int zmax = zmin + 16;
|
||||
+ int te_cnt = this.pendingTickEntries.size();
|
||||
+ for (int i = this.nextPendingTickEntry; i < te_cnt; i++) {
|
||||
+ NextTickListEntry ent = this.pendingTickEntries.get(i);
|
||||
+ if ((ent.a >= xmin) && (ent.a < xmax) && (ent.c >= zmin) && (ent.c < zmax)) {
|
||||
+ if (list == null) {
|
||||
+ list = new ArrayList<NextTickListEntry>();
|
||||
+ }
|
||||
+ list.add(ent);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return list;
|
||||
+ }
|
||||
+ // Spigot end
|
||||
}
|
||||
--
|
||||
1.8.1.3
|
||||
|
Loading…
Reference in a new issue