Change texture sending to be driven by the queue empty event from the

packet queue, rather than a timer
prioritization
Melanie 2009-10-02 04:04:14 +01:00
parent 54ff84050f
commit 18a744cac1
5 changed files with 60 additions and 95 deletions

View File

@ -232,6 +232,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_packetNumber = m_requestedPacketNumber; m_packetNumber = m_requestedPacketNumber;
} }
if (m_imageManager.Client.PacketHandler.GetQueueCount(ThrottleOutPacketType.Texture) == 0)
{
m_log.Debug("No textures queued, sending one packet to kickstart it");
SendPacket(m_imageManager.Client);
}
} }
} }
} }

View File

@ -81,8 +81,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates = private List<ObjectUpdatePacket.ObjectDataBlock> m_primFullUpdates =
new List<ObjectUpdatePacket.ObjectDataBlock>(); new List<ObjectUpdatePacket.ObjectDataBlock>();
private Timer m_textureRequestTimer;
private bool m_clientBlocked; private bool m_clientBlocked;
private int m_probesWithNoIngressPackets; private int m_probesWithNoIngressPackets;
@ -143,9 +141,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected int m_primTerseUpdateRate = 10; protected int m_primTerseUpdateRate = 10;
protected int m_primFullUpdateRate = 14; protected int m_primFullUpdateRate = 14;
protected int m_textureRequestRate = 100; protected int m_textureSendLimit = 100;
protected int m_textureSendLimit = 10; protected int m_textureDataLimit = 10;
protected int m_textureDataLimit = 5;
protected int m_packetMTU = 1400; protected int m_packetMTU = 1400;
@ -534,6 +531,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_PacketHandler = new LLPacketHandler(this, m_networkServer, userSettings); m_PacketHandler = new LLPacketHandler(this, m_networkServer, userSettings);
m_PacketHandler.SynchronizeClient = SynchronizeClient; m_PacketHandler.SynchronizeClient = SynchronizeClient;
m_PacketHandler.OnPacketStats += PopulateStats; m_PacketHandler.OnPacketStats += PopulateStats;
m_PacketHandler.OnQueueEmpty += HandleQueueEmpty;
if (scene.Config != null) if (scene.Config != null)
{ {
@ -555,9 +553,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_primFullUpdateRate = clientConfig.GetInt("FullUpdateRate", m_primFullUpdateRate = clientConfig.GetInt("FullUpdateRate",
m_primFullUpdateRate); m_primFullUpdateRate);
m_textureRequestRate = clientConfig.GetInt("TextureRequestRate",
m_textureRequestRate);
m_textureSendLimit = clientConfig.GetInt("TextureSendLimit", m_textureSendLimit = clientConfig.GetInt("TextureSendLimit",
m_textureSendLimit); m_textureSendLimit);
@ -607,9 +602,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (m_primFullUpdateTimer.Enabled) if (m_primFullUpdateTimer.Enabled)
lock (m_primFullUpdateTimer) lock (m_primFullUpdateTimer)
m_primFullUpdateTimer.Stop(); m_primFullUpdateTimer.Stop();
if (m_textureRequestTimer.Enabled)
lock (m_textureRequestTimer)
m_textureRequestTimer.Stop();
// This is just to give the client a reasonable chance of // This is just to give the client a reasonable chance of
// flushing out all it's packets. There should probably // flushing out all it's packets. There should probably
@ -706,10 +698,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (m_primFullUpdateTimer.Enabled) if (m_primFullUpdateTimer.Enabled)
lock (m_primFullUpdateTimer) lock (m_primFullUpdateTimer)
m_primFullUpdateTimer.Stop(); m_primFullUpdateTimer.Stop();
if (m_textureRequestTimer.Enabled)
lock (m_textureRequestTimer)
m_textureRequestTimer.Stop();
} }
public void Restart() public void Restart()
@ -732,11 +720,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_primFullUpdateTimer = new Timer(m_primFullUpdateRate); m_primFullUpdateTimer = new Timer(m_primFullUpdateRate);
m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
m_primFullUpdateTimer.AutoReset = false; m_primFullUpdateTimer.AutoReset = false;
m_textureRequestTimer = new Timer(m_textureRequestRate);
m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
m_textureRequestTimer.AutoReset = false;
} }
private void Terminate() private void Terminate()
@ -747,7 +730,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_avatarTerseUpdateTimer.Close(); m_avatarTerseUpdateTimer.Close();
m_primTerseUpdateTimer.Close(); m_primTerseUpdateTimer.Close();
m_primFullUpdateTimer.Close(); m_primFullUpdateTimer.Close();
m_textureRequestTimer.Close();
m_PacketHandler.OnPacketStats -= PopulateStats; m_PacketHandler.OnPacketStats -= PopulateStats;
m_PacketHandler.Dispose(); m_PacketHandler.Dispose();
@ -982,10 +964,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates); m_primFullUpdateTimer.Elapsed += new ElapsedEventHandler(ProcessPrimFullUpdates);
m_primFullUpdateTimer.AutoReset = false; m_primFullUpdateTimer.AutoReset = false;
m_textureRequestTimer = new Timer(m_textureRequestRate);
m_textureRequestTimer.Elapsed += new ElapsedEventHandler(ProcessTextureRequests);
m_textureRequestTimer.AutoReset = false;
m_scene.AddNewClient(this); m_scene.AddNewClient(this);
RefreshGroupMembership(); RefreshGroupMembership();
@ -1057,26 +1035,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
protected virtual void TextureRequestHandler()
{
m_log.DebugFormat("[TRH] Thread started");
while (m_imageManager != null)
{
try
{
while (m_imageManager != null)
{
}
}
catch (Exception e)
{
m_log.WarnFormat("[TRH] Exception in handler loop: {0}", e.Message);
m_log.Debug(e);
}
}
m_log.DebugFormat("[TRH] Thread terminated");
}
# endregion # endregion
// Previously ClientView.API partial class // Previously ClientView.API partial class
@ -3176,16 +3134,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Unlike the other timers, this one is only started after // Unlike the other timers, this one is only started after
// the first request is seen. // the first request is seen.
void ProcessTextureRequests(object sender, ElapsedEventArgs e) void HandleQueueEmpty(ThrottleOutPacketType queue)
{
switch (queue)
{
case ThrottleOutPacketType.Texture:
m_log.Debug("Texture queue empty");
ProcessTextureRequests();
break;
}
}
void ProcessTextureRequests()
{ {
if (m_imageManager != null) if (m_imageManager != null)
{ {
if (m_imageManager.ProcessImageQueue(m_textureSendLimit, m_imageManager.ProcessImageQueue(m_textureSendLimit,
m_textureDataLimit)) m_textureDataLimit);
{
lock (m_textureRequestTimer)
m_textureRequestTimer.Start();
}
} }
} }
@ -6638,8 +6603,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (m_imageManager != null) if (m_imageManager != null)
{ {
m_imageManager.EnqueueReq(args); m_imageManager.EnqueueReq(args);
lock (m_textureRequestTimer)
m_textureRequestTimer.Start();
} }
} }
} }

