use of net.i2p.stat.RateAverages in project i2p.i2p by i2p.
the class ProfileOrganizerRenderer method renderStatusHTML.
/**
* @param mode 0 = high cap; 1 = all; 2 = floodfill
*/
public void renderStatusHTML(Writer out, int mode) throws IOException {
boolean full = mode == 1;
Set<Hash> peers = _organizer.selectAllPeers();
long now = _context.clock().now();
long hideBefore = now - 90 * 60 * 1000;
Set<PeerProfile> order = new TreeSet<PeerProfile>(mode == 2 ? new HashComparator() : new ProfileComparator());
int older = 0;
int standard = 0;
for (Hash peer : peers) {
if (_organizer.getUs().equals(peer))
continue;
PeerProfile prof = _organizer.getProfileNonblocking(peer);
if (prof == null)
continue;
if (mode == 2) {
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null && info.getCapabilities().indexOf('f') >= 0)
order.add(prof);
continue;
}
if (prof.getLastSendSuccessful() <= hideBefore) {
older++;
continue;
}
if ((!full) && !_organizer.isHighCapacity(peer)) {
standard++;
continue;
}
order.add(prof);
}
int fast = 0;
int reliable = 0;
int integrated = 0;
StringBuilder buf = new StringBuilder(16 * 1024);
// //
if (mode < 2) {
// buf.append("<h2>").append(_t("Peer Profiles")).append("</h2>\n<p>");
buf.append("<p id=\"profiles_overview\" class=\"infohelp\">");
buf.append(ngettext("Showing 1 recent profile.", "Showing {0} recent profiles.", order.size())).append('\n');
if (older > 0)
buf.append(ngettext("Hiding 1 older profile.", "Hiding {0} older profiles.", older)).append('\n');
if (standard > 0)
buf.append("<a href=\"/profiles?f=1\">").append(ngettext("Hiding 1 standard profile.", "Hiding {0} standard profiles.", standard)).append("</a>\n");
buf.append("</p>");
buf.append("<div class=\"widescroll\"><table id=\"profilelist\">");
buf.append("<tr>");
buf.append("<th>").append(_t("Peer")).append("</th>");
buf.append("<th>").append(_t("Groups")).append("</th>");
buf.append("<th>").append(_t("Caps")).append("</th>");
buf.append("<th>").append(_t("Version")).append("</th>");
buf.append("<th>").append(_t("Speed")).append("</th>");
buf.append("<th>").append(_t("Capacity")).append("</th>");
buf.append("<th>").append(_t("Integration")).append("</th>");
buf.append("<th>").append(_t("Status")).append("</th>");
buf.append("<th>").append(_t("View/Edit")).append("</th>");
buf.append("</tr>");
int prevTier = 1;
for (PeerProfile prof : order) {
Hash peer = prof.getPeer();
int tier = 0;
boolean isIntegrated = false;
if (_organizer.isFast(peer)) {
tier = 1;
fast++;
reliable++;
} else if (_organizer.isHighCapacity(peer)) {
tier = 2;
reliable++;
} else if (_organizer.isFailing(peer)) {
} else {
tier = 3;
}
if (_organizer.isWellIntegrated(peer)) {
isIntegrated = true;
integrated++;
}
if (tier != prevTier)
buf.append("<tr><td colspan=\"9\"><hr></td></tr>\n");
prevTier = tier;
buf.append("<tr><td align=\"center\" nowrap>");
buf.append(_context.commSystem().renderPeerHTML(peer));
// debug
// if(prof.getIsExpandedDB())
// buf.append(" ** ");
buf.append("</td><td align=\"center\">");
switch(tier) {
case 1:
buf.append(_t("Fast, High Capacity"));
break;
case 2:
buf.append(_t("High Capacity"));
break;
case 3:
buf.append(_t("Standard"));
break;
default:
buf.append(_t("Failing"));
break;
}
if (isIntegrated)
buf.append(", ").append(_t("Integrated"));
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null) {
// prevent HTML injection in the caps and version
buf.append("<td align=\"right\">").append(DataHelper.stripHTML(info.getCapabilities()));
} else {
buf.append("<td align=\"right\"><i>").append(_t("unknown")).append("</i></td>");
}
buf.append("<td align=\"right\">");
String v = info != null ? info.getOption("router.version") : null;
if (v != null)
buf.append(DataHelper.stripHTML(v));
buf.append("</td><td align=\"right\">").append(num(prof.getSpeedValue()));
long bonus = prof.getSpeedBonus();
if (bonus != 0) {
if (bonus > 0)
buf.append(" (+");
else
buf.append(" (");
buf.append(bonus).append(')');
}
buf.append("</td><td align=\"right\">").append(num(prof.getCapacityValue()));
bonus = prof.getCapacityBonus();
if (bonus != 0) {
if (bonus > 0)
buf.append(" (+");
else
buf.append(" (");
buf.append(bonus).append(')');
}
buf.append("</td><td align=\"right\">").append(num(prof.getIntegrationValue()));
buf.append("</td><td align=\"center\">");
boolean ok = true;
if (_context.banlist().isBanlisted(peer)) {
buf.append(_t("Banned"));
ok = false;
}
if (prof.getIsFailing()) {
buf.append(' ').append(_t("Failing"));
ok = false;
}
if (_context.commSystem().wasUnreachable(peer)) {
buf.append(' ').append(_t("Unreachable"));
ok = false;
}
RateAverages ra = RateAverages.getTemp();
Rate failed = prof.getTunnelHistory().getFailedRate().getRate(30 * 60 * 1000);
long fails = failed.computeAverages(ra, false).getTotalEventCount();
if (ok && fails == 0) {
buf.append(_t("OK"));
} else if (fails > 0) {
Rate accepted = prof.getTunnelCreateResponseTime().getRate(30 * 60 * 1000);
long total = fails + accepted.computeAverages(ra, false).getTotalEventCount();
if (// hide if < 10%
total / fails <= 10)
buf.append(' ').append(fails).append('/').append(total).append(' ').append(_t("Test Fails"));
}
buf.append(" </td>");
// buf.append("<td nowrap align=\"center\"><a target=\"_blank\" href=\"dumpprofile.jsp?peer=")
// .append(peer.toBase64().substring(0,6)).append("\">").append(_t("profile")).append("</a>");
buf.append("<td nowrap align=\"center\"><a href=\"viewprofile?peer=").append(peer.toBase64()).append("\">").append(_t("profile")).append("</a>");
buf.append(" <a title=\"").append(_t("Configure peer")).append("\" href=\"configpeer?peer=").append(peer.toBase64()).append("\">+-</a></td>\n");
buf.append("</tr>");
// let's not build the whole page in memory (~500 bytes per peer)
out.write(buf.toString());
buf.setLength(0);
}
buf.append("</table></div>");
// //
// // don't bother reindenting
// //
} else {
// buf.append("<h2><a name=\"flood\"></a>").append(_t("Floodfill and Integrated Peers"))
// .append(" (").append(integratedPeers.size()).append(")</h2>\n");
buf.append("<div class=\"widescroll\"><table id=\"floodfills\">");
buf.append("<tr class=\"smallhead\">");
buf.append("<th>").append(_t("Peer")).append("</th>");
buf.append("<th>").append(_t("Caps")).append("</th>");
buf.append("<th>").append(_t("Integ. Value")).append("</th>");
buf.append("<th>").append(_t("Last Heard About")).append("</th>");
buf.append("<th>").append(_t("Last Heard From")).append("</th>");
buf.append("<th>").append(_t("Last Good Send")).append("</th>");
buf.append("<th>").append(_t("Last Bad Send")).append("</th>");
buf.append("<th>").append(_t("10m Resp. Time")).append("</th>");
buf.append("<th>").append(_t("1h Resp. Time")).append("</th>");
buf.append("<th>").append(_t("1d Resp. Time")).append("</th>");
buf.append("<th>").append(_t("Last Good Lookup")).append("</th>");
buf.append("<th>").append(_t("Last Bad Lookup")).append("</th>");
buf.append("<th>").append(_t("Last Good Store")).append("</th>");
buf.append("<th>").append(_t("Last Bad Store")).append("</th>");
buf.append("<th>").append(_t("1h Fail Rate")).append("</th>");
buf.append("<th>").append(_t("1d Fail Rate")).append("</th>");
buf.append("</tr>");
RateAverages ra = RateAverages.getTemp();
for (PeerProfile prof : order) {
Hash peer = prof.getPeer();
buf.append("<tr><td align=\"center\" nowrap>");
buf.append(_context.commSystem().renderPeerHTML(peer));
buf.append("</td>");
RouterInfo info = _context.netDb().lookupRouterInfoLocally(peer);
if (info != null)
buf.append("<td align=\"center\">").append(DataHelper.stripHTML(info.getCapabilities())).append("</td>");
else
buf.append("<td> </td>");
buf.append("<td align=\"right\">").append(num(prof.getIntegrationValue())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, prof.getLastHeardAbout())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, prof.getLastHeardFrom())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, prof.getLastSendSuccessful())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, prof.getLastSendFailed())).append("</td>");
buf.append("<td align=\"right\">").append(avg(prof, 10 * 60 * 1000l, ra)).append("</td>");
buf.append("<td align=\"right\">").append(avg(prof, 60 * 60 * 1000l, ra)).append("</td>");
buf.append("<td align=\"right\">").append(avg(prof, 24 * 60 * 60 * 1000l, ra)).append("</td>");
DBHistory dbh = prof.getDBHistory();
if (dbh != null) {
buf.append("<td align=\"right\">").append(formatInterval(now, dbh.getLastLookupSuccessful())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, dbh.getLastLookupFailed())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, dbh.getLastStoreSuccessful())).append("</td>");
buf.append("<td align=\"right\">").append(formatInterval(now, dbh.getLastStoreFailed())).append("</td>");
buf.append("<td align=\"right\">").append(davg(dbh, 60 * 60 * 1000l, ra)).append("</td>");
buf.append("<td align=\"right\">").append(davg(dbh, 24 * 60 * 60 * 1000l, ra)).append("</td>");
} else {
for (int i = 0; i < 6; i++) buf.append("<td align=\"right\">").append(_t(NA));
}
buf.append("</tr>\n");
}
buf.append("</table></div>");
// //
// // don't bother reindenting
// //
}
if (mode < 2) {
buf.append("<h3 class=\"tabletitle\">").append(_t("Thresholds")).append("</h3>\n").append("<table id=\"thresholds\"><tbody>").append("<tr><th><b>").append(_t("Speed")).append(": </b>").append(num(_organizer.getSpeedThreshold())).append("</th><th><b>").append(_t("Capacity")).append(": </b>").append(num(_organizer.getCapacityThreshold())).append("</th><th><b>").append(_t("Integration")).append(": </b>").append(num(_organizer.getIntegrationThreshold())).append("</th></tr><tr><td>").append(fast).append(' ').append(_t("fast peers")).append("</td><td>").append(reliable).append(' ').append(_t("high capacity peers")).append("</td><td>").append(integrated).append(' ').append(_t(" well integrated peers")).append("</td></tr></tbody></table>\n");
buf.append("<h3 class=\"tabletitle\">").append(_t("Definitions")).append("</h3>\n").append("<table id=\"profile_defs\"><tbody>");
buf.append("<tr><td><b>").append(_t("groups")).append(":</b></td><td>").append(_t("as determined by the profile organizer")).append("</td></tr>");
buf.append("<tr><td><b>").append(_t("caps")).append(":</b></td><td>").append(_t("capabilities in the netDb, not used to determine profiles")).append("</td></tr>");
buf.append("<tr id=\"capabilities_key\"><td colspan=\"2\"><table><tbody>");
buf.append("<tr><td> </td>").append("<td><b>B</b></td><td>").append(_t("SSU Testing")).append("</td>").append("<td><b>C</b></td><td>").append(_t("SSU Introducer")).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>f</b></td><td>").append(_t("Floodfill")).append("</td>").append("<td><b>H</b></td><td>").append(_t("Hidden")).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>K</b></td><td>").append(_t("Under {0} shared bandwidth", Router.MIN_BW_L + " KBps")).append("</td>").append("<td><b>L</b></td><td>").append(_t("{0} shared bandwidth", range(Router.MIN_BW_L, Router.MIN_BW_M))).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>M</b></td><td>").append(_t("{0} shared bandwidth", range(Router.MIN_BW_M, Router.MIN_BW_N))).append("</td>").append("<td><b>N</b></td><td>").append(_t("{0} shared bandwidth", range(Router.MIN_BW_N, Router.MIN_BW_O))).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>O</b></td><td>").append(_t("{0} shared bandwidth", range(Router.MIN_BW_O, Router.MIN_BW_P))).append("</td>").append("<td><b>P</b></td><td>").append(_t("{0} shared bandwidth", range(Router.MIN_BW_P, Router.MIN_BW_X))).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>R</b></td><td>").append(_t("Reachable")).append("</td>").append("<td><b>U</b></td><td>").append(_t("Unreachable")).append("</td>").append("<td> </td></tr>");
buf.append("<tr><td> </td>").append("<td><b>X</b></td><td>").append(_t("Over {0} shared bandwidth", Math.round(Router.MIN_BW_X * 1.024f) + " KBps")).append("</td>").append("<td> </td><td> </td><td> </td></tr>");
buf.append("<tr><td> </td><td colspan=\"5\">").append(_t("Note: For P and X bandwidth tiers, O is included for the purpose of backward compatibility in the NetDB.")).append("</tr>");
// profile_defs
buf.append("</tbody></table></td></tr>");
buf.append("<tr><td><b>").append(_t("speed")).append(":</b></td><td>").append(_t("peak throughput (bytes per second) over a 1 minute period that the peer has sustained in a single tunnel")).append("</td></tr>");
buf.append("<tr><td><b>").append(_t("capacity")).append(":</b></td><td>").append(_t("how many tunnels can we ask them to join in an hour?")).append("</td></tr>");
buf.append("<tr><td><b>").append(_t("integration")).append(":</b></td><td>").append(_t("how many new peers have they told us about lately?")).append("</td></tr>");
buf.append("<tr><td><b>").append(_t("status")).append(":</b></td><td>").append(_t("is the peer banned, or unreachable, or failing tunnel tests?")).append("</td></tr>");
// thresholds
buf.append("</tbody></table>\n");
// //
// // don't bother reindenting
// //
}
// mode < 2
out.write(buf.toString());
out.flush();
}
use of net.i2p.stat.RateAverages in project i2p.i2p by i2p.
the class TunnelPool method setLengthOverride.
/**
* Shorten the length when under extreme stress, else clear the override.
* We only do this for exploratory tunnels, since we have to build a fallback
* if we run out. It's much better to have a shorter tunnel than a fallback.
*
* @since 0.8.11
*/
private void setLengthOverride() {
if (!_settings.isExploratory())
return;
int len = _settings.getLength();
if (len > 1) {
RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire");
RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject");
RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess");
if (e != null && r != null && s != null) {
Rate er = e.getRate(10 * 60 * 1000);
Rate rr = r.getRate(10 * 60 * 1000);
Rate sr = s.getRate(10 * 60 * 1000);
if (er != null && rr != null && sr != null) {
RateAverages ra = RateAverages.getTemp();
long ec = er.computeAverages(ra, false).getTotalEventCount();
long rc = rr.computeAverages(ra, false).getTotalEventCount();
long sc = sr.computeAverages(ra, false).getTotalEventCount();
long tot = ec + rc + sc;
if (tot >= BUILD_TRIES_LENGTH_OVERRIDE_1) {
long succ = 1000 * sc / tot;
if (succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_1) {
if (len > 2 && succ <= 1000 / BUILD_TRIES_LENGTH_OVERRIDE_2)
_settings.setLengthOverride(len - 2);
else
_settings.setLengthOverride(len - 1);
return;
}
}
}
}
}
// disable
_settings.setLengthOverride(-1);
}
use of net.i2p.stat.RateAverages in project i2p.i2p by i2p.
the class TunnelPool method getAdjustedTotalQuantity.
/**
* Return settings.getTotalQuantity, unless this is an exploratory tunnel
* AND exploratory build success rate is less than 1/10, AND total settings
* is greater than 1. Otherwise subtract 1 to help prevent congestion collapse,
* and prevent really unintegrated routers from working too hard.
* We only do this for exploratory as different clients could have different
* length settings. Although I guess inbound and outbound exploratory
* could be different too, and inbound is harder...
*
* As of 0.9.19, add more if exploratory and floodfill, as floodfills
* generate a lot of exploratory traffic.
* TODO high-bandwidth non-floodfills do also...
*
* @since 0.8.11
*/
private int getAdjustedTotalQuantity() {
int rv = _settings.getTotalQuantity();
// TODO high-bw non-ff also
if (_settings.isExploratory() && _context.netDb().floodfillEnabled() && _context.router().getUptime() > 5 * 60 * 1000) {
rv += 2;
}
if (_settings.isExploratory() && rv > 1) {
RateStat e = _context.statManager().getRate("tunnel.buildExploratoryExpire");
RateStat r = _context.statManager().getRate("tunnel.buildExploratoryReject");
RateStat s = _context.statManager().getRate("tunnel.buildExploratorySuccess");
if (e != null && r != null && s != null) {
Rate er = e.getRate(10 * 60 * 1000);
Rate rr = r.getRate(10 * 60 * 1000);
Rate sr = s.getRate(10 * 60 * 1000);
if (er != null && rr != null && sr != null) {
RateAverages ra = RateAverages.getTemp();
long ec = er.computeAverages(ra, false).getTotalEventCount();
long rc = rr.computeAverages(ra, false).getTotalEventCount();
long sc = sr.computeAverages(ra, false).getTotalEventCount();
long tot = ec + rc + sc;
if (tot >= BUILD_TRIES_QUANTITY_OVERRIDE) {
if (1000 * sc / tot <= 1000 / BUILD_TRIES_QUANTITY_OVERRIDE)
rv--;
}
}
}
}
if (_settings.isExploratory() && _context.router().getUptime() < STARTUP_TIME) {
// more exploratory during startup, when we are refreshing the netdb RIs
rv++;
}
return rv;
}
use of net.i2p.stat.RateAverages in project i2p.i2p by i2p.
the class CapacityCalculator method estimateCapacity.
/**
* Compute a tunnel accept capacity-per-hour for the given period
* This is perhaps the most critical part of the peer ranking and selection
* system, so adjust with great care and testing to ensure good network
* performance and prevent congestion collapse.
*
* The baseline or "growth factor" is 5.
* Rejects will not reduce the baseline. Failures will.
*
* @param acceptStat Accept counter (1 = 1 accept)
* @param rejectStat Reject counter (1 = 1 reject)
* @param failedStat Failed counter (100 = 1 fail)
*
* Let A = accects, R = rejects, F = fails
* @return estimated and adjusted accepts per hour, for the given period
* which is, more or less, max(0, 5 + (A * (A / (A + 2R))) - (4 * F))
*/
private static double estimateCapacity(RateStat acceptStat, RateStat rejectStat, RateStat failedStat, int period) {
Rate curAccepted = acceptStat.getRate(period);
Rate curRejected = rejectStat.getRate(period);
Rate curFailed = failedStat.getRate(period);
RateAverages ra = RateAverages.getTemp();
double eventCount = 0;
if (curAccepted != null) {
eventCount = curAccepted.computeAverages(ra, false).getTotalEventCount();
// and we don't want everybody to be at zero during times of congestion.
if (eventCount > 0 && curRejected != null) {
long rejected = curRejected.computeAverages(ra, false).getTotalEventCount();
if (rejected > 0)
eventCount *= eventCount / (eventCount + (2 * rejected));
}
}
double stretch = ((double) ESTIMATE_PERIOD) / period;
double val = eventCount * stretch;
// We also don't want to drive everybody's capacity to zero, that isn't helpful.
if (curFailed != null) {
double failed = curFailed.computeAverages(ra, false).getTotalValues();
if (failed > 0) {
// if ( (period <= 10*60*1000) && (curFailed.getCurrentEventCount() > 0) )
// return 0.0d; // their tunnels have failed in the last 0-10 minutes
// else
// .04 = 4.0 / 100.0 adjustment to failed
val -= 0.04 * failed * stretch;
}
}
val += GROWTH_FACTOR;
if (val >= 0) {
return val;
} else {
return 0.0d;
}
}
use of net.i2p.stat.RateAverages in project i2p.i2p by i2p.
the class SybilRenderer method addProfilePoints.
private void addProfilePoints(List<RouterInfo> ris, Map<Hash, Points> points) {
long now = _context.clock().now();
RateAverages ra = RateAverages.getTemp();
for (RouterInfo info : ris) {
Hash h = info.getHash();
if (_context.banlist().isBanlisted(h))
addPoints(points, h, POINTS_BANLIST, "Banlisted");
PeerProfile prof = _context.profileOrganizer().getProfileNonblocking(h);
if (prof != null) {
long heard = prof.getFirstHeardAbout();
if (heard > 0) {
long age = Math.max(now - heard, 1);
if (age < 2 * DAY) {
// (POINTS_NEW / 48) for every hour under 48, max POINTS_NEW
double point = Math.min(POINTS_NEW, (2 * DAY - age) / (2 * DAY / POINTS_NEW));
addPoints(points, h, point, "First heard about: " + _t("{0} ago", DataHelper.formatDuration2(age)));
}
}
DBHistory dbh = prof.getDBHistory();
if (dbh != null) {
RateStat rs = dbh.getFailedLookupRate();
if (rs != null) {
Rate r = rs.getRate(24 * 60 * 60 * 1000);
if (r != null) {
r.computeAverages(ra, false);
if (ra.getTotalEventCount() > 0) {
double avg = 100 * ra.getAverage();
if (avg > 40)
addPoints(points, h, (avg - 40) / 6.0, "Lookup fail rate " + ((int) avg) + '%');
}
}
}
}
}
}
}
Aggregations