From 02328bd5d4eed44c0aa2e8fb108b5a6cf673edda Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 29 Apr 2025 08:59:30 -0400 Subject: [PATCH] Add UDP announce rate stat --- CHANGES.txt | 4 ++++ src/java/net/i2p/zzzot/UDPHandler.java | 25 +++++++++++++++++++++ src/java/net/i2p/zzzot/ZzzOT.java | 2 +- src/java/net/i2p/zzzot/ZzzOTController.java | 14 ++++++++++++ src/jsp/index.jsp | 16 +++++++++++-- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7958344..c5c53aa 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -4,7 +4,11 @@ s/ _destCache; + private final AtomicInteger _announces = new AtomicInteger(); private volatile boolean _running; // The listen port. @@ -70,6 +73,7 @@ public class UDPHandler implements I2PSessionMuxedListener { // keep it short, we should have the leaseset private final long LOOKUP_TIMEOUT = 1000; private final long CLEAN_TIME; + private final long STAT_TIME = 2*60*1000; private static final byte[] INVALID = DataHelper.getUTF8("Invalid connection ID"); private static final byte[] PROTOCOL = DataHelper.getUTF8("Bad protocol"); private static final byte[] SCRAPE = DataHelper.getUTF8("Scrape unsupported"); @@ -81,6 +85,7 @@ public class UDPHandler implements I2PSessionMuxedListener { _zzzot = zzzot; CLEAN_TIME = (zzzot.getTorrents().getUDPLifetime() + 60) * 1000; PORT = port; + _cleaner = new Cleaner(); sipk0 = ctx.random().nextLong(); sipk1 = ctx.random().nextLong(); // the highest-traffic zzzot is running about 3000 announces/minute, @@ -91,6 +96,8 @@ public class UDPHandler implements I2PSessionMuxedListener { public void start() { _running = true; (new I2PAppThread(new Waiter(), "ZzzOT UDP startup", true)).start(); + long[] r = new long[] { 5*60*1000 }; + _context.statManager().createRequiredRateStat("plugin.zzzot.announces.udp", "UDP announces per minute", "Plugins", r); } /** @@ -98,6 +105,9 @@ public class UDPHandler implements I2PSessionMuxedListener { */ public void stop() { _running = false; + _cleaner.cancel(); + _context.statManager().removeRateStat("plugin.zzzot.announces.udp"); + _announces.set(0); } private class Waiter implements Runnable { @@ -112,6 +122,7 @@ public class UDPHandler implements I2PSessionMuxedListener { I2PSession session = sessions.get(0); session.addMuxedSessionListener(UDPHandler.this, I2PSession.PROTO_DATAGRAM2, PORT); session.addMuxedSessionListener(UDPHandler.this, I2PSession.PROTO_DATAGRAM3, PORT); + _cleaner.schedule(STAT_TIME); if (_log.shouldInfo()) _log.info("got session"); break; @@ -154,6 +165,7 @@ public class UDPHandler implements I2PSessionMuxedListener { public void reportAbuse(I2PSession arg0, int arg1) {} public void disconnected(I2PSession arg0) { + _cleaner.cancel(); } public void errorOccurred(I2PSession arg0, String arg1, Throwable arg2) { @@ -286,6 +298,7 @@ public class UDPHandler implements I2PSessionMuxedListener { Torrents torrents = _zzzot.getTorrents(); Peers peers = torrents.get(ih); if (peers == null && event != EVENT_STOPPED) { + _announces.incrementAndGet(); peers = new Peers(); Peers p2 = torrents.putIfAbsent(ih, peers); if (p2 != null) @@ -433,4 +446,16 @@ public class UDPHandler implements I2PSessionMuxedListener { c = SipHashInline.hash24(sipk0, sipk1, buf); return cid == c; } + + /** + * Update the announce stat and set the announce count to 0 + */ + private class Cleaner extends SimpleTimer2.TimedEvent { + public Cleaner() { super(_context.simpleTimer2()); } + public void timeReached() { + long count = _announces.getAndSet(0); + _context.statManager().addRateData("plugin.zzzot.announces.udp", count / (STAT_TIME / (60*1000L))); + schedule(STAT_TIME); + } + } } diff --git a/src/java/net/i2p/zzzot/ZzzOT.java b/src/java/net/i2p/zzzot/ZzzOT.java index 511e158..66e3222 100644 --- a/src/java/net/i2p/zzzot/ZzzOT.java +++ b/src/java/net/i2p/zzzot/ZzzOT.java @@ -80,7 +80,7 @@ class ZzzOT { void start() { _cleaner.forceReschedule(CLEAN_TIME); long[] r = new long[] { 5*60*1000 }; - _context.statManager().createRequiredRateStat("plugin.zzzot.announces", "Announces per minute", "Plugins", r); + _context.statManager().createRequiredRateStat("plugin.zzzot.announces", "Total announces per minute", "Plugins", r); _context.statManager().createRequiredRateStat("plugin.zzzot.peers", "Number of peers", "Plugins", r); _context.statManager().createRequiredRateStat("plugin.zzzot.torrents", "Number of torrents", "Plugins", r); } diff --git a/src/java/net/i2p/zzzot/ZzzOTController.java b/src/java/net/i2p/zzzot/ZzzOTController.java index 179e333..bd3d736 100644 --- a/src/java/net/i2p/zzzot/ZzzOTController.java +++ b/src/java/net/i2p/zzzot/ZzzOTController.java @@ -180,6 +180,20 @@ public class ZzzOTController implements ClientApp { return r.getAvgOrLifetimeAvg(); } + /** + * @return announces per minute, 0 if not running or UDP not enabled + * @since 0.20.0 + */ + public static double getUDPAnnounceRate() { + RateStat rs = I2PAppContext.getGlobalContext().statManager().getRate("plugin.zzzot.announces.udp"); + if (rs == null) + return 0; + Rate r = rs.getRate(5*60*1000); + if (r == null) + return 0; + return r.getAvgOrLifetimeAvg(); + } + /** * @return false if not running * @since 0.20.0 diff --git a/src/jsp/index.jsp b/src/jsp/index.jsp index ee1a6a5..b38c00d 100644 --- a/src/jsp/index.jsp +++ b/src/jsp/index.jsp @@ -20,19 +20,31 @@

Torrents: <%=torrents.size()%>
Peers: <%=torrents.countPeers()%>
-Announce Rate: <%=String.format(java.util.Locale.US, "%.1f", ZzzOTController.getAnnounceRate())%> / minute
+<% + boolean udp = ZzzOTController.isUDPEnabled(); + if (udp) { +%> + Total Announce Rate: +<% + } else { +%> + Announce Rate: +<% + } +%> +<%=String.format(java.util.Locale.US, "%.1f", ZzzOTController.getAnnounceRate())%> / minute
Announce Interval: <%=torrents.getInterval() / 60%> minutes
<% String host = ZzzOTController.b32(); if (host != null) { %>Announce URL: http://<%=host%>/a
<% } - boolean udp = ZzzOTController.isUDPEnabled(); %> UDP Announce Support: <%=udp ? "yes" : "no"%>
<% if (udp) { %> + UDP Announce Rate: <%=String.format(java.util.Locale.US, "%.1f", ZzzOTController.getUDPAnnounceRate())%> / minute
UDP Connection Lifetime: <%=torrents.getUDPLifetime() / 60%> minutes
<% if (host != null) {