diff options
author | Sean Dague | 2007-12-07 19:13:35 +0000 |
---|---|---|
committer | Sean Dague | 2007-12-07 19:13:35 +0000 |
commit | 4221ec23f93cfb09a20abdcf83fcf46d2d6cd2c5 (patch) | |
tree | a4947582eae2d3458cb22291df3316611dba934c | |
parent | * Serialized data properly for the InterRegionSingleton InformRegionChild method (diff) | |
download | opensim-SC_OLD-4221ec23f93cfb09a20abdcf83fcf46d2d6cd2c5.zip opensim-SC_OLD-4221ec23f93cfb09a20abdcf83fcf46d2d6cd2c5.tar.gz opensim-SC_OLD-4221ec23f93cfb09a20abdcf83fcf46d2d6cd2c5.tar.bz2 opensim-SC_OLD-4221ec23f93cfb09a20abdcf83fcf46d2d6cd2c5.tar.xz |
further screwing around with the PacketQueue data structure.
Nearly time to replace a chunk of ClientView with this.
-rw-r--r-- | OpenSim/Region/ClientStack/PacketQueue.cs | 188 |
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 | { |