aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Region/ClientStack/PacketQueue.cs188
1 files changed, 149 insertions, 39 deletions
diff --git a/OpenSim/Region/ClientStack/PacketQueue.cs b/OpenSim/Region/ClientStack/PacketQueue.cs
index 6dfa15c..f2d270c 100644
--- a/OpenSim/Region/ClientStack/PacketQueue.cs
+++ b/OpenSim/Region/ClientStack/PacketQueue.cs
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ClientStack
44{ 44{
45 public class PacketQueue 45 public class PacketQueue
46 { 46 {
47 private BlockingQueue<QueItem> SendQueue; 47 private Queue<QueItem> SendQueue;
48 48
49 private Queue<QueItem> IncomingPacketQueue; 49 private Queue<QueItem> IncomingPacketQueue;
50 private Queue<QueItem> OutgoingPacketQueue; 50 private Queue<QueItem> OutgoingPacketQueue;
@@ -76,7 +76,8 @@ namespace OpenSim.Region.ClientStack
76 private PacketThrottle TextureThrottle; 76 private PacketThrottle TextureThrottle;
77 private PacketThrottle TotalThrottle; 77 private PacketThrottle TotalThrottle;
78 78
79 private Timer throttleTimer; 79 private long LastThrottle;
80 private long ThrottleInterval;
80 81
81 public PacketQueue() 82 public PacketQueue()
82 { 83 {
@@ -85,7 +86,7 @@ namespace OpenSim.Region.ClientStack
85 // in it to process. it's an on-purpose threadlock though because 86 // in it to process. it's an on-purpose threadlock though because
86 // without it, the clientloop will suck up all sim resources. 87 // without it, the clientloop will suck up all sim resources.
87 88
88 SendQueue = new BlockingQueue<QueItem>(); 89 SendQueue = new Queue<QueItem>();
89 90
90 IncomingPacketQueue = new Queue<QueItem>(); 91 IncomingPacketQueue = new Queue<QueItem>();
91 OutgoingPacketQueue = new Queue<QueItem>(); 92 OutgoingPacketQueue = new Queue<QueItem>();
@@ -111,9 +112,59 @@ namespace OpenSim.Region.ClientStack
111 TotalThrottle = new PacketThrottle(0, 162144, 1536000); 112 TotalThrottle = new PacketThrottle(0, 162144, 1536000);
112 113
113 // TIMERS needed for this 114 // TIMERS needed for this
114 throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor)); 115 LastThrottle = DateTime.Now.Ticks;
115 throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed); 116 ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
116 throttleTimer.Start(); 117 }
118
119 /* STANDARD QUEUE MANIPULATION INTERFACES */
120
121
122 public void Enqueue(QueItem item)
123 {
124 // We could micro lock, but that will tend to actually
125 // probably be worse than just synchronizing on SendQueue
126 lock (SendQueue) {
127 switch (item.throttleType)
128 {
129 case ThrottleOutPacketType.Resend:
130 ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
131 break;
132 case ThrottleOutPacketType.Texture:
133 ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
134 break;
135 case ThrottleOutPacketType.Task:
136 ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
137 break;
138 case ThrottleOutPacketType.Land:
139 ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
140 break;
141 case ThrottleOutPacketType.Asset:
142 ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
143 break;
144 case ThrottleOutPacketType.Cloud:
145 ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
146 break;
147 case ThrottleOutPacketType.Wind:
148 ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
149 break;
150
151 default:
152 // Acknowledgements and other such stuff should go directly to the blocking Queue
153 // Throttling them may and likely 'will' be problematic
154 SendQueue.Enqueue(item);
155 break;
156 }
157 }
158 }
159
160 public QueItem Dequeue()
161 {
162 if (ThrottlingTime()) {
163 ProcessThrottle();
164 }
165 lock (SendQueue) {
166 return SendQueue.Dequeue();
167 }
117 } 168 }
118 169
119 private void ResetCounters() 170 private void ResetCounters()
@@ -138,7 +189,99 @@ namespace OpenSim.Region.ClientStack
138 AssetOutgoingPacketQueue.Count > 0 || 189 AssetOutgoingPacketQueue.Count > 0 ||
139 TextureOutgoingPacketQueue.Count > 0); 190 TextureOutgoingPacketQueue.Count > 0);
140 } 191 }
192
193 // Run through our wait queues and flush out allotted numbers of bytes into the process queue
194
195 private bool ThrottlingTime()
196 {
197 if(DateTime.Now.Ticks < (LastThrottle + ThrottleInterval)) {
198 LastThrottle = DateTime.Now.Ticks;
199 return true;
200 } else {
201 return false;
202 }
203 }
141 204
205 public void ProcessThrottle()
206 {
207
208 // I was considering this.. Will an event fire if the thread it's on is blocked?
209
210 // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
211 // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
212 // so This'll pick up about around the right time.
213
214 int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
215 int throttleLoops = 0;
216
217 // We're going to dequeue all of the saved up packets until
218 // we've hit the throttle limit or there's no more packets to send
219 lock (SendQueue) {
220 ResetCounters();
221 while (TotalThrottle.UnderLimit() && PacketsWaiting() &&
222 (throttleLoops <= MaxThrottleLoops))
223 {
224 throttleLoops++;
225 //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
226 if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0)
227 {
228 QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
229
230 SendQueue.Enqueue(qpack);
231 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
232 ResendThrottle.Add(qpack.Packet.ToBytes().Length);
233 }
234 if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0)
235 {
236 QueItem qpack = LandOutgoingPacketQueue.Dequeue();
237
238 SendQueue.Enqueue(qpack);
239 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
240 LandThrottle.Add(qpack.Packet.ToBytes().Length);
241 }
242 if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0)
243 {
244 QueItem qpack = WindOutgoingPacketQueue.Dequeue();
245
246 SendQueue.Enqueue(qpack);
247 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
248 WindThrottle.Add(qpack.Packet.ToBytes().Length);
249 }
250 if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0)
251 {
252 QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
253
254 SendQueue.Enqueue(qpack);
255 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
256 CloudThrottle.Add(qpack.Packet.ToBytes().Length);
257 }
258 if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0)
259 {
260 QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
261
262 SendQueue.Enqueue(qpack);
263 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
264 TaskThrottle.Add(qpack.Packet.ToBytes().Length);
265 }
266 if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0)
267 {
268 QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
269
270 SendQueue.Enqueue(qpack);
271 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
272 TextureThrottle.Add(qpack.Packet.ToBytes().Length);
273 }
274 if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0)
275 {
276 QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
277
278 SendQueue.Enqueue(qpack);
279 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
280 AssetThrottle.Add(qpack.Packet.ToBytes().Length);
281 }
282 }
283 }
284 }
142 285
143 private void throttleTimer_Elapsed(object sender, ElapsedEventArgs e) 286 private void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
144 { 287 {
@@ -239,39 +382,6 @@ namespace OpenSim.Region.ClientStack
239 } 382 }
240 } 383 }
241 384
242 public void Add(QueItem item)
243 {
244 switch (item.throttleType)
245 {
246 case ThrottleOutPacketType.Resend:
247 ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
248 break;
249 case ThrottleOutPacketType.Texture:
250 ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
251 break;
252 case ThrottleOutPacketType.Task:
253 ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
254 break;
255 case ThrottleOutPacketType.Land:
256 ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
257 break;
258 case ThrottleOutPacketType.Asset:
259 ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
260 break;
261 case ThrottleOutPacketType.Cloud:
262 ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
263 break;
264 case ThrottleOutPacketType.Wind:
265 ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
266 break;
267
268 default:
269 // Acknowledgements and other such stuff should go directly to the blocking Queue
270 // Throttling them may and likely 'will' be problematic
271 SendQueue.Enqueue(item);
272 break;
273 }
274 }
275 385
276 private int ScaleThrottle(int value, int curmax, int newmax) 386 private int ScaleThrottle(int value, int curmax, int newmax)
277 { 387 {