use of net.i2p.stat.RateStat in project i2p.i2p by i2p.
the class RouterWatchdog method monitorRouter.
public void monitorRouter() {
boolean ok = verifyJobQueueLiveliness();
// If we aren't connected to the network that's why there's nobody to talk to
long netErrors = 0;
if (_context.commSystem().getStatus() == Status.DISCONNECTED) {
netErrors = 10;
} else {
RateStat rs = _context.statManager().getRate("udp.sendException");
if (rs != null) {
Rate r = rs.getRate(60 * 1000);
if (r != null)
netErrors = r.getLastEventCount();
}
}
ok = ok && (verifyClientLiveliness() || netErrors >= 5);
if (ok) {
_consecutiveErrors = 0;
} else {
_consecutiveErrors++;
dumpStatus();
if (shutdownOnHang()) {
_log.log(Log.CRIT, "Router hung! Restart forced by watchdog!");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException ie) {
}
// halt and not system.exit, since some of the shutdown hooks might be misbehaving
Runtime.getRuntime().halt(Router.EXIT_HARD_RESTART);
}
}
}
use of net.i2p.stat.RateStat in project i2p.i2p by i2p.
the class StatSummarizer method parseSpecs.
/**
* @param specs statName.period,statName.period,statName.period
* @return list of Rate objects
* @since public since 0.9.33, was package private
*/
public Set<Rate> parseSpecs(String specs) {
if (specs == null)
return Collections.emptySet();
StringTokenizer tok = new StringTokenizer(specs, ",");
Set<Rate> rv = new HashSet<Rate>();
while (tok.hasMoreTokens()) {
String spec = tok.nextToken();
int split = spec.lastIndexOf('.');
if ((split <= 0) || (split + 1 >= spec.length()))
continue;
String name = spec.substring(0, split);
String per = spec.substring(split + 1);
long period = -1;
try {
period = Long.parseLong(per);
RateStat rs = _context.statManager().getRate(name);
if (rs != null) {
Rate r = rs.getRate(period);
if (r != null)
rv.add(r);
}
} catch (NumberFormatException nfe) {
}
}
return rv;
}
use of net.i2p.stat.RateStat 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.RateStat 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.RateStat in project i2p.i2p by i2p.
the class TunnelPool method countHowManyToBuild.
/**
* Gather the data to see how many tunnels to build, and then actually compute that value (delegated to
* the countHowManyToBuild function below)
*/
int countHowManyToBuild() {
if (!isAlive()) {
return 0;
}
int wanted = getAdjustedTotalQuantity();
boolean allowZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) <= 0);
/**
* This algorithm builds based on the previous average length of time it takes
* to build a tunnel. This average is kept in the _buildRateName stat.
* It is a separate stat for each type of pool, since in and out building use different methods,
* as do exploratory and client pools,
* and each pool can have separate length and length variance settings.
* We add one minute to the stat for safety (two for exploratory tunnels).
*
* We linearly increase the number of builds per expiring tunnel from
* 1 to PANIC_FACTOR as the time-to-expire gets shorter.
*
* The stat will be 0 for first 10m of uptime so we will use the older, conservative algorithm
* below instead. This algorithm will take about 30m of uptime to settle down.
* Or, if we are building more than 33% of the time something is seriously wrong,
* we also use the conservative algorithm instead
*/
final String rateName = buildRateName();
// Compute the average time it takes us to build a single tunnel of this type.
int avg = 0;
RateStat rs = _context.statManager().getRate(rateName);
if (rs == null) {
// Create the RateStat here rather than at the top because
// the user could change the length settings while running
_context.statManager().createRequiredRateStat(rateName, "Tunnel Build Frequency", "Tunnels", new long[] { TUNNEL_LIFETIME });
rs = _context.statManager().getRate(rateName);
}
if (rs != null) {
Rate r = rs.getRate(TUNNEL_LIFETIME);
if (r != null)
avg = (int) (TUNNEL_LIFETIME * r.getAverageValue() / wanted);
}
if (avg > 0 && avg < TUNNEL_LIFETIME / 3) {
// if we're taking less than 200s per tunnel to build
// how many builds to kick off when time gets short
final int PANIC_FACTOR = 4;
// one minute safety factor
avg += 60 * 1000;
if (_settings.isExploratory())
// two minute safety factor
avg += 60 * 1000;
long now = _context.clock().now();
int expireSoon = 0;
int expireLater = 0;
int[] expireTime;
int fallback = 0;
synchronized (_tunnels) {
expireTime = new int[_tunnels.size()];
for (int i = 0; i < _tunnels.size(); i++) {
TunnelInfo info = _tunnels.get(i);
if (allowZeroHop || (info.getLength() > 1)) {
int timeToExpire = (int) (info.getExpiration() - now);
if (timeToExpire > 0 && timeToExpire < avg) {
expireTime[expireSoon++] = timeToExpire;
} else {
expireLater++;
}
} else if (info.getExpiration() - now > avg) {
fallback++;
}
}
}
int inProgress;
synchronized (_inProgress) {
inProgress = _inProgress.size();
}
int remainingWanted = (wanted - expireLater) - inProgress;
if (allowZeroHop)
remainingWanted -= fallback;
int rv = 0;
int latesttime = 0;
if (remainingWanted > 0) {
if (remainingWanted > expireSoon) {
// for tunnels completely missing
rv = PANIC_FACTOR * (remainingWanted - expireSoon);
remainingWanted = expireSoon;
}
// the other ones are extras
for (int i = 0; i < remainingWanted; i++) {
int latestidx = 0;
// given the small size of the array this is efficient enough
for (int j = 0; j < expireSoon; j++) {
if (expireTime[j] > latesttime) {
latesttime = expireTime[j];
latestidx = j;
}
}
expireTime[latestidx] = 0;
if (latesttime > avg / 2)
rv += 1;
else
rv += 2 + ((PANIC_FACTOR - 2) * (((avg / 2) - latesttime) / (avg / 2)));
}
}
if (rv > 0 && _log.shouldLog(Log.DEBUG))
_log.debug("New Count: rv: " + rv + " allow? " + allowZeroHop + " avg " + avg + " latesttime " + latesttime + " soon " + expireSoon + " later " + expireLater + " std " + wanted + " inProgress " + inProgress + " fallback " + fallback + " for " + toString());
_context.statManager().addRateData(rateName, rv + inProgress, 0);
return rv;
}
// fixed, conservative algorithm - starts building 3 1/2 - 6m before expiration
// (210 or 270s) + (0..90s random)
// + _settings.getRebuildPeriod() + _expireSkew;
long expireAfter = _context.clock().now() + _expireSkew;
int expire30s = 0;
int expire90s = 0;
int expire150s = 0;
int expire210s = 0;
int expire270s = 0;
int expireLater = 0;
int fallback = 0;
synchronized (_tunnels) {
for (int i = 0; i < _tunnels.size(); i++) {
TunnelInfo info = _tunnels.get(i);
if (allowZeroHop || (info.getLength() > 1)) {
long timeToExpire = info.getExpiration() - expireAfter;
if (timeToExpire <= 0) {
// consider it unusable
} else if (timeToExpire <= 30 * 1000) {
expire30s++;
} else if (timeToExpire <= 90 * 1000) {
expire90s++;
} else if (timeToExpire <= 150 * 1000) {
expire150s++;
} else if (timeToExpire <= 210 * 1000) {
expire210s++;
} else if (timeToExpire <= 270 * 1000) {
expire270s++;
} else {
expireLater++;
}
} else if (info.getExpiration() > expireAfter) {
fallback++;
}
}
}
int inProgress = 0;
synchronized (_inProgress) {
inProgress = _inProgress.size();
for (int i = 0; i < inProgress; i++) {
PooledTunnelCreatorConfig cfg = _inProgress.get(i);
if (cfg.getLength() <= 1)
fallback++;
}
}
int rv = countHowManyToBuild(allowZeroHop, expire30s, expire90s, expire150s, expire210s, expire270s, expireLater, wanted, inProgress, fallback);
_context.statManager().addRateData(rateName, (rv > 0 || inProgress > 0) ? 1 : 0, 0);
return rv;
}
Aggregations