Add UDP announce rate stat

This commit is contained in:
zzz
2025-04-29 08:59:30 -04:00
parent 6bc7821f1b
commit 02328bd5d4
5 changed files with 58 additions and 3 deletions

View File

@ -4,7 +4,11 @@
s/<Ref id=/<Ref refid=/g
- Add interval to stats page
- Add stats to I2P stats subsystem
- Show announce URLs on stats page
- Remove ElGamal support
- Remove support for non-compact announce replies
- Reduce memory usage
- Remove seedless support
2024-04-07 [0.19.0]
- Disable full scrape by default

View File

@ -22,6 +22,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
@ -51,8 +52,10 @@ public class UDPHandler implements I2PSessionMuxedListener {
private final Log _log;
private final I2PTunnel _tunnel;
private final ZzzOT _zzzot;
private final Cleaner _cleaner;
private final long sipk0, sipk1;
private final Map<Hash, Destination> _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);
}
}
}

View File

@ -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);
}

View File

@ -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

View File

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