ndn-js
Version:
A JavaScript client library for Named Data Networking
156 lines (137 loc) • 5 kB
JavaScript
/**
* Copyright (C) 2018-2019 Regents of the University of California.
* @author: Chavoosh Ghasemi <chghasemi@cs.arizona.edu>
* @author: From https://github.com/named-data/ndn-tools/tree/master/tools/chunks
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
/** @ignore */
var Pipeline = require('./pipeline.js').Pipeline;
/**
* Round Trip Time Estimator
*
* This class implements the "Mean-Deviation" RTT estimator, as discussed in RFC 6298,
* with the modifications to RTO calculation described in RFC 7323 Appendix G.
*
* @param {Object} opts An object that can contain RTT estimator options to overwrite their default
* values. If null is passed then all options will be set to their default values.
*/
var RttEstimator = function RttEstimator(opts)
{
// Options
this.alpha = Pipeline.op("alpha", 0.125, opts); // parameter for RTT estimation
this.beta = Pipeline.op("beta", 0.25, opts); // parameter for RTT variation calculation
this.k = Pipeline.op("k", 8, opts); // factor of RTT variation when calculating RTO
this.initialRto = Pipeline.op("initialRto", 1000, opts); // initial RTO value (ms)
this.minRto = Pipeline.op("minRto", 200, opts); // lower bound of RTO (ms)
this.maxRto = Pipeline.op("maxRto", 20000, opts); // upper bound of RTO (ms)
this.rtoBackoffMultiplier = Pipeline.op("rtoBackoffMultiplier", 2, opts);
this.delayArr = []; // keep track of full delay of each segment to calculate ave jitter
this.sRtt = NaN; // smoothed RTT
this.rttVar = NaN; // RTT variation
this.rto = this.initialRto;
this.rttMin = Number.MAX_VALUE;
this.rttMax = Number.NEGATIVE_INFINITY;
this.rttAvg = 0;
this.nRttSamples = 0;
}
exports.RttEstimator = RttEstimator;
RttEstimator.prototype.clamp = function(v, min, max)
{
if (min < v && v < max) {
return v
} else if (v < min) {
return min
} else if (max < v) {
return max
}
};
/**
* Add a new RTT measurement to the estimator for the given received segment.
*
* @param segNo the segment number of the received segmented Data
* @param rtt the sampled rtt
* @param nExpectedSamples number of expected samples, must be greater than 0.
* It should be set to current number of in-flight Interests. Please
* refer to Appendix G of RFC 7323 for details.
*
* NOTE: Don't take RTT measurement for retransmitted segments
*/
RttEstimator.prototype.addMeasurement = function(segNo, rtt, nExpectedSamples)
{
if (nExpectedSamples <= 0) {
console.log("ERROR: nExpectedSamples is less than or equal to ZERO");
}
if (this.nRttSamples === 0) { // first measurement
this.sRtt = rtt;
this.rttVar = this.sRtt / 2;
this.rto = this.sRtt + this.k * this.rttVar;
}
else {
var alpha = this.alpha / nExpectedSamples;
var beta = this.beta / nExpectedSamples;
this.rttVar = (1 - beta) * this.rttVar + beta * Math.abs(this.sRtt - rtt);
this.sRtt = (1 - alpha) * this.sRtt + alpha * rtt;
this.rto = this.sRtt + this.k * this.rttVar;
}
this.rto = this.clamp(this.rto, this.minRto, this.maxRto);
this.rttAvg = (this.nRttSamples * this.rttAvg + rtt) / (this.nRttSamples + 1);
this.rttMax = Math.max(rtt, this.rttMax);
this.rttMin = Math.min(rtt, this.rttMin);
this.nRttSamples++;
};
RttEstimator.prototype.addDelayMeasurement = function(segNo, delay)
{
this.delayArr[segNo] = delay;
};
/**
* Return average of retrieved segments' RTT variance
*/
RttEstimator.prototype.getAvgJitter = function()
{
var samples = 0;
var jitterAvg = 0;
var jitterLast = 0;
for (var i = 0; i < this.delayArr.length; ++i) {
if (this.delayArr[i] === undefined)
continue;
if (samples > 0) {
jitterAvg = ((jitterAvg * samples) + Math.abs(jitterLast - this.delayArr[i])) / (samples + 1);
}
jitterLast = this.delayArr[i];
samples++;
}
return jitterAvg;
};
RttEstimator.prototype.backoffRto = function()
{
this.rto = this.clamp(this.rto * this.rtobackoffmultiplier, this.minrto, this.maxrto);
};
RttEstimator.prototype.getEstimatedRto = function()
{
return this.rto;
};
RttEstimator.prototype.getMinRtt = function()
{
return this.rttMin;
};
RttEstimator.prototype.getMaxRtt = function()
{
return this.rttMax;
};
RttEstimator.prototype.getAvgRtt = function()
{
return this.rttAvg;
};