diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 126 |
1 files changed, 95 insertions, 31 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index e52ac37..fe31bd9 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -31,6 +31,7 @@ using System.Net; | |||
31 | using System.Threading; | 31 | using System.Threading; |
32 | using log4net; | 32 | using log4net; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Framework.Monitoring; | ||
34 | using OpenMetaverse; | 35 | using OpenMetaverse; |
35 | using OpenMetaverse.Packets; | 36 | using OpenMetaverse.Packets; |
36 | 37 | ||
@@ -81,6 +82,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// hooked to put more data on the empty queue</summary> | 82 | /// hooked to put more data on the empty queue</summary> |
82 | public event QueueEmpty OnQueueEmpty; | 83 | public event QueueEmpty OnQueueEmpty; |
83 | 84 | ||
85 | public event Func<ThrottleOutPacketTypeFlags, bool> HasUpdates; | ||
86 | |||
84 | /// <summary>AgentID for this client</summary> | 87 | /// <summary>AgentID for this client</summary> |
85 | public readonly UUID AgentID; | 88 | public readonly UUID AgentID; |
86 | /// <summary>The remote address of the connected client</summary> | 89 | /// <summary>The remote address of the connected client</summary> |
@@ -160,6 +163,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
160 | private int m_maxRTO = 60000; | 163 | private int m_maxRTO = 60000; |
161 | public bool m_deliverPackets = true; | 164 | public bool m_deliverPackets = true; |
162 | 165 | ||
166 | public int m_lastStartpingTimeMS; | ||
167 | public int m_pingMS; | ||
168 | |||
169 | public int PingTimeMS | ||
170 | { | ||
171 | get | ||
172 | { | ||
173 | if (m_pingMS < 10) | ||
174 | return 10; | ||
175 | if(m_pingMS > 2000) | ||
176 | return 2000; | ||
177 | return m_pingMS; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /// <summary> | ||
182 | /// This is the percentage of the udp texture queue to add to the task queue since | ||
183 | /// textures are now generally handled through http. | ||
184 | /// </summary> | ||
185 | private double m_cannibalrate = 0.0; | ||
186 | |||
187 | private ClientInfo m_info = new ClientInfo(); | ||
188 | |||
163 | /// <summary> | 189 | /// <summary> |
164 | /// Default constructor | 190 | /// Default constructor |
165 | /// </summary> | 191 | /// </summary> |
@@ -197,6 +223,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | // Create an array of token buckets for this clients different throttle categories | 223 | // Create an array of token buckets for this clients different throttle categories |
198 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 224 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
199 | 225 | ||
226 | m_cannibalrate = rates.CannibalizeTextureRate; | ||
227 | |||
200 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 228 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
201 | { | 229 | { |
202 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 230 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
@@ -212,6 +240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
212 | 240 | ||
213 | // Initialize this to a sane value to prevent early disconnects | 241 | // Initialize this to a sane value to prevent early disconnects |
214 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; | 242 | TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; |
243 | m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0; | ||
215 | } | 244 | } |
216 | 245 | ||
217 | /// <summary> | 246 | /// <summary> |
@@ -241,20 +270,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
241 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 270 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists |
242 | // of pending and needed ACKs for every client every time some method wants information about | 271 | // of pending and needed ACKs for every client every time some method wants information about |
243 | // this connection is a recipe for poor performance | 272 | // this connection is a recipe for poor performance |
244 | ClientInfo info = new ClientInfo(); | 273 | |
245 | info.pendingAcks = new Dictionary<uint, uint>(); | 274 | m_info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
246 | info.needAck = new Dictionary<uint, byte[]>(); | 275 | m_info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
247 | 276 | m_info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | |
248 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 277 | m_info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
249 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 278 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
250 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 279 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
251 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 280 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
252 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 281 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; |
253 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 282 | |
254 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 283 | return m_info; |
255 | info.totalThrottle = (int)m_throttleCategory.DripRate; | ||
256 | |||
257 | return info; | ||
258 | } | 284 | } |
259 | 285 | ||
260 | /// <summary> | 286 | /// <summary> |
@@ -348,6 +374,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
348 | texture = Math.Max(texture, LLUDPServer.MTU); | 374 | texture = Math.Max(texture, LLUDPServer.MTU); |
349 | asset = Math.Max(asset, LLUDPServer.MTU); | 375 | asset = Math.Max(asset, LLUDPServer.MTU); |
350 | 376 | ||
377 | // Since most textures are now delivered through http, make it possible | ||
378 | // to cannibalize some of the bw from the texture throttle to use for | ||
379 | // the task queue (e.g. object updates) | ||
380 | task = task + (int)(m_cannibalrate * texture); | ||
381 | texture = (int)((1 - m_cannibalrate) * texture); | ||
382 | |||
351 | //int total = resend + land + wind + cloud + task + texture + asset; | 383 | //int total = resend + land + wind + cloud + task + texture + asset; |
352 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", | 384 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", |
353 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); | 385 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); |
@@ -646,15 +678,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
646 | /// <param name="categories">Throttle categories to fire the callback for</param> | 678 | /// <param name="categories">Throttle categories to fire the callback for</param> |
647 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) | 679 | private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) |
648 | { | 680 | { |
649 | if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | 681 | // if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) |
682 | if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) | ||
650 | { | 683 | { |
684 | m_isQueueEmptyRunning = true; | ||
685 | |||
686 | int start = Environment.TickCount & Int32.MaxValue; | ||
687 | const int MIN_CALLBACK_MS = 30; | ||
688 | |||
689 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
690 | if (m_nextOnQueueEmpty == 0) | ||
691 | m_nextOnQueueEmpty = 1; | ||
692 | |||
651 | // Use a value of 0 to signal that FireQueueEmpty is running | 693 | // Use a value of 0 to signal that FireQueueEmpty is running |
652 | m_nextOnQueueEmpty = 0; | 694 | // m_nextOnQueueEmpty = 0; |
653 | // Asynchronously run the callback | 695 | |
654 | Util.FireAndForget(FireQueueEmpty, categories); | 696 | m_categories = categories; |
697 | |||
698 | if (HasUpdates(m_categories)) | ||
699 | { | ||
700 | // Asynchronously run the callback | ||
701 | Util.FireAndForget(FireQueueEmpty, categories); | ||
702 | } | ||
703 | else | ||
704 | { | ||
705 | m_isQueueEmptyRunning = false; | ||
706 | } | ||
655 | } | 707 | } |
656 | } | 708 | } |
657 | 709 | ||
710 | private bool m_isQueueEmptyRunning; | ||
711 | private ThrottleOutPacketTypeFlags m_categories = 0; | ||
712 | |||
658 | /// <summary> | 713 | /// <summary> |
659 | /// Fires the OnQueueEmpty callback and sets the minimum time that it | 714 | /// Fires the OnQueueEmpty callback and sets the minimum time that it |
660 | /// can be called again | 715 | /// can be called again |
@@ -664,22 +719,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
664 | /// signature</param> | 719 | /// signature</param> |
665 | private void FireQueueEmpty(object o) | 720 | private void FireQueueEmpty(object o) |
666 | { | 721 | { |
667 | const int MIN_CALLBACK_MS = 30; | 722 | // int start = Environment.TickCount & Int32.MaxValue; |
723 | // const int MIN_CALLBACK_MS = 30; | ||
668 | 724 | ||
669 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | 725 | // if (m_udpServer.IsRunningOutbound) |
670 | QueueEmpty callback = OnQueueEmpty; | 726 | // { |
671 | 727 | ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; | |
672 | int start = Environment.TickCount & Int32.MaxValue; | 728 | QueueEmpty callback = OnQueueEmpty; |
673 | 729 | ||
674 | if (callback != null) | 730 | if (callback != null) |
675 | { | 731 | { |
676 | try { callback(categories); } | 732 | // if (m_udpServer.IsRunningOutbound) |
677 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | 733 | // { |
678 | } | 734 | try { callback(categories); } |
735 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } | ||
736 | // } | ||
737 | } | ||
738 | // } | ||
739 | |||
740 | // m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | ||
741 | // if (m_nextOnQueueEmpty == 0) | ||
742 | // m_nextOnQueueEmpty = 1; | ||
743 | |||
744 | // } | ||
679 | 745 | ||
680 | m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; | 746 | m_isQueueEmptyRunning = false; |
681 | if (m_nextOnQueueEmpty == 0) | ||
682 | m_nextOnQueueEmpty = 1; | ||
683 | } | 747 | } |
684 | internal void ForceThrottleSetting(int throttle, int setting) | 748 | internal void ForceThrottleSetting(int throttle, int setting) |
685 | { | 749 | { |