View File

@ -65,6 +65,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_j2kDecodeModule = pJ2kDecodeModule; m_j2kDecodeModule = pJ2kDecodeModule;
} }
public LLClientView Client
{
get { return m_client; }
}
public void EnqueueReq(TextureRequestArgs newRequest) public void EnqueueReq(TextureRequestArgs newRequest)
{ {
//newRequest is the properties of our new texture fetch request. //newRequest is the properties of our new texture fetch request.
@ -207,8 +212,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
threshold = 10; threshold = 10;
//Uncomment this to see what the texture stack is doing //Uncomment this to see what the texture stack is doing
//m_log.Debug("Queue: " + m_client.PacketHandler.PacketQueue.TextureOutgoingPacketQueueCount.ToString() + " Threshold: " + threshold.ToString() + " outstanding: " + m_outstandingtextures.ToString()); //m_log.Debug("Queue: " + m_client.PacketHandler.PacketQueue.getQueueCount(ThrottleOutPacketType.Texture).ToString() + " Threshold: " + threshold.ToString() + " outstanding: " + m_outstandingtextures.ToString());
if (m_client.PacketHandler.PacketQueue.TextureOutgoingPacketQueueCount < threshold) if (m_client.PacketHandler.PacketQueue.GetQueueCount(ThrottleOutPacketType.Texture) < threshold)
{ {
while (m_priorityQueue.Count > 0) while (m_priorityQueue.Count > 0)
{ {

View File

@ -62,6 +62,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private Queue<LLQueItem> TextureOutgoingPacketQueue; private Queue<LLQueItem> TextureOutgoingPacketQueue;
private Queue<LLQueItem> AssetOutgoingPacketQueue; private Queue<LLQueItem> AssetOutgoingPacketQueue;
private List<ThrottleOutPacketType> Empty = new List<ThrottleOutPacketType>();
// m_log.Info("[THROTTLE]: Entering Throttle");
// private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
// private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
@ -85,20 +87,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private Dictionary<uint,int> contents = new Dictionary<uint, int>(); private Dictionary<uint,int> contents = new Dictionary<uint, int>();
/// <summary>
/// The number of packets in the OutgoingPacketQueue
///
/// </summary>
internal int TextureOutgoingPacketQueueCount
{
get
{
if (TextureOutgoingPacketQueue == null)
return 0;
return TextureOutgoingPacketQueue.Count;
}
}
// private long LastThrottle; // private long LastThrottle;
// private long ThrottleInterval; // private long ThrottleInterval;
private Timer throttleTimer; private Timer throttleTimer;
@ -212,28 +200,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
switch (item.throttleType & ThrottleOutPacketType.TypeMask) switch (item.throttleType & ThrottleOutPacketType.TypeMask)
{ {
case ThrottleOutPacketType.Resend: case ThrottleOutPacketType.Resend:
ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item); ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item, ThrottleOutPacketType.Resend);
break; break;
case ThrottleOutPacketType.Texture: case ThrottleOutPacketType.Texture:
ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item); ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item, ThrottleOutPacketType.Texture);
break; break;
case ThrottleOutPacketType.Task: case ThrottleOutPacketType.Task:
if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0) if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0)
ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item); ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item, ThrottleOutPacketType.Task);
else else
ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item, ThrottleOutPacketType.Task);
break; break;
case ThrottleOutPacketType.Land: case ThrottleOutPacketType.Land:
ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item, ThrottleOutPacketType.Land);
break; break;
case ThrottleOutPacketType.Asset: case ThrottleOutPacketType.Asset:
ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item); ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item, ThrottleOutPacketType.Asset);
break; break;
case ThrottleOutPacketType.Cloud: case ThrottleOutPacketType.Cloud:
ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item); ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item, ThrottleOutPacketType.Cloud);
break; break;
case ThrottleOutPacketType.Wind: case ThrottleOutPacketType.Wind:
ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item); ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item, ThrottleOutPacketType.Wind);
break; break;
default: default:
@ -408,6 +396,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
int throttleLoops = 0; int throttleLoops = 0;
List<ThrottleOutPacketType> e;
// We're going to dequeue all of the saved up packets until // We're going to dequeue all of the saved up packets until
// we've hit the throttle limit or there's no more packets to send // we've hit the throttle limit or there's no more packets to send
@ -420,8 +409,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ResetCounters(); ResetCounters();
List<ThrottleOutPacketType> Empty = new List<ThrottleOutPacketType>();
// m_log.Info("[THROTTLE]: Entering Throttle");
while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops) while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops)
{ {
qchanged = false; // We will break out of the loop if no work was accomplished qchanged = false; // We will break out of the loop if no work was accomplished
@ -448,7 +435,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
LandThrottle.AddBytes(qpack.Length); LandThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (LandOutgoingPacketQueue.Count == 0) if (LandOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Land))
Empty.Add(ThrottleOutPacketType.Land); Empty.Add(ThrottleOutPacketType.Land);
} }
@ -461,7 +448,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
WindThrottle.AddBytes(qpack.Length); WindThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (WindOutgoingPacketQueue.Count == 0) if (WindOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Wind))
Empty.Add(ThrottleOutPacketType.Wind); Empty.Add(ThrottleOutPacketType.Wind);
} }
@ -474,7 +461,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
CloudThrottle.AddBytes(qpack.Length); CloudThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (CloudOutgoingPacketQueue.Count == 0) if (CloudOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Cloud))
Empty.Add(ThrottleOutPacketType.Cloud); Empty.Add(ThrottleOutPacketType.Cloud);
} }
@ -496,7 +483,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
TaskThrottle.AddBytes(qpack.Length); TaskThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (TaskOutgoingPacketQueue.Count == 0 && TaskLowpriorityPacketQueue.Count == 0) if (TaskOutgoingPacketQueue.Count == 0 && TaskLowpriorityPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Task))
Empty.Add(ThrottleOutPacketType.Task); Empty.Add(ThrottleOutPacketType.Task);
} }
@ -509,7 +496,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
TextureThrottle.AddBytes(qpack.Length); TextureThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (TextureOutgoingPacketQueue.Count == 0) if (TextureOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Texture))
Empty.Add(ThrottleOutPacketType.Texture); Empty.Add(ThrottleOutPacketType.Texture);
} }
@ -522,16 +509,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AssetThrottle.AddBytes(qpack.Length); AssetThrottle.AddBytes(qpack.Length);
qchanged = true; qchanged = true;
if (AssetOutgoingPacketQueue.Count == 0) if (AssetOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Asset))
Empty.Add(ThrottleOutPacketType.Asset); Empty.Add(ThrottleOutPacketType.Asset);
} }
} }
// m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
foreach (ThrottleOutPacketType t in Empty) e = new List<ThrottleOutPacketType>(Empty);
{ Empty.Clear();
TriggerOnQueueEmpty(t);
} }
foreach (ThrottleOutPacketType t in e)
{
if (GetQueueCount(t) == 0)
TriggerOnQueueEmpty(t);
} }
} }
@ -552,7 +543,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
ProcessThrottle(); ProcessThrottle();
} }
private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item) private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item, ThrottleOutPacketType itemType)
{ {
// The idea.. is if the packet throttle queues are empty // The idea.. is if the packet throttle queues are empty
// and the client is under throttle for the type. Queue // and the client is under throttle for the type. Queue
@ -568,6 +559,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
throttle.AddBytes(item.Length); throttle.AddBytes(item.Length);
TotalThrottle.AddBytes(item.Length); TotalThrottle.AddBytes(item.Length);
SendQueue.Enqueue(item); SendQueue.Enqueue(item);
lock (this)
{
if (!Empty.Contains(itemType))
Empty.Add(itemType);
}
} }
catch (Exception e) catch (Exception e)
{ {

View File

@ -1352,11 +1352,6 @@
;PacketMTU = 1400 ;PacketMTU = 1400
; TextureUpdateRate (mS) determines how many times per second
; texture send processing will occur. The default is 100mS.
;
;TextureRequestRate = 100
; TextureSendLimit determines how many different textures ; TextureSendLimit determines how many different textures
; will be considered on each cycle. Textures are selected ; will be considered on each cycle. Textures are selected
; by priority. The old mechanism specified a value of 10 for ; by priority. The old mechanism specified a value of 10 for