diff --git a/src/main/java/org/qortal/api/resource/PeersResource.java b/src/main/java/org/qortal/api/resource/PeersResource.java index d019bb4f..962f5e14 100644 --- a/src/main/java/org/qortal/api/resource/PeersResource.java +++ b/src/main/java/org/qortal/api/resource/PeersResource.java @@ -31,6 +31,7 @@ import org.qortal.network.PeerAddress; import org.qortal.repository.DataException; import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; +import org.qortal.utils.ExecuteProduceConsume; @Path("/peers") @Tag(name = "Peers") @@ -108,6 +109,29 @@ public class PeersResource { return Network.getInstance().getSelfPeers(); } + @GET + @Path("/enginestats") + @Operation( + summary = "Fetch statistics snapshot for networking engine", + responses = { + @ApiResponse( + content = @Content( + mediaType = MediaType.APPLICATION_JSON, + array = @ArraySchema( + schema = @Schema( + implementation = ExecuteProduceConsume.StatsSnapshot.class + ) + ) + ) + ) + } + ) + public ExecuteProduceConsume.StatsSnapshot getEngineStats() { + Security.checkApiCallAllowed(request); + + return Network.getInstance().getStatsSnapshot(); + } + @POST @Operation( summary = "Add new peer address", diff --git a/src/main/java/org/qortal/network/Network.java b/src/main/java/org/qortal/network/Network.java index c25aaf1e..92f27a73 100644 --- a/src/main/java/org/qortal/network/Network.java +++ b/src/main/java/org/qortal/network/Network.java @@ -56,6 +56,7 @@ import org.qortal.repository.Repository; import org.qortal.repository.RepositoryManager; import org.qortal.settings.Settings; import org.qortal.utils.ExecuteProduceConsume; +import org.qortal.utils.ExecuteProduceConsume.StatsSnapshot; import org.qortal.utils.NTP; // For managing peers @@ -199,6 +200,10 @@ public class Network { return this.maxMessageSize; } + public StatsSnapshot getStatsSnapshot() { + return this.networkEPC.getStatsSnapshot(); + } + // Peer lists public List getConnectedPeers() { diff --git a/src/main/java/org/qortal/utils/ExecuteProduceConsume.java b/src/main/java/org/qortal/utils/ExecuteProduceConsume.java index 451a616c..4fa35ee9 100644 --- a/src/main/java/org/qortal/utils/ExecuteProduceConsume.java +++ b/src/main/java/org/qortal/utils/ExecuteProduceConsume.java @@ -5,11 +5,26 @@ import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public abstract class ExecuteProduceConsume implements Runnable { + @XmlAccessorType(XmlAccessType.FIELD) + public static class StatsSnapshot { + public int activeThreadCount = 0; + public int greatestActiveThreadCount = 0; + public int consumerCount = 0; + public int tasksProduced = 0; + public int tasksConsumed = 0; + + public StatsSnapshot() { + } + } + private final String className; private final Logger logger; @@ -51,28 +66,18 @@ public abstract class ExecuteProduceConsume implements Runnable { return this.executor.awaitTermination(timeout, TimeUnit.MILLISECONDS); } - public int getActiveThreadCount() { - synchronized (this) { - return this.activeThreadCount; - } - } + public StatsSnapshot getStatsSnapshot() { + StatsSnapshot snapshot = new StatsSnapshot(); - public int getGreatestActiveThreadCount() { synchronized (this) { - return this.greatestActiveThreadCount; + snapshot.activeThreadCount = this.activeThreadCount; + snapshot.greatestActiveThreadCount = this.greatestActiveThreadCount; + snapshot.consumerCount = this.consumerCount; + snapshot.tasksProduced = this.tasksProduced; + snapshot.tasksConsumed = this.tasksConsumed; } - } - public int getTasksProduced() { - synchronized (this) { - return this.tasksProduced; - } - } - - public int getTasksConsumed() { - synchronized (this) { - return this.tasksConsumed; - } + return snapshot; } /** diff --git a/src/test/java/org/qortal/test/EPCTests.java b/src/test/java/org/qortal/test/EPCTests.java index 1a77ba6d..d03a787c 100644 --- a/src/test/java/org/qortal/test/EPCTests.java +++ b/src/test/java/org/qortal/test/EPCTests.java @@ -11,6 +11,7 @@ import java.util.concurrent.TimeUnit; import org.junit.Test; import org.qortal.utils.ExecuteProduceConsume; +import org.qortal.utils.ExecuteProduceConsume.StatsSnapshot; public class EPCTests { @@ -60,13 +61,12 @@ public class EPCTests { ScheduledExecutorService statusExecutor = Executors.newSingleThreadScheduledExecutor(); statusExecutor.scheduleAtFixedRate(() -> { - synchronized (testEPC) { - final long seconds = (System.currentTimeMillis() - start) / 1000L; - System.out.println(String.format("After %d second%s, active threads: %d, greatest thread count: %d, tasks produced: %d, tasks consumed: %d", - seconds, (seconds != 1 ? "s" : ""), - testEPC.getActiveThreadCount(), testEPC.getGreatestActiveThreadCount(), - testEPC.getTasksProduced(), testEPC.getTasksConsumed())); - } + StatsSnapshot snapshot = testEPC.getStatsSnapshot(); + final long seconds = (System.currentTimeMillis() - start) / 1000L; + System.out.println(String.format("After %d second%s, active threads: %d, greatest thread count: %d, tasks produced: %d, tasks consumed: %d", + seconds, (seconds != 1 ? "s" : ""), + snapshot.activeThreadCount, snapshot.greatestActiveThreadCount, + snapshot.tasksProduced, snapshot.tasksConsumed)); }, 1L, 1L, TimeUnit.SECONDS); // Let it run for a minute @@ -78,10 +78,10 @@ public class EPCTests { final long after = System.currentTimeMillis(); System.out.println(String.format("Shutdown took %d milliseconds", after - before)); - System.out.println(String.format("Greatest thread count: %d", testEPC.getGreatestActiveThreadCount())); - System.out.println(String.format("Tasks produced: %d", testEPC.getTasksProduced())); - System.out.println(String.format("Tasks consumed: %d", testEPC.getTasksConsumed())); + StatsSnapshot snapshot = testEPC.getStatsSnapshot(); + System.out.println(String.format("Greatest thread count: %d, tasks produced: %d, tasks consumed: %d", + snapshot.greatestActiveThreadCount, snapshot.tasksProduced, snapshot.tasksConsumed)); } @Test