aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
authorJohn Hurliman2009-10-21 11:59:48 -0700
committerJohn Hurliman2009-10-21 11:59:48 -0700
commit9178537e9414478f0a9bd84bb5e106b2f15640c3 (patch)
treec21bca46c08cdc9868ca7608856f51d029207aab /OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
parentFixed the way OnQueueEmpty is called to prevent simultaneous calls for the sa... (diff)
downloadopensim-SC-9178537e9414478f0a9bd84bb5e106b2f15640c3.zip
opensim-SC-9178537e9414478f0a9bd84bb5e106b2f15640c3.tar.gz
opensim-SC-9178537e9414478f0a9bd84bb5e106b2f15640c3.tar.bz2
opensim-SC-9178537e9414478f0a9bd84bb5e106b2f15640c3.tar.xz
* Replaced the UnackedPacketCollection with a lockless implementation. The tiny amount of time spent in the locks turned into a lot of time when the rest of the LLUDP implementation went lockless
* Changed the timer tracking numbers for each client to not have "memory". It will no longer queue up calls to functions like ResendUnacked * Reverted Jim's WaitHandle code. Although it was technically more correct, it exhibited the exact same behavior as the old code but spent more cycles. The 20ms has been replaced with the minimum amount of time before a token bucket could receive a drip, and an else { sleep(0); } was added to make sure the outgoing packet handler always yields at least a minimum amount
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs143
1 files changed, 45 insertions, 98 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 7d5c11e..a8ce102 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -121,12 +121,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
121 private int m_recvBufferSize; 121 private int m_recvBufferSize;
122 /// <summary>Flag to process packets asynchronously or synchronously</summary> 122 /// <summary>Flag to process packets asynchronously or synchronously</summary>
123 private bool m_asyncPacketHandling; 123 private bool m_asyncPacketHandling;
124 /// <summary>Track the minimum amount of time needed to send the next packet in the 124 /// <summary>Tracks whether or not a packet was sent each round so we know
125 /// OutgoingPacketHandler loop so we know when to sleep</summary> 125 /// whether or not to sleep</summary>
126 private int m_minTimeout = Int32.MaxValue; 126 private bool m_packetSent;
127 /// <summary>EventWaitHandle to signify the outgoing packet handler thread that
128 /// there is more work to do</summary>
129 private EventWaitHandle m_outgoingWaitHandle;
130 127
131 public Socket Server { get { return null; } } 128 public Socket Server { get { return null; } }
132 129
@@ -174,8 +171,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
174 171
175 base.Start(m_recvBufferSize, m_asyncPacketHandling); 172 base.Start(m_recvBufferSize, m_asyncPacketHandling);
176 173
177 m_outgoingWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
178
179 // Start the incoming packet processing thread 174 // Start the incoming packet processing thread
180 Thread incomingThread = new Thread(IncomingPacketHandler); 175 Thread incomingThread = new Thread(IncomingPacketHandler);
181 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")"; 176 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")";
@@ -190,8 +185,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
190 { 185 {
191 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 186 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
192 base.Stop(); 187 base.Stop();
193
194 m_outgoingWaitHandle.Close();
195 } 188 }
196 189
197 public void AddScene(IScene scene) 190 public void AddScene(IScene scene)
@@ -374,10 +367,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
374 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); 367 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
375 pc.Header.Reliable = false; 368 pc.Header.Reliable = false;
376 369
377 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
378
379 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; 370 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
380 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; 371 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
372 pc.PingID.OldestUnacked = 0;
381 373
382 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 374 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
383 } 375 }
@@ -397,39 +389,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
397 return; 389 return;
398 } 390 }
399 391
400 if (udpClient.NeedAcks.Count > 0) 392 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
393 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
394
395 if (expiredPackets != null)
401 { 396 {
402 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO 397 m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
403 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
404 398
405 if (expiredPackets != null) 399 // Resend packets
400 for (int i = 0; i < expiredPackets.Count; i++)
406 { 401 {
407 m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID); 402 OutgoingPacket outgoingPacket = expiredPackets[i];
408 403
409 // Resend packets 404 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
410 for (int i = 0; i < expiredPackets.Count; i++) 405 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
411 {
412 OutgoingPacket outgoingPacket = expiredPackets[i];
413
414 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
415 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
416 406
417 // Set the resent flag 407 // Set the resent flag
418 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 408 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
419 outgoingPacket.Category = ThrottleOutPacketType.Resend; 409 outgoingPacket.Category = ThrottleOutPacketType.Resend;
420 410
421 // The TickCount will be set to the current time when the packet 411 // The TickCount will be set to the current time when the packet
422 // is actually sent out again 412 // is actually sent out again
423 outgoingPacket.TickCount = 0; 413 outgoingPacket.TickCount = 0;
424 414
425 // Bump up the resend count on this packet 415 // Bump up the resend count on this packet
426 Interlocked.Increment(ref outgoingPacket.ResendCount); 416 Interlocked.Increment(ref outgoingPacket.ResendCount);
427 //Interlocked.Increment(ref Stats.ResentPackets); 417 //Interlocked.Increment(ref Stats.ResentPackets);
428 418
429 // Requeue or resend the packet 419 // Requeue or resend the packet
430 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 420 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
431 SendPacketFinal(outgoingPacket); 421 SendPacketFinal(outgoingPacket);
432 }
433 } 422 }
434 } 423 }
435 } 424 }
@@ -577,11 +566,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
577 // Handle appended ACKs 566 // Handle appended ACKs
578 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 567 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
579 { 568 {
580 lock (udpClient.NeedAcks.SyncRoot) 569 for (int i = 0; i < packet.Header.AckList.Length; i++)
581 { 570 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent);
582 for (int i = 0; i < packet.Header.AckList.Length; i++)
583 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
584 }
585 } 571 }
586 572
587 // Handle PacketAck packets 573 // Handle PacketAck packets
@@ -589,11 +575,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
589 { 575 {
590 PacketAckPacket ackPacket = (PacketAckPacket)packet; 576 PacketAckPacket ackPacket = (PacketAckPacket)packet;
591 577
592 lock (udpClient.NeedAcks.SyncRoot) 578 for (int i = 0; i < ackPacket.Packets.Length; i++)
593 { 579 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent);
594 for (int i = 0; i < ackPacket.Packets.Length; i++)
595 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
596 }
597 580
598 // We don't need to do anything else with PacketAck packets 581 // We don't need to do anything else with PacketAck packets
599 return; 582 return;
@@ -734,21 +717,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 client.Close(); 717 client.Close();
735 } 718 }
736 719
737 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
738 {
739 OutgoingPacket ackedPacket;
740 if (client.NeedAcks.RemoveUnsafe(ack, out ackedPacket) && !fromResend)
741 {
742 // Update stats
743 Interlocked.Add(ref client.UnackedBytes, -ackedPacket.Buffer.DataLength);
744
745 // Calculate the round-trip time for this packet and its ACK
746 int rtt = currentTime - ackedPacket.TickCount;
747 if (rtt > 0)
748 client.UpdateRoundTrip(rtt);
749 }
750 }
751
752 private void IncomingPacketHandler() 720 private void IncomingPacketHandler()
753 { 721 {
754 // Set this culture for the thread that incoming packets are received 722 // Set this culture for the thread that incoming packets are received
@@ -775,11 +743,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
775 packetInbox.Clear(); 743 packetInbox.Clear();
776 } 744 }
777 745
778 public bool SignalOutgoingPacketHandler()
779 {
780 return m_outgoingWaitHandle.Set();
781 }
782
783 private void OutgoingPacketHandler() 746 private void OutgoingPacketHandler()
784 { 747 {
785 // Set this culture for the thread that outgoing packets are sent 748 // Set this culture for the thread that outgoing packets are sent
@@ -790,28 +753,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
790 { 753 {
791 try 754 try
792 { 755 {
793 m_minTimeout = Int32.MaxValue; 756 m_packetSent = false;
794 757
795 // Handle outgoing packets, resends, acknowledgements, and pings for each 758 // Handle outgoing packets, resends, acknowledgements, and pings for each
796 // client. m_minTimeout will be set to 0 if more packets are waiting in the 759 // client. m_packetSent will be set to true if a packet is sent
797 // queues with bandwidth to spare, or the number of milliseconds we need to
798 // wait before at least one packet can be sent to a client
799 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); 760 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
800 761
801 // Can't wait for a negative amount of time, and put a 100ms ceiling on our 762 // If a packet was sent, only do a minimum length context switch to allow
802 // maximum wait time 763 // other parts of the code to do work. If nothing was sent, sleep for the
803 m_minTimeout = Utils.Clamp(m_minTimeout, 0, 100); 764 // minimum amount of time before a token bucket could get more tokens
804 765 if (m_packetSent)
805 if (m_minTimeout > 0) 766 Thread.Sleep(0);
806 { 767 else
807 // Don't bother waiting for a shorter interval than our TickCountResolution 768 Thread.Sleep((int)TickCountResolution);
808 // since the token buckets wouldn't update anyways
809 m_minTimeout = Math.Max(m_minTimeout, (int)TickCountResolution);
810
811 // Wait for someone to signal that packets are ready to be sent, or for our
812 // sleep interval to expire
813 m_outgoingWaitHandle.WaitOne(m_minTimeout);
814 }
815 } 769 }
816 catch (Exception ex) 770 catch (Exception ex)
817 { 771 {
@@ -841,7 +795,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
841 if (udpClient.ElapsedMSOutgoingPacketHandler >= 100) 795 if (udpClient.ElapsedMSOutgoingPacketHandler >= 100)
842 { 796 {
843 ResendUnacked(udpClient); 797 ResendUnacked(udpClient);
844 udpClient.ElapsedMSOutgoingPacketHandler -= 100; 798 udpClient.ElapsedMSOutgoingPacketHandler = 0;
845 udpClient.Elapsed100MSOutgoingPacketHandler += 1; 799 udpClient.Elapsed100MSOutgoingPacketHandler += 1;
846 } 800 }
847 801
@@ -849,7 +803,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
849 if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5) 803 if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5)
850 { 804 {
851 SendAcks(udpClient); 805 SendAcks(udpClient);
852 udpClient.Elapsed100MSOutgoingPacketHandler -= 5; 806 udpClient.Elapsed100MSOutgoingPacketHandler = 0;
853 udpClient.Elapsed500MSOutgoingPacketHandler += 1; 807 udpClient.Elapsed500MSOutgoingPacketHandler += 1;
854 } 808 }
855 809
@@ -857,19 +811,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
857 if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10) 811 if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10)
858 { 812 {
859 SendPing(udpClient); 813 SendPing(udpClient);
860 udpClient.Elapsed500MSOutgoingPacketHandler -= 10; 814 udpClient.Elapsed500MSOutgoingPacketHandler = 0;
861 } 815 }
862 816
863 // Dequeue any outgoing packets that are within the throttle limits 817 // Dequeue any outgoing packets that are within the throttle limits
864 // and get the minimum time we would have to sleep before this client 818 if (udpClient.DequeueOutgoing())
865 // could send a packet out 819 m_packetSent = true;
866 int minTimeoutThisLoop = udpClient.DequeueOutgoing();
867
868 // Although this is not thread safe, it is cheaper than locking and the
869 // worst that will happen is we sleep for slightly longer than the
870 // minimum necessary interval
871 if (minTimeoutThisLoop < m_minTimeout)
872 m_minTimeout = minTimeoutThisLoop;
873 } 820 }
874 821
875 udpClient.TickLastOutgoingPacketHandler = thisTick; 822 udpClient.TickLastOutgoingPacketHandler = thisTick;