diff options
author | Teravus Ovares | 2007-11-22 19:01:53 +0000 |
---|---|---|
committer | Teravus Ovares | 2007-11-22 19:01:53 +0000 |
commit | 999eec603ea62056f599761b90c7a0510336cdd9 (patch) | |
tree | 436e7a97ec06ab22b2378d24c5feb5296cfd7a6a /OpenSim/Region/ClientStack/ClientView.cs | |
parent | * removed erroneous comments (diff) | |
download | opensim-SC_OLD-999eec603ea62056f599761b90c7a0510336cdd9.zip opensim-SC_OLD-999eec603ea62056f599761b90c7a0510336cdd9.tar.gz opensim-SC_OLD-999eec603ea62056f599761b90c7a0510336cdd9.tar.bz2 opensim-SC_OLD-999eec603ea62056f599761b90c7a0510336cdd9.tar.xz |
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.
Diffstat (limited to 'OpenSim/Region/ClientStack/ClientView.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/ClientView.cs | 158 |
1 files changed, 153 insertions, 5 deletions
diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs index 10f880b..411883b 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs | |||
@@ -87,11 +87,53 @@ namespace OpenSim.Region.ClientStack | |||
87 | private int probesWithNoIngressPackets = 0; | 87 | private int probesWithNoIngressPackets = 0; |
88 | private int lastPacketsReceived = 0; | 88 | private int lastPacketsReceived = 0; |
89 | 89 | ||
90 | 90 | // 1536000 | |
91 | private int throttleOutbound = 262144; // Number of bytes allowed to go out per second. (256kbps per client) | 91 | private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client) |
92 | // TODO: Make this variable. Lower throttle on un-ack. Raise over time? | 92 | // TODO: Make this variable. Lower throttle on un-ack. Raise over time? |
93 | private int throttleSentPeriod = 0; // Number of bytes sent this period | 93 | private int throttleSentPeriod = 0; // Number of bytes sent this period |
94 | 94 | ||
95 | private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client) | ||
96 | // TODO: Make this variable. Lower throttle on un-ack. Raise over time | ||
97 | |||
98 | // All throttle times and number of bytes are calculated by dividing by this value | ||
99 | private int throttleTimeDivisor = 5; | ||
100 | |||
101 | private int throttletimems = 1000; | ||
102 | |||
103 | // Maximum -per type- throttle | ||
104 | private int ResendthrottleMAX = 100000; | ||
105 | private int LandthrottleMax = 100000; | ||
106 | private int WindthrottleMax = 100000; | ||
107 | private int CloudthrottleMax = 100000; | ||
108 | private int TaskthrottleMax = 800000; | ||
109 | private int AssetthrottleMax = 800000; | ||
110 | private int TexturethrottleMax = 800000; | ||
111 | |||
112 | // Minimum -per type- throttle | ||
113 | private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets | ||
114 | private int LandthrottleMin = 1000; | ||
115 | private int WindthrottleMin = 1000; | ||
116 | private int CloudthrottleMin = 1000; | ||
117 | private int TaskthrottleMin = 1000; | ||
118 | private int AssetthrottleMin = 1000; | ||
119 | private int TexturethrottleMin = 1000; | ||
120 | |||
121 | // Sim default per-client settings. | ||
122 | private int ResendthrottleOutbound = 50000; | ||
123 | private int ResendthrottleSentPeriod = 0; | ||
124 | private int LandthrottleOutbound = 100000; | ||
125 | private int LandthrottleSentPeriod = 0; | ||
126 | private int WindthrottleOutbound = 10000; | ||
127 | private int WindthrottleSentPeriod = 0; | ||
128 | private int CloudthrottleOutbound = 5000; | ||
129 | private int CloudthrottleSentPeriod = 0; | ||
130 | private int TaskthrottleOutbound = 100000; | ||
131 | private int TaskthrottleSentPeriod = 0; | ||
132 | private int AssetthrottleOutbound = 80000; | ||
133 | private int AssetthrottleSentPeriod = 0; | ||
134 | private int TexturethrottleOutbound = 100000; | ||
135 | private int TexturethrottleSentPeriod = 0; | ||
136 | |||
95 | private Timer throttleTimer; | 137 | private Timer throttleTimer; |
96 | 138 | ||
97 | public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager, | 139 | public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager, |
@@ -114,14 +156,31 @@ namespace OpenSim.Region.ClientStack | |||
114 | 156 | ||
115 | startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code); | 157 | startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code); |
116 | 158 | ||
159 | |||
160 | // While working on this, the BlockingQueue had me fooled for a bit. | ||
161 | // The Blocking queue causes the thread to stop until there's something | ||
162 | // in it to process. it's an on-purpose threadlock though because | ||
163 | // without it, the clientloop will suck up all sim resources. | ||
164 | |||
117 | PacketQueue = new BlockingQueue<QueItem>(); | 165 | PacketQueue = new BlockingQueue<QueItem>(); |
118 | 166 | ||
167 | IncomingPacketQueue = new Queue<QueItem>(); | ||
168 | OutgoingPacketQueue = new Queue<QueItem>(); | ||
169 | ResendOutgoingPacketQueue = new Queue<QueItem>(); | ||
170 | LandOutgoingPacketQueue = new Queue<QueItem>(); | ||
171 | WindOutgoingPacketQueue = new Queue<QueItem>(); | ||
172 | CloudOutgoingPacketQueue = new Queue<QueItem>(); | ||
173 | TaskOutgoingPacketQueue = new Queue<QueItem>(); | ||
174 | TextureOutgoingPacketQueue = new Queue<QueItem>(); | ||
175 | AssetOutgoingPacketQueue = new Queue<QueItem>(); | ||
176 | |||
177 | |||
119 | //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); | 178 | //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); |
120 | AckTimer = new Timer(750); | 179 | AckTimer = new Timer(750); |
121 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); | 180 | AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); |
122 | AckTimer.Start(); | 181 | AckTimer.Start(); |
123 | 182 | ||
124 | throttleTimer = new Timer(1000); | 183 | throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor)); |
125 | throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed); | 184 | throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed); |
126 | throttleTimer.Start(); | 185 | throttleTimer.Start(); |
127 | 186 | ||
@@ -133,8 +192,97 @@ namespace OpenSim.Region.ClientStack | |||
133 | } | 192 | } |
134 | 193 | ||
135 | void throttleTimer_Elapsed(object sender, ElapsedEventArgs e) | 194 | void throttleTimer_Elapsed(object sender, ElapsedEventArgs e) |
136 | { | 195 | { |
137 | throttleSentPeriod = 0; | 196 | throttleSentPeriod = 0; |
197 | ResendthrottleSentPeriod = 0; | ||
198 | LandthrottleSentPeriod = 0; | ||
199 | WindthrottleSentPeriod = 0; | ||
200 | CloudthrottleSentPeriod = 0; | ||
201 | TaskthrottleSentPeriod = 0; | ||
202 | AssetthrottleSentPeriod = 0; | ||
203 | TexturethrottleSentPeriod = 0; | ||
204 | |||
205 | // I was considering this.. Will an event fire if the thread it's on is blocked? | ||
206 | |||
207 | // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long | ||
208 | // The General overhead of the UDP protocol gets sent to the queue un-throttled by this | ||
209 | // so This'll pick up about around the right time. | ||
210 | |||
211 | int MaxThrottleLoops = 5550; // 50*7 packets can be dequeued at once. | ||
212 | int throttleLoops = 0; | ||
213 | |||
214 | // We're going to dequeue all of the saved up packets until | ||
215 | // we've hit the throttle limit or there's no more packets to send | ||
216 | while ((throttleSentPeriod <= ((int)(throttleOutbound/throttleTimeDivisor)) && | ||
217 | (ResendOutgoingPacketQueue.Count > 0 || | ||
218 | LandOutgoingPacketQueue.Count > 0 || | ||
219 | WindOutgoingPacketQueue.Count > 0 || | ||
220 | CloudOutgoingPacketQueue.Count > 0 || | ||
221 | TaskOutgoingPacketQueue.Count > 0 || | ||
222 | AssetOutgoingPacketQueue.Count > 0 || | ||
223 | TextureOutgoingPacketQueue.Count > 0)) && throttleLoops <= MaxThrottleLoops) | ||
224 | { | ||
225 | throttleLoops++; | ||
226 | //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up. | ||
227 | if (ResendthrottleSentPeriod <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0) | ||
228 | { | ||
229 | QueItem qpack = ResendOutgoingPacketQueue.Dequeue(); | ||
230 | |||
231 | PacketQueue.Enqueue(qpack); | ||
232 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
233 | ResendthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
234 | } | ||
235 | if (LandthrottleSentPeriod <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0) | ||
236 | { | ||
237 | QueItem qpack = LandOutgoingPacketQueue.Dequeue(); | ||
238 | |||
239 | PacketQueue.Enqueue(qpack); | ||
240 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
241 | LandthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
242 | } | ||
243 | if (WindthrottleSentPeriod <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0) | ||
244 | { | ||
245 | QueItem qpack = WindOutgoingPacketQueue.Dequeue(); | ||
246 | |||
247 | PacketQueue.Enqueue(qpack); | ||
248 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
249 | WindthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
250 | } | ||
251 | if (CloudthrottleSentPeriod <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0) | ||
252 | { | ||
253 | QueItem qpack = CloudOutgoingPacketQueue.Dequeue(); | ||
254 | |||
255 | PacketQueue.Enqueue(qpack); | ||
256 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
257 | CloudthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
258 | } | ||
259 | if (TaskthrottleSentPeriod <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0) | ||
260 | { | ||
261 | QueItem qpack = TaskOutgoingPacketQueue.Dequeue(); | ||
262 | |||
263 | PacketQueue.Enqueue(qpack); | ||
264 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
265 | TaskthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
266 | } | ||
267 | if (TexturethrottleSentPeriod <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0) | ||
268 | { | ||
269 | QueItem qpack = TextureOutgoingPacketQueue.Dequeue(); | ||
270 | |||
271 | PacketQueue.Enqueue(qpack); | ||
272 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
273 | TexturethrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
274 | } | ||
275 | if (AssetthrottleSentPeriod <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0) | ||
276 | { | ||
277 | QueItem qpack = AssetOutgoingPacketQueue.Dequeue(); | ||
278 | |||
279 | PacketQueue.Enqueue(qpack); | ||
280 | throttleSentPeriod += qpack.Packet.ToBytes().Length; | ||
281 | AssetthrottleSentPeriod += qpack.Packet.ToBytes().Length; | ||
282 | } | ||
283 | |||
284 | } | ||
285 | |||
138 | } | 286 | } |
139 | 287 | ||
140 | public LLUUID SessionId | 288 | public LLUUID SessionId |
@@ -277,7 +425,7 @@ namespace OpenSim.Region.ClientStack | |||
277 | else | 425 | else |
278 | { | 426 | { |
279 | // Throw it back on the queue if it's going to cause us to flood the client | 427 | // Throw it back on the queue if it's going to cause us to flood the client |
280 | if (throttleSentPeriod > throttleOutbound) | 428 | if (throttleSentPeriod > throttleOutboundMax) |
281 | { | 429 | { |
282 | PacketQueue.Enqueue(nextPacket); | 430 | PacketQueue.Enqueue(nextPacket); |
283 | MainLog.Instance.Verbose("Client over throttle limit, requeuing packet"); | 431 | MainLog.Instance.Verbose("Client over throttle limit, requeuing packet"); |