more efficient way of checking for already seen packets:
- uses Environment.TickCount for all timestamps (instead of more costly Util.UnixTimeSinceEpoch() - takes care of Environment.TickCount overflow (which will happens after 24.8 days of system uptime) - avoids instantiating List copies for each check - gets rid of one lock() invocation - moves calculation of loop invariant variable out of the loop itself0.6.6-post-fixes
parent
a1ba9dee8d
commit
77122d7861
|
@ -90,10 +90,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// the hashing. Expiration is less common and can be allowed the
|
// the hashing. Expiration is less common and can be allowed the
|
||||||
// time for a linear scan.
|
// time for a linear scan.
|
||||||
//
|
//
|
||||||
private Dictionary<uint, int> m_DupeTracker =
|
private List<uint> m_alreadySeenList = new List<uint>();
|
||||||
new Dictionary<uint, int>();
|
private Dictionary<uint, int>m_alreadySeenTracker = new Dictionary<uint, int>();
|
||||||
private uint m_DupeTrackerWindow = 30;
|
private int m_alreadySeenWindow = 30000;
|
||||||
private int m_DupeTrackerLastCheck = Environment.TickCount;
|
private int m_lastAlreadySeenCheck = Environment.TickCount & Int32.MaxValue;
|
||||||
|
|
||||||
|
// private Dictionary<uint, int> m_DupeTracker =
|
||||||
|
// new Dictionary<uint, int>();
|
||||||
|
// private uint m_DupeTrackerWindow = 30;
|
||||||
|
// private int m_DupeTrackerLastCheck = Environment.TickCount;
|
||||||
|
|
||||||
// Values for the SimStatsReporter
|
// Values for the SimStatsReporter
|
||||||
//
|
//
|
||||||
|
@ -449,27 +454,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
// We can't keep an unlimited record of dupes. This will prune the
|
// We can't keep an unlimited record of dupes. This will prune the
|
||||||
// dictionary by age.
|
// dictionary by age.
|
||||||
//
|
//
|
||||||
private void PruneDupeTracker()
|
// NOTE: this needs to be called from within lock
|
||||||
|
// (m_alreadySeenTracker) context!
|
||||||
|
private void ExpireSeenPackets()
|
||||||
{
|
{
|
||||||
lock (m_DupeTracker)
|
if (m_alreadySeenList.Count < 1024)
|
||||||
{
|
|
||||||
if (m_DupeTracker.Count < 1024)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Environment.TickCount - m_DupeTrackerLastCheck < 2000)
|
int ticks = 0;
|
||||||
return;
|
int tc = Environment.TickCount & Int32.MaxValue;
|
||||||
|
if (tc >= m_lastAlreadySeenCheck)
|
||||||
|
ticks = tc - m_lastAlreadySeenCheck;
|
||||||
|
else
|
||||||
|
ticks = Int32.MaxValue - m_lastAlreadySeenCheck + tc;
|
||||||
|
|
||||||
m_DupeTrackerLastCheck = Environment.TickCount;
|
if (ticks < 2000) return;
|
||||||
|
m_lastAlreadySeenCheck = tc;
|
||||||
|
|
||||||
Dictionary<uint, int> packs =
|
// we calculate the drop dead tick count here instead of
|
||||||
new Dictionary<uint, int>(m_DupeTracker);
|
// in the loop: any packet with a timestamp before
|
||||||
|
// dropDeadTC can be expired
|
||||||
foreach (uint pack in packs.Keys)
|
int dropDeadTC = tc - m_alreadySeenWindow;
|
||||||
|
int i = 0;
|
||||||
|
while (i < m_alreadySeenList.Count && m_alreadySeenTracker[m_alreadySeenList[i]] < dropDeadTC)
|
||||||
{
|
{
|
||||||
if (Util.UnixTimeSinceEpoch() - m_DupeTracker[pack] >
|
m_alreadySeenTracker.Remove(m_alreadySeenList[i]);
|
||||||
m_DupeTrackerWindow)
|
i++;
|
||||||
m_DupeTracker.Remove(pack);
|
|
||||||
}
|
}
|
||||||
|
// if we dropped packet from m_alreadySeenTracker we need
|
||||||
|
// to drop them from m_alreadySeenList as well, let's do
|
||||||
|
// that in one go: the list is ordered after all.
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
m_alreadySeenList.RemoveRange(0, i);
|
||||||
|
// m_log.DebugFormat("[CLIENT]: expired {0} packets, {1}:{2} left", i, m_alreadySeenList.Count, m_alreadySeenTracker.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -545,18 +563,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (packet.Type != PacketType.AgentUpdate)
|
if (packet.Type != PacketType.AgentUpdate)
|
||||||
m_PacketsReceived++;
|
m_PacketsReceived++;
|
||||||
|
|
||||||
PruneDupeTracker();
|
|
||||||
|
|
||||||
// Check for duplicate packets.. packets that the client is
|
// Check for duplicate packets.. packets that the client is
|
||||||
// resending because it didn't receive our ack
|
// resending because it didn't receive our ack
|
||||||
//
|
//
|
||||||
lock (m_DupeTracker)
|
lock (m_alreadySeenTracker)
|
||||||
{
|
{
|
||||||
if (m_DupeTracker.ContainsKey(packet.Header.Sequence))
|
ExpireSeenPackets();
|
||||||
|
|
||||||
|
if (m_alreadySeenTracker.ContainsKey(packet.Header.Sequence))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_DupeTracker.Add(packet.Header.Sequence,
|
m_alreadySeenTracker.Add(packet.Header.Sequence, Environment.TickCount & Int32.MaxValue);
|
||||||
Util.UnixTimeSinceEpoch());
|
m_alreadySeenList.Add(packet.Header.Sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Client.ProcessInPacket(packet);
|
m_Client.ProcessInPacket(packet);
|
||||||
|
|
Loading…
Reference in New Issue