fix: snapshot entity metrics on main thread
Build / build (push) Successful in 3m0s

This commit is contained in:
dmg
2026-01-22 23:47:55 -05:00
parent 7f48256f7d
commit 2648897197
4 changed files with 56 additions and 26 deletions
@@ -6,6 +6,7 @@ import java.lang.management.MemoryUsage;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -31,6 +32,8 @@ public final class MetricsRegistry {
private final Method serverMsptMethod;
private final Method playerPingMethod;
private final Method chunkTileEntitiesMethod;
private volatile Map<String, Long> entityCountsSnapshot = Collections.emptyMap();
private volatile Map<String, Long> tileEntityCountsSnapshot = Collections.emptyMap();
private final LongAdder chatMessages = new LongAdder();
private final LongAdder playerMovements = new LongAdder();
@@ -120,6 +123,37 @@ public final class MetricsRegistry {
pluginDisables.increment();
}
public void refreshEntitySnapshots() {
Map<String, Long> entityCounts = new HashMap<>();
Map<String, Long> tileCounts = new HashMap<>();
for (var world : server.getWorlds()) {
for (Entity entity : world.getEntities()) {
EntityType type = entity.getType();
String label = normalizeLabel(type.name());
entityCounts.merge(label, 1L, Long::sum);
}
if (chunkTileEntitiesMethod != null) {
for (Chunk chunk : world.getLoadedChunks()) {
Object result = invoke(chunkTileEntitiesMethod, chunk);
if (!(result instanceof Object[] states)) {
continue;
}
for (Object state : states) {
if (state instanceof BlockState blockState) {
String label = normalizeLabel(blockState.getType().name());
tileCounts.merge(label, 1L, Long::sum);
}
}
}
}
}
entityCountsSnapshot = Collections.unmodifiableMap(entityCounts);
tileEntityCountsSnapshot = Collections.unmodifiableMap(tileCounts);
}
public String render() {
StringBuilder builder = new StringBuilder();
@@ -226,37 +260,14 @@ public final class MetricsRegistry {
}
private void appendEntityMetrics(StringBuilder builder) {
Map<String, Long> entityCounts = new HashMap<>();
for (var world : server.getWorlds()) {
for (Entity entity : world.getEntities()) {
EntityType type = entity.getType();
String label = normalizeLabel(type.name());
entityCounts.merge(label, 1L, Long::sum);
}
}
appendLabeledGauge(builder, "spigot_entities_total", "Entities by type", "type", entityCounts);
appendLabeledGauge(builder, "spigot_entities_total", "Entities by type", "type", entityCountsSnapshot);
}
private void appendTileEntityMetrics(StringBuilder builder) {
if (chunkTileEntitiesMethod == null) {
return;
}
Map<String, Long> tileCounts = new HashMap<>();
for (var world : server.getWorlds()) {
for (Chunk chunk : world.getLoadedChunks()) {
Object result = invoke(chunkTileEntitiesMethod, chunk);
if (!(result instanceof Object[] states)) {
continue;
}
for (Object state : states) {
if (state instanceof BlockState blockState) {
String label = normalizeLabel(blockState.getType().name());
tileCounts.merge(label, 1L, Long::sum);
}
}
}
}
appendLabeledGauge(builder, "spigot_tile_entities_total", "Tile entities by type", "type", tileCounts);
appendLabeledGauge(builder, "spigot_tile_entities_total", "Tile entities by type", "type", tileEntityCountsSnapshot);
}
private void appendPlayerPingMetrics(StringBuilder builder) {