Created a client driven packet throttler. The sim now respects the client's network throttle settings but does sanity checks to avoid too little(nothing gets sent) or too much(the sim crashes) data.
* Consider this experimental.. however, it looks very promising.afrisby
parent
ae5999c3d5
commit
999eec603e
|
@ -62,7 +62,9 @@ namespace OpenSim.Framework
|
||||||
Cloud = 3,
|
Cloud = 3,
|
||||||
Task = 4,
|
Task = 4,
|
||||||
Texture = 5,
|
Texture = 5,
|
||||||
Asset = 6
|
Asset = 6,
|
||||||
|
Unknown = 7,
|
||||||
|
Back = 8
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -40,6 +40,17 @@ namespace OpenSim.Region.ClientStack
|
||||||
public partial class ClientView
|
public partial class ClientView
|
||||||
{
|
{
|
||||||
protected BlockingQueue<QueItem> PacketQueue;
|
protected BlockingQueue<QueItem> PacketQueue;
|
||||||
|
|
||||||
|
protected Queue<QueItem> IncomingPacketQueue;
|
||||||
|
protected Queue<QueItem> OutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> ResendOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> LandOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> WindOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> CloudOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> TaskOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> TextureOutgoingPacketQueue;
|
||||||
|
protected Queue<QueItem> AssetOutgoingPacketQueue;
|
||||||
|
|
||||||
protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
|
protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
|
||||||
protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
|
protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
|
||||||
|
|
||||||
|
@ -213,7 +224,39 @@ namespace OpenSim.Region.ClientStack
|
||||||
QueItem item = new QueItem();
|
QueItem item = new QueItem();
|
||||||
item.Packet = NewPack;
|
item.Packet = NewPack;
|
||||||
item.Incoming = false;
|
item.Incoming = false;
|
||||||
|
item.throttleType = throttlePacketType; // Packet throttle type
|
||||||
|
switch (throttlePacketType)
|
||||||
|
{
|
||||||
|
case ThrottleOutPacketType.Resend:
|
||||||
|
ResendOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Texture:
|
||||||
|
TextureOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Task:
|
||||||
|
TaskOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Land:
|
||||||
|
LandOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Asset:
|
||||||
|
AssetOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Cloud:
|
||||||
|
CloudOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
case ThrottleOutPacketType.Wind:
|
||||||
|
WindOutgoingPacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
// Acknowledgements and other such stuff should go directly to the blocking Queue
|
||||||
|
// Throttling them may and likely 'will' be problematic
|
||||||
PacketQueue.Enqueue(item);
|
PacketQueue.Enqueue(item);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//OutgoingPacketQueue.Enqueue(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
# region Low Level Packet Methods
|
# region Low Level Packet Methods
|
||||||
|
@ -228,7 +271,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
ack_it.Packets[0].ID = Pack.Header.Sequence;
|
ack_it.Packets[0].ID = Pack.Header.Sequence;
|
||||||
ack_it.Header.Reliable = false;
|
ack_it.Header.Reliable = false;
|
||||||
|
|
||||||
OutPacket(ack_it, ThrottleOutPacketType.Task);
|
OutPacket(ack_it, ThrottleOutPacketType.Unknown);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if (Pack.Header.Reliable)
|
if (Pack.Header.Reliable)
|
||||||
|
@ -289,7 +332,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
}
|
}
|
||||||
|
|
||||||
acks.Header.Reliable = false;
|
acks.Header.Reliable = false;
|
||||||
OutPacket(acks, ThrottleOutPacketType.Task);
|
OutPacket(acks, ThrottleOutPacketType.Unknown);
|
||||||
|
|
||||||
PendingAcks.Clear();
|
PendingAcks.Clear();
|
||||||
}
|
}
|
||||||
|
@ -314,6 +357,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
|
|
||||||
public Packet Packet;
|
public Packet Packet;
|
||||||
public bool Incoming;
|
public bool Incoming;
|
||||||
|
public ThrottleOutPacketType throttleType;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
@ -781,12 +781,9 @@ namespace OpenSim.Region.ClientStack
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region unimplemented handlers
|
|
||||||
case PacketType.AgentThrottle:
|
case PacketType.AgentThrottle:
|
||||||
|
|
||||||
//OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet " + Pack.ToString());
|
OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet " + Pack.ToString());
|
||||||
|
|
||||||
AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
|
AgentThrottlePacket atpack = (AgentThrottlePacket)Pack;
|
||||||
|
|
||||||
|
@ -828,7 +825,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
tAsset = (int)BitConverter.ToSingle(throttle, j);
|
tAsset = (int)BitConverter.ToSingle(throttle, j);
|
||||||
|
|
||||||
tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
|
tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
|
||||||
OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet AgentThrottle - Got throttle:resendbytes=" + tResend +
|
OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "Client AgentThrottle - Got throttle:resendbytes=" + tResend +
|
||||||
" landbytes=" + tLand +
|
" landbytes=" + tLand +
|
||||||
" windbytes=" + tWind +
|
" windbytes=" + tWind +
|
||||||
" cloudbytes=" + tCloud +
|
" cloudbytes=" + tCloud +
|
||||||
|
@ -836,9 +833,233 @@ namespace OpenSim.Region.ClientStack
|
||||||
" texturebytes=" + tTexture +
|
" texturebytes=" + tTexture +
|
||||||
" Assetbytes=" + tAsset +
|
" Assetbytes=" + tAsset +
|
||||||
" Allbytes=" + tall);
|
" Allbytes=" + tall);
|
||||||
|
// Total Sanity
|
||||||
|
// Make sure that the client sent sane total values.
|
||||||
|
|
||||||
|
// If the client didn't send acceptable values....
|
||||||
|
// Scale the clients values down until they are acceptable.
|
||||||
|
|
||||||
|
if (tall <= throttleOutboundMax)
|
||||||
|
{
|
||||||
|
// Sanity
|
||||||
|
// Making sure the client sends sane values
|
||||||
|
// This gives us a measure of control of the comms
|
||||||
|
// Check Max of Type
|
||||||
|
// Then Check Min of type
|
||||||
|
|
||||||
|
// Resend throttle
|
||||||
|
if (tResend <= ResendthrottleMAX)
|
||||||
|
ResendthrottleOutbound = tResend;
|
||||||
|
|
||||||
|
if (tResend < ResendthrottleMin)
|
||||||
|
ResendthrottleOutbound = ResendthrottleMin;
|
||||||
|
|
||||||
|
// Land throttle
|
||||||
|
if (tLand <= LandthrottleMax)
|
||||||
|
LandthrottleOutbound = tLand;
|
||||||
|
|
||||||
|
if (tLand < LandthrottleMin)
|
||||||
|
LandthrottleOutbound = LandthrottleMin;
|
||||||
|
|
||||||
|
// Wind throttle
|
||||||
|
if (tWind <= WindthrottleMax)
|
||||||
|
WindthrottleOutbound = tWind;
|
||||||
|
|
||||||
|
if (tWind < WindthrottleMin)
|
||||||
|
WindthrottleOutbound = WindthrottleMin;
|
||||||
|
|
||||||
|
// Cloud throttle
|
||||||
|
if (tCloud <= CloudthrottleMax)
|
||||||
|
CloudthrottleOutbound = tCloud;
|
||||||
|
|
||||||
|
if (tCloud < CloudthrottleMin)
|
||||||
|
CloudthrottleOutbound = CloudthrottleMin;
|
||||||
|
|
||||||
|
// Task throttle
|
||||||
|
if (tTask <= TaskthrottleMax)
|
||||||
|
TaskthrottleOutbound = tTask;
|
||||||
|
|
||||||
|
if (tTask < TaskthrottleMin)
|
||||||
|
TaskthrottleOutbound = TaskthrottleMin;
|
||||||
|
|
||||||
|
// Texture throttle
|
||||||
|
if (tTexture <= TexturethrottleMax)
|
||||||
|
TexturethrottleOutbound = tTexture;
|
||||||
|
|
||||||
|
if (tTexture < TexturethrottleMin)
|
||||||
|
TexturethrottleOutbound = TexturethrottleMin;
|
||||||
|
|
||||||
|
//Asset throttle
|
||||||
|
if (tAsset <= AssetthrottleMax)
|
||||||
|
AssetthrottleOutbound = tAsset;
|
||||||
|
|
||||||
|
if (tAsset < AssetthrottleMin)
|
||||||
|
AssetthrottleOutbound = AssetthrottleMin;
|
||||||
|
|
||||||
|
OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
|
||||||
|
" landbytes=" + LandthrottleOutbound +
|
||||||
|
" windbytes=" + WindthrottleOutbound +
|
||||||
|
" cloudbytes=" + CloudthrottleOutbound +
|
||||||
|
" taskbytes=" + TaskthrottleOutbound +
|
||||||
|
" texturebytes=" + TexturethrottleOutbound +
|
||||||
|
" Assetbytes=" + AssetthrottleOutbound +
|
||||||
|
" Allbytes=" + tall);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The client didn't send acceptable values..
|
||||||
|
// so it's our job now to turn them into acceptable values
|
||||||
|
// We're going to first scale the values down
|
||||||
|
// After that we're going to check if the scaled values are sane
|
||||||
|
|
||||||
|
// We're going to be dividing by a user value.. so make sure
|
||||||
|
// we don't get a divide by zero error.
|
||||||
|
if (tall > 0)
|
||||||
|
{
|
||||||
|
// Find out the percentage of all communications
|
||||||
|
// the client requests for each type. We'll keep resend at
|
||||||
|
// it's client recommended level (won't scale it down)
|
||||||
|
// unless it's beyond sane values itself.
|
||||||
|
|
||||||
|
if (tResend <= ResendthrottleMAX)
|
||||||
|
{
|
||||||
|
// This is nexted because we only want to re-set the values
|
||||||
|
// the packet throttler uses once.
|
||||||
|
|
||||||
|
if (tResend >= ResendthrottleMin)
|
||||||
|
{
|
||||||
|
ResendthrottleOutbound = tResend;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResendthrottleOutbound = ResendthrottleMin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResendthrottleOutbound = ResendthrottleMAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Getting Percentages of communication for each type of data
|
||||||
|
float LandPercent = (float)(tLand / tall);
|
||||||
|
float WindPercent = (float)(tWind / tall);
|
||||||
|
float CloudPercent = (float)(tCloud / tall);
|
||||||
|
float TaskPercent = (float)(tTask / tall);
|
||||||
|
float TexturePercent = (float)(tTexture / tall);
|
||||||
|
float AssetPercent = (float)(tAsset / tall);
|
||||||
|
|
||||||
|
// Okay.. now we've got the percentages of total communication.
|
||||||
|
// Apply them to a new max total
|
||||||
|
|
||||||
|
int tLandResult = (int)(LandPercent * throttleOutboundMax);
|
||||||
|
int tWindResult = (int)(WindPercent * throttleOutboundMax);
|
||||||
|
int tCloudResult = (int)(CloudPercent * throttleOutboundMax);
|
||||||
|
int tTaskResult = (int)(TaskPercent * throttleOutboundMax);
|
||||||
|
int tTextureResult = (int)(TexturePercent * throttleOutboundMax);
|
||||||
|
int tAssetResult = (int)(AssetPercent * throttleOutboundMax);
|
||||||
|
|
||||||
|
// Now we have to check our scaled values for sanity
|
||||||
|
|
||||||
|
// Check Max of Type
|
||||||
|
// Then Check Min of type
|
||||||
|
|
||||||
|
// Land throttle
|
||||||
|
if (tLandResult <= LandthrottleMax)
|
||||||
|
LandthrottleOutbound = tLandResult;
|
||||||
|
|
||||||
|
if (tLandResult < LandthrottleMin)
|
||||||
|
LandthrottleOutbound = LandthrottleMin;
|
||||||
|
|
||||||
|
// Wind throttle
|
||||||
|
if (tWindResult <= WindthrottleMax)
|
||||||
|
WindthrottleOutbound = tWindResult;
|
||||||
|
|
||||||
|
if (tWindResult < WindthrottleMin)
|
||||||
|
WindthrottleOutbound = WindthrottleMin;
|
||||||
|
|
||||||
|
// Cloud throttle
|
||||||
|
if (tCloudResult <= CloudthrottleMax)
|
||||||
|
CloudthrottleOutbound = tCloudResult;
|
||||||
|
|
||||||
|
if (tCloudResult < CloudthrottleMin)
|
||||||
|
CloudthrottleOutbound = CloudthrottleMin;
|
||||||
|
|
||||||
|
// Task throttle
|
||||||
|
if (tTaskResult <= TaskthrottleMax)
|
||||||
|
TaskthrottleOutbound = tTaskResult;
|
||||||
|
|
||||||
|
if (tTaskResult < TaskthrottleMin)
|
||||||
|
TaskthrottleOutbound = TaskthrottleMin;
|
||||||
|
|
||||||
|
// Texture throttle
|
||||||
|
if (tTextureResult <= TexturethrottleMax)
|
||||||
|
TexturethrottleOutbound = tTextureResult;
|
||||||
|
|
||||||
|
if (tTextureResult < TexturethrottleMin)
|
||||||
|
TexturethrottleOutbound = TexturethrottleMin;
|
||||||
|
|
||||||
|
//Asset throttle
|
||||||
|
if (tAssetResult <= AssetthrottleMax)
|
||||||
|
AssetthrottleOutbound = tAssetResult;
|
||||||
|
|
||||||
|
if (tAssetResult < AssetthrottleMin)
|
||||||
|
AssetthrottleOutbound = AssetthrottleMin;
|
||||||
|
|
||||||
|
OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
|
||||||
|
" landbytes=" + LandthrottleOutbound +
|
||||||
|
" windbytes=" + WindthrottleOutbound +
|
||||||
|
" cloudbytes=" + CloudthrottleOutbound +
|
||||||
|
" taskbytes=" + TaskthrottleOutbound +
|
||||||
|
" texturebytes=" + TexturethrottleOutbound +
|
||||||
|
" Assetbytes=" + AssetthrottleOutbound +
|
||||||
|
" Allbytes=" + tall);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// The client sent a stupid value..
|
||||||
|
// We're going to set the throttles to the minimum possible
|
||||||
|
ResendthrottleOutbound = ResendthrottleMin;
|
||||||
|
LandthrottleOutbound = LandthrottleMin;
|
||||||
|
WindthrottleOutbound = WindthrottleMin;
|
||||||
|
CloudthrottleOutbound = CloudthrottleMin;
|
||||||
|
TaskthrottleOutbound = TaskthrottleMin;
|
||||||
|
TexturethrottleOutbound = TexturethrottleMin;
|
||||||
|
AssetthrottleOutbound = AssetthrottleMin;
|
||||||
|
OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "ClientSentBadThrottle Using:resendbytes=" + ResendthrottleOutbound +
|
||||||
|
" landbytes=" + LandthrottleOutbound +
|
||||||
|
" windbytes=" + WindthrottleOutbound +
|
||||||
|
" cloudbytes=" + CloudthrottleOutbound +
|
||||||
|
" taskbytes=" + TaskthrottleOutbound +
|
||||||
|
" texturebytes=" + TexturethrottleOutbound +
|
||||||
|
" Assetbytes=" + AssetthrottleOutbound +
|
||||||
|
" Allbytes=" + tall);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// Reset Client Throttles
|
||||||
|
// This has the effect of 'wiggling the slider
|
||||||
|
// causes prim and stuck textures that didn't download to download
|
||||||
|
|
||||||
|
ResendthrottleSentPeriod = 0;
|
||||||
|
LandthrottleSentPeriod = 0;
|
||||||
|
WindthrottleSentPeriod = 0;
|
||||||
|
CloudthrottleSentPeriod = 0;
|
||||||
|
TaskthrottleSentPeriod = 0;
|
||||||
|
AssetthrottleSentPeriod = 0;
|
||||||
|
TexturethrottleSentPeriod = 0;
|
||||||
|
|
||||||
|
//Yay, we've finally handled the agent Throttle packet!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region unimplemented handlers
|
||||||
case PacketType.StartPingCheck:
|
case PacketType.StartPingCheck:
|
||||||
// Send the client the ping response back
|
// Send the client the ping response back
|
||||||
// Pass the same PingID in the matching packet
|
// Pass the same PingID in the matching packet
|
||||||
|
|
|
@ -87,11 +87,53 @@ namespace OpenSim.Region.ClientStack
|
||||||
private int probesWithNoIngressPackets = 0;
|
private int probesWithNoIngressPackets = 0;
|
||||||
private int lastPacketsReceived = 0;
|
private int lastPacketsReceived = 0;
|
||||||
|
|
||||||
|
// 1536000
|
||||||
private int throttleOutbound = 262144; // Number of bytes allowed to go out per second. (256kbps per client)
|
private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client)
|
||||||
// TODO: Make this variable. Lower throttle on un-ack. Raise over time?
|
// TODO: Make this variable. Lower throttle on un-ack. Raise over time?
|
||||||
private int throttleSentPeriod = 0; // Number of bytes sent this period
|
private int throttleSentPeriod = 0; // Number of bytes sent this period
|
||||||
|
|
||||||
|
private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client)
|
||||||
|
// TODO: Make this variable. Lower throttle on un-ack. Raise over time
|
||||||
|
|
||||||
|
// All throttle times and number of bytes are calculated by dividing by this value
|
||||||
|
private int throttleTimeDivisor = 5;
|
||||||
|
|
||||||
|
private int throttletimems = 1000;
|
||||||
|
|
||||||
|
// Maximum -per type- throttle
|
||||||
|
private int ResendthrottleMAX = 100000;
|
||||||
|
private int LandthrottleMax = 100000;
|
||||||
|
private int WindthrottleMax = 100000;
|
||||||
|
private int CloudthrottleMax = 100000;
|
||||||
|
private int TaskthrottleMax = 800000;
|
||||||
|
private int AssetthrottleMax = 800000;
|
||||||
|
private int TexturethrottleMax = 800000;
|
||||||
|
|
||||||
|
// Minimum -per type- throttle
|
||||||
|
private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets
|
||||||
|
private int LandthrottleMin = 1000;
|
||||||
|
private int WindthrottleMin = 1000;
|
||||||
|
private int CloudthrottleMin = 1000;
|
||||||
|
private int TaskthrottleMin = 1000;
|
||||||
|
private int AssetthrottleMin = 1000;
|
||||||
|
private int TexturethrottleMin = 1000;
|
||||||
|
|
||||||
|
// Sim default per-client settings.
|
||||||
|
private int ResendthrottleOutbound = 50000;
|
||||||
|
private int ResendthrottleSentPeriod = 0;
|
||||||
|
private int LandthrottleOutbound = 100000;
|
||||||
|
private int LandthrottleSentPeriod = 0;
|
||||||
|
private int WindthrottleOutbound = 10000;
|
||||||
|
private int WindthrottleSentPeriod = 0;
|
||||||
|
private int CloudthrottleOutbound = 5000;
|
||||||
|
private int CloudthrottleSentPeriod = 0;
|
||||||
|
private int TaskthrottleOutbound = 100000;
|
||||||
|
private int TaskthrottleSentPeriod = 0;
|
||||||
|
private int AssetthrottleOutbound = 80000;
|
||||||
|
private int AssetthrottleSentPeriod = 0;
|
||||||
|
private int TexturethrottleOutbound = 100000;
|
||||||
|
private int TexturethrottleSentPeriod = 0;
|
||||||
|
|
||||||
private Timer throttleTimer;
|
private Timer throttleTimer;
|
||||||
|
|
||||||
public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager,
|
public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager,
|
||||||
|
@ -114,14 +156,31 @@ namespace OpenSim.Region.ClientStack
|
||||||
|
|
||||||
startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
|
startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
|
||||||
|
|
||||||
|
|
||||||
|
// While working on this, the BlockingQueue had me fooled for a bit.
|
||||||
|
// The Blocking queue causes the thread to stop until there's something
|
||||||
|
// in it to process. it's an on-purpose threadlock though because
|
||||||
|
// without it, the clientloop will suck up all sim resources.
|
||||||
|
|
||||||
PacketQueue = new BlockingQueue<QueItem>();
|
PacketQueue = new BlockingQueue<QueItem>();
|
||||||
|
|
||||||
|
IncomingPacketQueue = new Queue<QueItem>();
|
||||||
|
OutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
ResendOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
LandOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
WindOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
CloudOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
TaskOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
TextureOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
AssetOutgoingPacketQueue = new Queue<QueItem>();
|
||||||
|
|
||||||
|
|
||||||
//this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
|
//this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
|
||||||
AckTimer = new Timer(750);
|
AckTimer = new Timer(750);
|
||||||
AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
|
AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
|
||||||
AckTimer.Start();
|
AckTimer.Start();
|
||||||
|
|
||||||
throttleTimer = new Timer(1000);
|
throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor));
|
||||||
throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed);
|
throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed);
|
||||||
throttleTimer.Start();
|
throttleTimer.Start();
|
||||||
|
|
||||||
|
@ -135,6 +194,95 @@ namespace OpenSim.Region.ClientStack
|
||||||
void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
|
void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
throttleSentPeriod = 0;
|
throttleSentPeriod = 0;
|
||||||
|
ResendthrottleSentPeriod = 0;
|
||||||
|
LandthrottleSentPeriod = 0;
|
||||||
|
WindthrottleSentPeriod = 0;
|
||||||
|
CloudthrottleSentPeriod = 0;
|
||||||
|
TaskthrottleSentPeriod = 0;
|
||||||
|
AssetthrottleSentPeriod = 0;
|
||||||
|
TexturethrottleSentPeriod = 0;
|
||||||
|
|
||||||
|
// I was considering this.. Will an event fire if the thread it's on is blocked?
|
||||||
|
|
||||||
|
// Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
|
||||||
|
// The General overhead of the UDP protocol gets sent to the queue un-throttled by this
|
||||||
|
// so This'll pick up about around the right time.
|
||||||
|
|
||||||
|
int MaxThrottleLoops = 5550; // 50*7 packets can be dequeued at once.
|
||||||
|
int throttleLoops = 0;
|
||||||
|
|
||||||
|
// 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
|
||||||
|
while ((throttleSentPeriod <= ((int)(throttleOutbound/throttleTimeDivisor)) &&
|
||||||
|
(ResendOutgoingPacketQueue.Count > 0 ||
|
||||||
|
LandOutgoingPacketQueue.Count > 0 ||
|
||||||
|
WindOutgoingPacketQueue.Count > 0 ||
|
||||||
|
CloudOutgoingPacketQueue.Count > 0 ||
|
||||||
|
TaskOutgoingPacketQueue.Count > 0 ||
|
||||||
|
AssetOutgoingPacketQueue.Count > 0 ||
|
||||||
|
TextureOutgoingPacketQueue.Count > 0)) && throttleLoops <= MaxThrottleLoops)
|
||||||
|
{
|
||||||
|
throttleLoops++;
|
||||||
|
//Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
|
||||||
|
if (ResendthrottleSentPeriod <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
ResendthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (LandthrottleSentPeriod <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = LandOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
LandthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (WindthrottleSentPeriod <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = WindOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
WindthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (CloudthrottleSentPeriod <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
CloudthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (TaskthrottleSentPeriod <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
TaskthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (TexturethrottleSentPeriod <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
TexturethrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
if (AssetthrottleSentPeriod <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0)
|
||||||
|
{
|
||||||
|
QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
|
||||||
|
|
||||||
|
PacketQueue.Enqueue(qpack);
|
||||||
|
throttleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
AssetthrottleSentPeriod += qpack.Packet.ToBytes().Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LLUUID SessionId
|
public LLUUID SessionId
|
||||||
|
@ -277,7 +425,7 @@ namespace OpenSim.Region.ClientStack
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Throw it back on the queue if it's going to cause us to flood the client
|
// Throw it back on the queue if it's going to cause us to flood the client
|
||||||
if (throttleSentPeriod > throttleOutbound)
|
if (throttleSentPeriod > throttleOutboundMax)
|
||||||
{
|
{
|
||||||
PacketQueue.Enqueue(nextPacket);
|
PacketQueue.Enqueue(nextPacket);
|
||||||
MainLog.Instance.Verbose("Client over throttle limit, requeuing packet");
|
MainLog.Instance.Verbose("Client over throttle limit, requeuing packet");
|
||||||
|
|
Loading…
Reference in New Issue