Search in sources :

Example 11 with Rate

use of net.i2p.stat.Rate 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;
}
Also used : RateStat(net.i2p.stat.RateStat) StringTokenizer(java.util.StringTokenizer) Rate(net.i2p.stat.Rate) HashSet(java.util.HashSet)

Example 12 with Rate

use of net.i2p.stat.Rate 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);
}
Also used : RateStat(net.i2p.stat.RateStat) Rate(net.i2p.stat.Rate) RateAverages(net.i2p.stat.RateAverages)

Example 13 with Rate

use of net.i2p.stat.Rate 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;
}
Also used : RateStat(net.i2p.stat.RateStat) Rate(net.i2p.stat.Rate) RateAverages(net.i2p.stat.RateAverages)

Example 14 with Rate

use of net.i2p.stat.Rate 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;
}
Also used : RateStat(net.i2p.stat.RateStat) Rate(net.i2p.stat.Rate) TunnelInfo(net.i2p.router.TunnelInfo)

Example 15 with Rate

use of net.i2p.stat.Rate in project i2p.i2p by i2p.

the class BuildExecutor method allowed.

private int allowed() {
    CommSystemFacade csf = _context.commSystem();
    if (csf.getStatus() == Status.DISCONNECTED)
        return 0;
    if (csf.isDummy() && csf.getEstablished().size() <= 0)
        return 0;
    int maxKBps = _context.bandwidthLimiter().getOutboundKBytesPerSecond();
    // Max. 1 concurrent build per 6 KB/s outbound
    int allowed = maxKBps / 6;
    RateStat rs = _context.statManager().getRate("tunnel.buildRequestTime");
    if (rs != null) {
        Rate r = rs.getRate(60 * 1000);
        double avg = 0;
        if (r != null)
            avg = r.getAverageValue();
        if (avg <= 0)
            avg = rs.getLifetimeAverageValue();
        if (avg > 1) {
            // If builds take more than 75 ms, start throttling
            int throttle = (int) (75 * MAX_CONCURRENT_BUILDS / avg);
            if (throttle < allowed) {
                allowed = throttle;
                if (allowed < MAX_CONCURRENT_BUILDS && _log.shouldLog(Log.INFO))
                    _log.info("Throttling max builds to " + allowed + " due to avg build time of " + ((int) avg) + " ms");
            }
        }
    }
    if (allowed < 2)
        // Never choke below 2 builds (but congestion may)
        allowed = 2;
    else if (allowed > MAX_CONCURRENT_BUILDS)
        allowed = MAX_CONCURRENT_BUILDS;
    allowed = _context.getProperty("router.tunnelConcurrentBuilds", allowed);
    // expire any REALLY old requests
    long expireBefore = _context.clock().now() + 10 * 60 * 1000 - BuildRequestor.REQUEST_TIMEOUT - GRACE_PERIOD;
    for (Iterator<PooledTunnelCreatorConfig> iter = _recentlyBuildingMap.values().iterator(); iter.hasNext(); ) {
        PooledTunnelCreatorConfig cfg = iter.next();
        if (cfg.getExpiration() <= expireBefore) {
            iter.remove();
        }
    }
    // expire any old requests
    List<PooledTunnelCreatorConfig> expired = null;
    int concurrent = 0;
    // Todo: Make expiration variable
    expireBefore = _context.clock().now() + 10 * 60 * 1000 - BuildRequestor.REQUEST_TIMEOUT;
    for (Iterator<PooledTunnelCreatorConfig> iter = _currentlyBuildingMap.values().iterator(); iter.hasNext(); ) {
        PooledTunnelCreatorConfig cfg = iter.next();
        if (cfg.getExpiration() <= expireBefore) {
            // save them for another minute
            _recentlyBuildingMap.putIfAbsent(Long.valueOf(cfg.getReplyMessageId()), cfg);
            iter.remove();
            if (expired == null)
                expired = new ArrayList<PooledTunnelCreatorConfig>();
            expired.add(cfg);
        }
    }
    concurrent = _currentlyBuildingMap.size();
    allowed -= concurrent;
    if (expired != null) {
        for (int i = 0; i < expired.size(); i++) {
            PooledTunnelCreatorConfig cfg = expired.get(i);
            if (_log.shouldLog(Log.INFO))
                _log.info("Timed out waiting for reply asking for " + cfg);
            // Also note the fact that this tunnel request timed out in the peers' profiles.
            for (int iPeer = 0; iPeer < cfg.getLength(); iPeer++) {
                // Look up peer
                Hash peer = cfg.getPeer(iPeer);
                // Avoid recording ourselves
                if (peer.equals(_context.routerHash()))
                    continue;
                // Look up routerInfo
                RouterInfo ri = _context.netDb().lookupRouterInfoLocally(peer);
                // Default and detect bandwidth tier
                String bwTier = "Unknown";
                // Returns "Unknown" if none recognized
                if (ri != null)
                    bwTier = ri.getBandwidthTier();
                // Record that a peer of the given tier expired
                _context.statManager().addRateData("tunnel.tierExpire" + bwTier, 1);
                didNotReply(cfg.getReplyMessageId(), peer);
                // Blame everybody since we don't know whose fault it is.
                // (it could be our exploratory tunnel's fault too...)
                _context.profileManager().tunnelTimedOut(peer);
            }
            TunnelPool pool = cfg.getTunnelPool();
            if (pool != null)
                pool.buildComplete(cfg);
            if (cfg.getDestination() == null) {
                _context.statManager().addRateData("tunnel.buildExploratoryExpire", 1);
            // if (cfg.isInbound())
            // _context.statManager().addRateData("tunnel.buildExploratoryExpireIB", 1);
            // else
            // _context.statManager().addRateData("tunnel.buildExploratoryExpireOB", 1);
            } else {
                _context.statManager().addRateData("tunnel.buildClientExpire", 1);
            // if (cfg.isInbound())
            // _context.statManager().addRateData("tunnel.buildClientExpireIB", 1);
            // else
            // _context.statManager().addRateData("tunnel.buildClientExpireOB", 1);
            }
        }
    }
    _context.statManager().addRateData("tunnel.concurrentBuilds", concurrent, 0);
    long lag = _context.jobQueue().getMaxLag();
    if ((lag > 2000) && (_context.router().getUptime() > 5 * 60 * 1000)) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Too lagged [" + lag + "], don't allow building");
        _context.statManager().addRateData("tunnel.concurrentBuildsLagged", concurrent, lag);
        // if we have a job heavily blocking our jobqueue, ssllloowww dddooowwwnnn
        return 0;
    }
    return allowed;
}
Also used : CommSystemFacade(net.i2p.router.CommSystemFacade) Rate(net.i2p.stat.Rate) RouterInfo(net.i2p.data.router.RouterInfo) ArrayList(java.util.ArrayList) Hash(net.i2p.data.Hash) RateStat(net.i2p.stat.RateStat)

Aggregations

Rate (net.i2p.stat.Rate)29 RateStat (net.i2p.stat.RateStat)24 RateAverages (net.i2p.stat.RateAverages)6 Hash (net.i2p.data.Hash)5 RouterInfo (net.i2p.data.router.RouterInfo)5 PeerProfile (net.i2p.router.peermanager.PeerProfile)4 TreeSet (java.util.TreeSet)3 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 DBHistory (net.i2p.router.peermanager.DBHistory)2 HashSet (java.util.HashSet)1 StringTokenizer (java.util.StringTokenizer)1 RouterAddress (net.i2p.data.router.RouterAddress)1 CommSystemFacade (net.i2p.router.CommSystemFacade)1 RouterContext (net.i2p.router.RouterContext)1 TunnelInfo (net.i2p.router.TunnelInfo)1 MaskedIPSet (net.i2p.router.util.MaskedIPSet)1 SummaryListener (net.i2p.router.web.SummaryListener)1 FrequencyStat (net.i2p.stat.FrequencyStat)1 ConvertToHash (net.i2p.util.ConvertToHash)1