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 | |
parent | * removed erroneous comments (diff) | |
download | opensim-SC-999eec603ea62056f599761b90c7a0510336cdd9.zip opensim-SC-999eec603ea62056f599761b90c7a0510336cdd9.tar.gz opensim-SC-999eec603ea62056f599761b90c7a0510336cdd9.tar.bz2 opensim-SC-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.
-rw-r--r-- | OpenSim/Framework/IClientAPI.cs | 4 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/ClientView.PacketQueue.cs | 50 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs | 247 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/ClientView.cs | 158 |
4 files changed, 437 insertions, 22 deletions
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 05adf22..2c82d97 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs | |||
@@ -62,7 +62,9 @@ namespace OpenSim.Framework | |||
62 | Cloud = 3, | 62 | Cloud = 3, |
63 | Task = 4, | 63 | Task = 4, |
64 | Texture = 5, | 64 | Texture = 5, |
65 | Asset = 6 | 65 | Asset = 6, |
66 | Unknown = 7, | ||
67 | Back = 8 | ||
66 | } | 68 | } |
67 | 69 | ||
68 | /// <summary> | 70 | /// <summary> |
diff --git a/OpenSim/Region/ClientStack/ClientView.PacketQueue.cs b/OpenSim/Region/ClientStack/ClientView.PacketQueue.cs index 179d02a..3ce3d8c 100644 --- a/OpenSim/Region/ClientStack/ClientView.PacketQueue.cs +++ b/OpenSim/Region/ClientStack/ClientView.PacketQueue.cs | |||
@@ -40,6 +40,17 @@ namespace OpenSim.Region.ClientStack | |||
40 | public partial class ClientView | 40 | public partial class ClientView |
41 | { | 41 | { |
42 | protected BlockingQueue<QueItem> PacketQueue; | 42 | protected BlockingQueue<QueItem> PacketQueue; |
43 | |||
44 | protected Queue<QueItem> IncomingPacketQueue; | ||
45 | protected Queue<QueItem> OutgoingPacketQueue; | ||
46 | protected Queue<QueItem> ResendOutgoingPacketQueue; | ||
47 | protected Queue<QueItem> LandOutgoingPacketQueue; | ||
48 | protected Queue<QueItem> WindOutgoingPacketQueue; | ||
49 | protected Queue<QueItem> CloudOutgoingPacketQueue; | ||
50 | protected Queue<QueItem> TaskOutgoingPacketQueue; | ||
51 | protected Queue<QueItem> TextureOutgoingPacketQueue; | ||
52 | protected Queue<QueItem> AssetOutgoingPacketQueue; | ||
53 | |||
43 | protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | 54 | protected Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); |
44 | protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | 55 | protected Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); |
45 | 56 | ||
@@ -213,7 +224,39 @@ namespace OpenSim.Region.ClientStack | |||
213 | QueItem item = new QueItem(); | 224 | QueItem item = new QueItem(); |
214 | item.Packet = NewPack; | 225 | item.Packet = NewPack; |
215 | item.Incoming = false; | 226 | item.Incoming = false; |
216 | PacketQueue.Enqueue(item); | 227 | item.throttleType = throttlePacketType; // Packet throttle type |
228 | switch (throttlePacketType) | ||
229 | { | ||
230 | case ThrottleOutPacketType.Resend: | ||
231 | ResendOutgoingPacketQueue.Enqueue(item); | ||
232 | break; | ||
233 | case ThrottleOutPacketType.Texture: | ||
234 | TextureOutgoingPacketQueue.Enqueue(item); | ||
235 | break; | ||
236 | case ThrottleOutPacketType.Task: | ||
237 | TaskOutgoingPacketQueue.Enqueue(item); | ||
238 | break; | ||
239 | case ThrottleOutPacketType.Land: | ||
240 | LandOutgoingPacketQueue.Enqueue(item); | ||
241 | break; | ||
242 | case ThrottleOutPacketType.Asset: | ||
243 | AssetOutgoingPacketQueue.Enqueue(item); | ||
244 | break; | ||
245 | case ThrottleOutPacketType.Cloud: | ||
246 | CloudOutgoingPacketQueue.Enqueue(item); | ||
247 | break; | ||
248 | case ThrottleOutPacketType.Wind: | ||
249 | WindOutgoingPacketQueue.Enqueue(item); | ||
250 | break; | ||
251 | |||
252 | default: | ||
253 | |||
254 | // Acknowledgements and other such stuff should go directly to the blocking Queue | ||
255 | // Throttling them may and likely 'will' be problematic | ||
256 | PacketQueue.Enqueue(item); | ||
257 | break; | ||
258 | } | ||
259 | //OutgoingPacketQueue.Enqueue(item); | ||
217 | } | 260 | } |
218 | 261 | ||
219 | # region Low Level Packet Methods | 262 | # region Low Level Packet Methods |
@@ -228,7 +271,7 @@ namespace OpenSim.Region.ClientStack | |||
228 | ack_it.Packets[0].ID = Pack.Header.Sequence; | 271 | ack_it.Packets[0].ID = Pack.Header.Sequence; |
229 | ack_it.Header.Reliable = false; | 272 | ack_it.Header.Reliable = false; |
230 | 273 | ||
231 | OutPacket(ack_it, ThrottleOutPacketType.Task); | 274 | OutPacket(ack_it, ThrottleOutPacketType.Unknown); |
232 | } | 275 | } |
233 | /* | 276 | /* |
234 | if (Pack.Header.Reliable) | 277 | if (Pack.Header.Reliable) |
@@ -289,7 +332,7 @@ namespace OpenSim.Region.ClientStack | |||
289 | } | 332 | } |
290 | 333 | ||
291 | acks.Header.Reliable = false; | 334 | acks.Header.Reliable = false; |
292 | OutPacket(acks, ThrottleOutPacketType.Task); | 335 | OutPacket(acks, ThrottleOutPacketType.Unknown); |
293 | 336 | ||
294 | PendingAcks.Clear(); | 337 | PendingAcks.Clear(); |
295 | } | 338 | } |
@@ -314,6 +357,7 @@ namespace OpenSim.Region.ClientStack | |||
314 | 357 | ||
315 | public Packet Packet; | 358 | public Packet Packet; |
316 | public bool Incoming; | 359 | public bool Incoming; |
360 | public ThrottleOutPacketType throttleType; | ||
317 | } | 361 | } |
318 | 362 | ||
319 | #endregion | 363 | #endregion |
diff --git a/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs b/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs index 7f762b6..93c12a6 100644 --- a/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs +++ b/OpenSim/Region/ClientStack/ClientView.ProcessPackets.cs | |||
@@ -781,12 +781,9 @@ namespace OpenSim.Region.ClientStack | |||
781 | } | 781 | } |
782 | break; | 782 | break; |
783 | 783 | ||
784 | #endregion | ||
785 | |||
786 | #region unimplemented handlers | ||
787 | case PacketType.AgentThrottle: | 784 | case PacketType.AgentThrottle: |
788 | 785 | ||
789 | //OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet " + Pack.ToString()); | 786 | OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet " + Pack.ToString()); |
790 | 787 | ||
791 | AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; | 788 | AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; |
792 | 789 | ||
@@ -803,7 +800,7 @@ namespace OpenSim.Region.ClientStack | |||
803 | 800 | ||
804 | //Agent Throttle Block contains 7 single floatingpoint values. | 801 | //Agent Throttle Block contains 7 single floatingpoint values. |
805 | int j = 0; | 802 | int j = 0; |
806 | 803 | ||
807 | // Some Systems may be big endian... | 804 | // Some Systems may be big endian... |
808 | // it might be smart to do this check more often... | 805 | // it might be smart to do this check more often... |
809 | if (!BitConverter.IsLittleEndian) | 806 | if (!BitConverter.IsLittleEndian) |
@@ -813,22 +810,22 @@ namespace OpenSim.Region.ClientStack | |||
813 | // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_ | 810 | // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_ |
814 | // bytes | 811 | // bytes |
815 | // Convert to integer, since.. the full fp space isn't used. | 812 | // Convert to integer, since.. the full fp space isn't used. |
816 | tResend = (int)BitConverter.ToSingle(throttle, j); | 813 | tResend = (int)BitConverter.ToSingle(throttle, j); |
817 | j += singlefloat; | 814 | j += singlefloat; |
818 | tLand = (int)BitConverter.ToSingle(throttle, j); | 815 | tLand = (int)BitConverter.ToSingle(throttle, j); |
819 | j += singlefloat; | 816 | j += singlefloat; |
820 | tWind = (int)BitConverter.ToSingle(throttle, j); | 817 | tWind = (int)BitConverter.ToSingle(throttle, j); |
821 | j += singlefloat; | 818 | j += singlefloat; |
822 | tCloud = (int)BitConverter.ToSingle(throttle, j); | 819 | tCloud = (int)BitConverter.ToSingle(throttle, j); |
823 | j += singlefloat; | 820 | j += singlefloat; |
824 | tTask = (int)BitConverter.ToSingle(throttle, j); | 821 | tTask = (int)BitConverter.ToSingle(throttle, j); |
825 | j += singlefloat; | 822 | j += singlefloat; |
826 | tTexture = (int)BitConverter.ToSingle(throttle, j); | 823 | tTexture = (int)BitConverter.ToSingle(throttle, j); |
827 | j += singlefloat; | 824 | j += singlefloat; |
828 | tAsset = (int)BitConverter.ToSingle(throttle, j); | 825 | tAsset = (int)BitConverter.ToSingle(throttle, j); |
829 | 826 | ||
830 | tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; | 827 | tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; |
831 | OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "unhandled packet AgentThrottle - Got throttle:resendbytes=" + tResend + | 828 | OpenSim.Framework.Console.MainLog.Instance.Verbose("CLIENT", "Client AgentThrottle - Got throttle:resendbytes=" + tResend + |
832 | " landbytes=" + tLand + | 829 | " landbytes=" + tLand + |
833 | " windbytes=" + tWind + | 830 | " windbytes=" + tWind + |
834 | " cloudbytes=" + tCloud + | 831 | " cloudbytes=" + tCloud + |
@@ -836,9 +833,233 @@ namespace OpenSim.Region.ClientStack | |||
836 | " texturebytes=" + tTexture + | 833 | " texturebytes=" + tTexture + |
837 | " Assetbytes=" + tAsset + | 834 | " Assetbytes=" + tAsset + |
838 | " Allbytes=" + tall); | 835 | " Allbytes=" + tall); |
836 | // Total Sanity | ||
837 | // Make sure that the client sent sane total values. | ||
838 | |||
839 | // If the client didn't send acceptable values.... | ||
840 | // Scale the clients values down until they are acceptable. | ||
841 | |||
842 | if (tall <= throttleOutboundMax) | ||
843 | { | ||
844 | // Sanity | ||
845 | // Making sure the client sends sane values | ||
846 | // This gives us a measure of control of the comms | ||
847 | // Check Max of Type | ||
848 | // Then Check Min of type | ||
849 | |||
850 | // Resend throttle | ||
851 | if (tResend <= ResendthrottleMAX) | ||
852 | ResendthrottleOutbound = tResend; | ||
853 | |||
854 | if (tResend < ResendthrottleMin) | ||
855 | ResendthrottleOutbound = ResendthrottleMin; | ||
856 | |||
857 | // Land throttle | ||
858 | if (tLand <= LandthrottleMax) | ||
859 | LandthrottleOutbound = tLand; | ||
860 | |||
861 | if (tLand < LandthrottleMin) | ||
862 | LandthrottleOutbound = LandthrottleMin; | ||
863 | |||
864 | // Wind throttle | ||
865 | if (tWind <= WindthrottleMax) | ||
866 | WindthrottleOutbound = tWind; | ||
867 | |||
868 | if (tWind < WindthrottleMin) | ||
869 | WindthrottleOutbound = WindthrottleMin; | ||
870 | |||
871 | // Cloud throttle | ||
872 | if (tCloud <= CloudthrottleMax) | ||
873 | CloudthrottleOutbound = tCloud; | ||
874 | |||
875 | if (tCloud < CloudthrottleMin) | ||
876 | CloudthrottleOutbound = CloudthrottleMin; | ||
877 | |||
878 | // Task throttle | ||
879 | if (tTask <= TaskthrottleMax) | ||
880 | TaskthrottleOutbound = tTask; | ||
881 | |||
882 | if (tTask < TaskthrottleMin) | ||
883 | TaskthrottleOutbound = TaskthrottleMin; | ||
884 | |||
885 | // Texture throttle | ||
886 | if (tTexture <= TexturethrottleMax) | ||
887 | TexturethrottleOutbound = tTexture; | ||
888 | |||
889 | if (tTexture < TexturethrottleMin) | ||
890 | TexturethrottleOutbound = TexturethrottleMin; | ||
891 | |||
892 | //Asset throttle | ||
893 | if (tAsset <= AssetthrottleMax) | ||
894 | AssetthrottleOutbound = tAsset; | ||
895 | |||
896 | if (tAsset < AssetthrottleMin) | ||
897 | AssetthrottleOutbound = AssetthrottleMin; | ||
898 | |||
899 | OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound + | ||
900 | " landbytes=" + LandthrottleOutbound + | ||
901 | " windbytes=" + WindthrottleOutbound + | ||
902 | " cloudbytes=" + CloudthrottleOutbound + | ||
903 | " taskbytes=" + TaskthrottleOutbound + | ||
904 | " texturebytes=" + TexturethrottleOutbound + | ||
905 | " Assetbytes=" + AssetthrottleOutbound + | ||
906 | " Allbytes=" + tall); | ||
907 | } | ||
908 | else | ||
909 | { | ||
910 | // The client didn't send acceptable values.. | ||
911 | // so it's our job now to turn them into acceptable values | ||
912 | // We're going to first scale the values down | ||
913 | // After that we're going to check if the scaled values are sane | ||
914 | |||
915 | // We're going to be dividing by a user value.. so make sure | ||
916 | // we don't get a divide by zero error. | ||
917 | if (tall > 0) | ||
918 | { | ||
919 | // Find out the percentage of all communications | ||
920 | // the client requests for each type. We'll keep resend at | ||
921 | // it's client recommended level (won't scale it down) | ||
922 | // unless it's beyond sane values itself. | ||
923 | |||
924 | if (tResend <= ResendthrottleMAX) | ||
925 | { | ||
926 | // This is nexted because we only want to re-set the values | ||
927 | // the packet throttler uses once. | ||
928 | |||
929 | if (tResend >= ResendthrottleMin) | ||
930 | { | ||
931 | ResendthrottleOutbound = tResend; | ||
932 | } | ||
933 | else | ||
934 | { | ||
935 | ResendthrottleOutbound = ResendthrottleMin; | ||
936 | } | ||
937 | } | ||
938 | else | ||
939 | { | ||
940 | ResendthrottleOutbound = ResendthrottleMAX; | ||
941 | } | ||
942 | |||
943 | |||
944 | // Getting Percentages of communication for each type of data | ||
945 | float LandPercent = (float)(tLand / tall); | ||
946 | float WindPercent = (float)(tWind / tall); | ||
947 | float CloudPercent = (float)(tCloud / tall); | ||
948 | float TaskPercent = (float)(tTask / tall); | ||
949 | float TexturePercent = (float)(tTexture / tall); | ||
950 | float AssetPercent = (float)(tAsset / tall); | ||
951 | |||
952 | // Okay.. now we've got the percentages of total communication. | ||
953 | // Apply them to a new max total | ||
954 | |||
955 | int tLandResult = (int)(LandPercent * throttleOutboundMax); | ||
956 | int tWindResult = (int)(WindPercent * throttleOutboundMax); | ||
957 | int tCloudResult = (int)(CloudPercent * throttleOutboundMax); | ||
958 | int tTaskResult = (int)(TaskPercent * throttleOutboundMax); | ||
959 | int tTextureResult = (int)(TexturePercent * throttleOutboundMax); | ||
960 | int tAssetResult = (int)(AssetPercent * throttleOutboundMax); | ||
961 | |||
962 | // Now we have to check our scaled values for sanity | ||
963 | |||
964 | // Check Max of Type | ||
965 | // Then Check Min of type | ||
966 | |||
967 | // Land throttle | ||
968 | if (tLandResult <= LandthrottleMax) | ||
969 | LandthrottleOutbound = tLandResult; | ||
970 | |||
971 | if (tLandResult < LandthrottleMin) | ||
972 | LandthrottleOutbound = LandthrottleMin; | ||
973 | |||
974 | // Wind throttle | ||
975 | if (tWindResult <= WindthrottleMax) | ||
976 | WindthrottleOutbound = tWindResult; | ||
977 | |||
978 | if (tWindResult < WindthrottleMin) | ||
979 | WindthrottleOutbound = WindthrottleMin; | ||
980 | |||
981 | // Cloud throttle | ||
982 | if (tCloudResult <= CloudthrottleMax) | ||
983 | CloudthrottleOutbound = tCloudResult; | ||
984 | |||
985 | if (tCloudResult < CloudthrottleMin) | ||
986 | CloudthrottleOutbound = CloudthrottleMin; | ||
987 | |||
988 | // Task throttle | ||
989 | if (tTaskResult <= TaskthrottleMax) | ||
990 | TaskthrottleOutbound = tTaskResult; | ||
991 | |||
992 | if (tTaskResult < TaskthrottleMin) | ||
993 | TaskthrottleOutbound = TaskthrottleMin; | ||
994 | |||
995 | // Texture throttle | ||
996 | if (tTextureResult <= TexturethrottleMax) | ||
997 | TexturethrottleOutbound = tTextureResult; | ||
998 | |||
999 | if (tTextureResult < TexturethrottleMin) | ||
1000 | TexturethrottleOutbound = TexturethrottleMin; | ||
1001 | |||
1002 | //Asset throttle | ||
1003 | if (tAssetResult <= AssetthrottleMax) | ||
1004 | AssetthrottleOutbound = tAssetResult; | ||
1005 | |||
1006 | if (tAssetResult < AssetthrottleMin) | ||
1007 | AssetthrottleOutbound = AssetthrottleMin; | ||
1008 | |||
1009 | OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound + | ||
1010 | " landbytes=" + LandthrottleOutbound + | ||
1011 | " windbytes=" + WindthrottleOutbound + | ||
1012 | " cloudbytes=" + CloudthrottleOutbound + | ||
1013 | " taskbytes=" + TaskthrottleOutbound + | ||
1014 | " texturebytes=" + TexturethrottleOutbound + | ||
1015 | " Assetbytes=" + AssetthrottleOutbound + | ||
1016 | " Allbytes=" + tall); | ||
1017 | |||
1018 | } | ||
1019 | else | ||
1020 | { | ||
1021 | |||
1022 | // The client sent a stupid value.. | ||
1023 | // We're going to set the throttles to the minimum possible | ||
1024 | ResendthrottleOutbound = ResendthrottleMin; | ||
1025 | LandthrottleOutbound = LandthrottleMin; | ||
1026 | WindthrottleOutbound = WindthrottleMin; | ||
1027 | CloudthrottleOutbound = CloudthrottleMin; | ||
1028 | TaskthrottleOutbound = TaskthrottleMin; | ||
1029 | TexturethrottleOutbound = TexturethrottleMin; | ||
1030 | AssetthrottleOutbound = AssetthrottleMin; | ||
1031 | OpenSim.Framework.Console.MainLog.Instance.Verbose("THROTTLE", "ClientSentBadThrottle Using:resendbytes=" + ResendthrottleOutbound + | ||
1032 | " landbytes=" + LandthrottleOutbound + | ||
1033 | " windbytes=" + WindthrottleOutbound + | ||
1034 | " cloudbytes=" + CloudthrottleOutbound + | ||
1035 | " taskbytes=" + TaskthrottleOutbound + | ||
1036 | " texturebytes=" + TexturethrottleOutbound + | ||
1037 | " Assetbytes=" + AssetthrottleOutbound + | ||
1038 | " Allbytes=" + tall); | ||
1039 | } | ||
1040 | |||
1041 | } | ||
1042 | // Reset Client Throttles | ||
1043 | // This has the effect of 'wiggling the slider | ||
1044 | // causes prim and stuck textures that didn't download to download | ||
1045 | |||
1046 | ResendthrottleSentPeriod = 0; | ||
1047 | LandthrottleSentPeriod = 0; | ||
1048 | WindthrottleSentPeriod = 0; | ||
1049 | CloudthrottleSentPeriod = 0; | ||
1050 | TaskthrottleSentPeriod = 0; | ||
1051 | AssetthrottleSentPeriod = 0; | ||
1052 | TexturethrottleSentPeriod = 0; | ||
1053 | |||
1054 | //Yay, we've finally handled the agent Throttle packet! | ||
839 | 1055 | ||
840 | 1056 | ||
1057 | |||
841 | break; | 1058 | break; |
1059 | |||
1060 | #endregion | ||
1061 | |||
1062 | #region unimplemented handlers | ||
842 | case PacketType.StartPingCheck: | 1063 | case PacketType.StartPingCheck: |
843 | // Send the client the ping response back | 1064 | // Send the client the ping response back |
844 | // Pass the same PingID in the matching packet | 1065 | // Pass the same PingID in the matching packet |
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"); |