recursive SequenceNumberStats; untested

This commit is contained in:
wangyix 2014-08-01 12:00:41 -07:00
parent cdcc6ece04
commit eba07b03e2
2 changed files with 120 additions and 4 deletions

View file

@ -13,22 +13,67 @@
#include <limits>
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength)
SequenceNumberStats::SequenceNumberStats(int statsHistoryLength, int maxRecursion)
: _received(0),
_lastReceivedSequence(0),
_missingSet(),
_stats(),
_lastSenderUUID(),
_statsHistory(statsHistoryLength)
_statsHistory(statsHistoryLength),
_unreasonableTracker(NULL),
_maxRecursion(maxRecursion)
{
}
SequenceNumberStats::SequenceNumberStats(const SequenceNumberStats& other)
: _received(other._received),
_lastReceivedSequence(other._lastReceivedSequence),
_missingSet(other._missingSet),
_stats(other._stats),
_lastSenderUUID(other._lastSenderUUID),
_statsHistory(other._statsHistory),
_unreasonableTracker(NULL),
_maxRecursion(other._maxRecursion)
{
if (other._unreasonableTracker) {
_unreasonableTracker = new SequenceNumberStats(*other._unreasonableTracker);
}
}
SequenceNumberStats& SequenceNumberStats::operator=(const SequenceNumberStats& rhs) {
_received = rhs._received;
_lastReceivedSequence = rhs._lastReceivedSequence;
_missingSet = rhs._missingSet;
_stats = rhs._stats;
_lastSenderUUID = rhs._lastSenderUUID;
_statsHistory = rhs._statsHistory;
_maxRecursion = rhs._maxRecursion;
if (rhs._unreasonableTracker) {
_unreasonableTracker = new SequenceNumberStats(*rhs._unreasonableTracker);
} else {
_unreasonableTracker = NULL;
}
return *this;
}
SequenceNumberStats::~SequenceNumberStats() {
if (_unreasonableTracker) {
delete _unreasonableTracker;
}
}
void SequenceNumberStats::reset() {
_received = 0;
_missingSet.clear();
_stats = PacketStreamStats();
_lastSenderUUID = QUuid();
_statsHistory.clear();
if (_unreasonableTracker) {
delete _unreasonableTracker;
}
}
static const int UINT16_RANGE = std::numeric_limits<uint16_t>::max() + 1;
@ -78,10 +123,64 @@ SequenceNumberStats::ArrivalInfo SequenceNumberStats::sequenceNumberReceived(qui
} else if (absGap > MAX_REASONABLE_SEQUENCE_GAP) {
arrivalInfo._status = Unreasonable;
/*
// ignore packet if gap is unreasonable
qDebug() << "ignoring unreasonable sequence number:" << incoming
<< "previous:" << _lastReceivedSequence;
_stats._unreasonable++;
*/
// do not create a child tracker for unreasonable seq nums if this instance is the last one in the chain.
// otherwise, create one if we don't have one.
if (!_unreasonableTracker && _maxRecursion > 0) {
_unreasonableTracker = new SequenceNumberStats(0, _maxRecursion - 1);
}
if (_unreasonableTracker) {
// track this unreasonable seq number with our _unreasonableTracker.
ArrivalInfo unreasonableTrackerArrivalInfo = _unreasonableTracker->sequenceNumberReceived(incoming);
const int UNREASONABLE_TRACKER_RECEIVED_THRESHOLD = 10;
const float UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD = 0.1f;
const float UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD = 0.1f;
// when our _unreasonableTracker has received enough seq nums and doesn't have an _unreasonableTracker of its own,
// we'll either inherit its state only if we think its stream is plausible. it will then be deleted.
// (if it has an _unreasonableTracker of its own, its _unreasonableTracker may be detecting a plausible stream
// while its parent does not, so we should let it accrue seq nums and decide plausibility first)
if (!_unreasonableTracker->hasUnreasonableTracker() &&
_unreasonableTracker->_received >= UNREASONABLE_TRACKER_RECEIVED_THRESHOLD) {
if (_unreasonableTracker->getUnreasonableRate() < UNRUNREASONABLE_TRACKER_UNREASONABLE_RATE_THRESHOLD &&
_unreasonableTracker->getStats().getOutOfOrderRate() < UNREASONABLE_TRACKER_OUT_OF_ORDER_RATE_THRESHOLD) {
// the _unreasonableTracker has detected a plausible stream of seq numbers;
// copy its state to this tracker.
_received = _unreasonableTracker->_received;
_lastReceivedSequence = _unreasonableTracker->_lastReceivedSequence;
_missingSet = _unreasonableTracker->_missingSet;
_stats = _unreasonableTracker->_stats;
// don't copy _lastSenderUUID; _unreasonableTracker always has null UUID for that member.
// ours should be up-to-date.
// don't copy _statsHistory; _unreasonableTracker keeps a history of length 0.
// simply clear ours.
_statsHistory.clear();
arrivalInfo = unreasonableTrackerArrivalInfo;
}
// remove our _unreasonableTracker
delete _unreasonableTracker;
}
}
return arrivalInfo;
}

View file

@ -18,6 +18,10 @@
const int MAX_REASONABLE_SEQUENCE_GAP = 1000;
const int DEFAULT_MAX_RECURSION = 5;
class PacketStreamStats {
public:
PacketStreamStats()
@ -30,7 +34,7 @@ public:
_duplicate(0)
{}
float getUnreasonableRate() const { return (float)_unreasonable / _expectedReceived; }
float getOutOfOrderRate() const { return (float)(_early + _late) / _expectedReceived; }
float getEaryRate() const { return (float)_early / _expectedReceived; }
float getLateRate() const { return (float)_late / _expectedReceived; }
float getLostRate() const { return (float)_lost / _expectedReceived; }
@ -61,14 +65,19 @@ public:
};
SequenceNumberStats(int statsHistoryLength = 0);
SequenceNumberStats(int statsHistoryLength = 0, int maxRecursion = DEFAULT_MAX_RECURSION);
SequenceNumberStats(const SequenceNumberStats& other);
SequenceNumberStats& operator=(const SequenceNumberStats& rhs);
~SequenceNumberStats();
public:
void reset();
ArrivalInfo sequenceNumberReceived(quint16 incoming, QUuid senderUUID = QUuid(), const bool wantExtraDebugging = false);
void pruneMissingSet(const bool wantExtraDebugging = false);
void pushStatsToHistory() { _statsHistory.insert(_stats); }
quint32 getReceived() const { return _received; }
float getUnreasonableRate() const { return _stats._unreasonable / _received; }
quint32 getExpectedReceived() const { return _stats._expectedReceived; }
quint32 getUnreasonable() const { return _stats._unreasonable; }
@ -94,6 +103,14 @@ private:
QUuid _lastSenderUUID;
RingBufferHistory<PacketStreamStats> _statsHistory;
// to deal with the incoming seq nums going out of sync with this tracker, we'll create another instance
// of this class when we encounter an unreasonable
SequenceNumberStats* _unreasonableTracker;
int _maxRecursion;
bool hasUnreasonableTracker() const { return _unreasonableTracker != NULL; }
};
#endif // hifi_SequenceNumberStats_h