]> git.deb.at Git - rhonda/impostor.hazel.git/commitdiff
Added recycling
authorJamJar00 <jamster.30@btinternet.com>
Mon, 16 May 2016 16:51:52 +0000 (17:51 +0100)
committerJamJar00 <jamster.30@btinternet.com>
Mon, 16 May 2016 16:51:52 +0000 (17:51 +0100)
14 files changed:
Hazel/Connection.cs
Hazel/ConnectionListener.cs
Hazel/DataEventArgs.cs
Hazel/DisconnectedEventArgs.cs
Hazel/Hazel.csproj
Hazel/IRecyclable.cs [new file with mode: 0644]
Hazel/NewConnectionEventArgs.cs
Hazel/ObjectPool.cs [new file with mode: 0644]
Hazel/TcpConnection.cs
Hazel/TcpConnectionListener.cs
Hazel/UdpClientConnection.cs
Hazel/UdpConnection.Reliable.cs
Hazel/UdpConnectionListener.cs
Hazel/UdpServerConnection.cs

index 72cd2457527fdcaaf4ccc23c665e93f8d8faad88..3418f63ac2929d6ca8649040e2da21a66f9d4ced 100644 (file)
@@ -98,9 +98,13 @@ namespace Hazel
         /// <summary>
         ///     Invokes the DataReceived event to alert subscribers we received data.
         /// </summary>
-        /// <param name="args">The arguments to supply.</param>
-        protected void InvokeDataReceived(DataEventArgs args)
+        /// <param name="bytes">The bytes to supply.</param>
+        /// <param name="sendOption">The sendOption to supply.</param>
+        protected void InvokeDataReceived(byte[] bytes, SendOption sendOption)
         {
+            DataEventArgs args = DataEventArgs.GetObject();
+            args.Set(bytes, sendOption);
+
             //Make a copy to avoid race condition between null check and invocation
             EventHandler<DataEventArgs> handler = DataReceived;
             if (handler != null)
@@ -110,9 +114,12 @@ namespace Hazel
         /// <summary>
         ///     Invokes the Disconnected event to alert hooked up methods there was an error or the remote end point disconnected.
         /// </summary>
-        /// <param name="args">The arguments to supply.</param>
-        protected void InvokeDisconnected(DisconnectedEventArgs args)
+        /// <param name="e">The exception, if any, that occured to cause this.</param>
+        protected void InvokeDisconnected(Exception e)
         {
+            DisconnectedEventArgs args = DisconnectedEventArgs.GetObject();
+            args.Set(e);
+
             //Make a copy to avoid race condition between null check and invocation
             EventHandler<DisconnectedEventArgs> handler = Disconnected;
             if (handler != null)
index 640bf4c8808ba356da79d5faa5be55df29d07941..60452c4eefab46108fc7ffbeb3309ed0a7fa5b1b 100644 (file)
@@ -26,8 +26,12 @@ namespace Hazel
         ///     Invokes the NewConnection event with the supplied args.
         /// </summary>
         /// <param name="args">The arguments for the event.</param>
-        protected void FireNewConnectionEvent(NewConnectionEventArgs args)
+        protected void InvokeNewConnection(Connection connection)
         {
+            //Get new args
+            NewConnectionEventArgs args = NewConnectionEventArgs.GetObject();
+            args.Set(connection);
+
             //Make a copy to avoid race condition between null check and invocation
             EventHandler<NewConnectionEventArgs> handler = NewConnection;
             if (handler != null)
index 9c87cf5d809ca00b12da8fd23fd5f66a996c1f8a..a1cb0592356fa77ae3820d6944b59724dfde3b1a 100644 (file)
@@ -12,8 +12,22 @@ using System.Text;
 
 namespace Hazel
 {
-    public class DataEventArgs : EventArgs
+    public class DataEventArgs : EventArgs, IRecyclable
     {
+        /// <summary>
+        ///     Object pool for this event.
+        /// </summary>
+        static readonly ObjectPool<DataEventArgs> objectPool = new ObjectPool<DataEventArgs>(() => new DataEventArgs());
+
+        /// <summary>
+        ///     Returns an instance of this object from the pool.
+        /// </summary>
+        /// <returns></returns>
+        internal static DataEventArgs GetObject()
+        {
+            return objectPool.GetObject();
+        }
+
         /// <summary>
         ///     The bytes received.
         /// </summary>
@@ -25,13 +39,30 @@ namespace Hazel
         public object SendOption { get; private set; }
 
         /// <summary>
-        ///     Creates DataEventArgs from bytes received.
+        ///     Private constructor for object pool.
         /// </summary>
-        /// <param name="bytes"></param>
-        public DataEventArgs(byte[] bytes, SendOption sendOption)
+        DataEventArgs()
+        {
+
+        }
+
+        /// <summary>
+        ///     Sets the members of the arguments.
+        /// </summary>
+        /// <param name="bytes">The bytes received.</param>
+        /// <param name="sendOption">The send option used to send the data.</param>
+        internal void Set(byte[] bytes, SendOption sendOption)
         {
             this.Bytes = bytes;
             this.SendOption = sendOption;
         }
+
+        /// <summary>
+        ///     Returns this object back to the object pool.
+        /// </summary>
+        public void Recycle()
+        {
+            objectPool.PutObject(this);
+        }
     }
 }
index c4b9a0b3f519c0ebfa1ca3ffa8c112d0d2987e15..4468eef94b15abbdeca658478dd5566dfec8c60b 100644 (file)
@@ -8,20 +8,50 @@ namespace Hazel
     /// <summary>
     ///     Events args for disconnected events.
     /// </summary>
-    public class DisconnectedEventArgs
+    public class DisconnectedEventArgs : IRecyclable
     {
+        /// <summary>
+        ///     Object pool for this event.
+        /// </summary>
+        static readonly ObjectPool<DisconnectedEventArgs> objectPool = new ObjectPool<DisconnectedEventArgs>(() => new DisconnectedEventArgs());
+
+        /// <summary>
+        ///     Returns an instance of this object from the pool.
+        /// </summary>
+        /// <returns></returns>
+        internal static DisconnectedEventArgs GetObject()
+        {
+            return objectPool.GetObject();
+        }
+
         /// <summary>
         ///     The exception, if any, that caused the disconnect, otherwise null.
         /// </summary>
         public Exception Exception { get; private set; }
 
         /// <summary>
-        ///     Creates a DisconnectedEventArgs from the given exception or null
+        ///     Private constructor for object pool.
+        /// </summary>
+        DisconnectedEventArgs()
+        {
+
+        }
+
+        /// <summary>
+        ///     Sets the given exception for the arguments.
         /// </summary>
         /// <param name="e">The exception if the cause.</param>
-        internal DisconnectedEventArgs(Exception e)
+        internal void Set(Exception e)
         {
             this.Exception = e;
         }
+
+        /// <summary>
+        ///     Returns this object back to the object pool.
+        /// </summary>
+        public void Recycle()
+        {
+            objectPool.PutObject(this);
+        }
     }
 }
index b77da7b9ee6f52a4d2bfffd8bab506b829930ec9..a4cc7dcc22159927fed35ec75e04936e2b470d81 100644 (file)
     <Compile Include="DataEventArgs.cs" />
     <Compile Include="DisconnectedEventArgs.cs" />
     <Compile Include="HazelException.cs" />
+    <Compile Include="IRecyclable.cs" />
     <Compile Include="NetworkConnection.cs" />
     <Compile Include="NetworkConnectionListener.cs" />
     <Compile Include="NetworkEndPoint.cs" />
     <Compile Include="NewConnectionEventArgs.cs" />
+    <Compile Include="ObjectPool.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SendOption.cs" />
     <Compile Include="SendOptionInternal.cs" />
diff --git a/Hazel/IRecyclable.cs b/Hazel/IRecyclable.cs
new file mode 100644 (file)
index 0000000..c044f3c
--- /dev/null
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Hazel
+{
+    /// <summary>
+    ///     Interface for all items that can be returned to an object pool.
+    /// </summary>
+    interface IRecyclable
+    {
+        /// <summary>
+        ///     Returns this object back to the object pool.
+        /// </summary>
+        void Recycle();
+    }
+}
index e4b6ab89899b00fbdd8112629bbea99267e1cb24..6cdf3aa5d9a7803524899d89c2a94b9ef0ba47ce 100644 (file)
@@ -8,16 +8,50 @@ namespace Hazel
     /// <summary>
     ///     Event args for new connection events.
     /// </summary>
-    public class NewConnectionEventArgs : EventArgs
+    public class NewConnectionEventArgs : EventArgs, IRecyclable
     {
+        /// <summary>
+        ///     Object pool for this event.
+        /// </summary>
+        static readonly ObjectPool<NewConnectionEventArgs> objectPool = new ObjectPool<NewConnectionEventArgs>(() => new NewConnectionEventArgs());
+
+        /// <summary>
+        ///     Returns an instance of this object from the pool.
+        /// </summary>
+        /// <returns></returns>
+        internal static NewConnectionEventArgs GetObject()
+        {
+            return objectPool.GetObject();
+        }
+
         /// <summary>
         ///     The new connection.
         /// </summary>
         public Connection Connection { get; private set; }
 
-        internal NewConnectionEventArgs(Connection Connection)
+        /// <summary>
+        ///     Private constructor for thread pool.
+        /// </summary>
+        NewConnectionEventArgs()
+        {
+
+        }
+
+        /// <summary>
+        ///     Sets the members of the arguments.
+        /// </summary>
+        /// <param name="Connection"></param>
+        internal void Set(Connection Connection)
         {
             this.Connection = Connection;
         }
+
+        /// <summary>
+        ///     Returns this object back to the object pool.
+        /// </summary>
+        public void Recycle()
+        {
+            objectPool.PutObject(this);
+        }
     }
 }
diff --git a/Hazel/ObjectPool.cs b/Hazel/ObjectPool.cs
new file mode 100644 (file)
index 0000000..4a05e39
--- /dev/null
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hazel
+{
+    /// <summary>
+    ///     A fairly simple object pool for items that will be created a lot.
+    /// </summary>
+    /// <typeparam name="T">The type that is pooled.</typeparam>
+    class ObjectPool<T> where T : IRecyclable
+    {
+        /// <summary>
+        ///     Our pool of objects
+        /// </summary>
+        ConcurrentBag<T> pool = new ConcurrentBag<T>();
+
+        /// <summary>
+        ///     The generator for creating new objects.
+        /// </summary>
+        /// <returns></returns>
+        Func<T> objectFactory;
+
+        /// <summary>
+        ///     Internal constructor for our ObjectPool.
+        /// </summary>
+        internal ObjectPool(Func<T> objectFactory)
+        {
+            this.objectFactory = objectFactory;
+        }
+
+        /// <summary>
+        ///     Returns a pooled object of type T, if none are available another is created.
+        /// </summary>
+        /// <returns>An instance of T.</returns>
+        internal T GetObject()
+        {
+            T item;
+            if (pool.TryTake(out item))
+                return item;
+
+            return objectFactory.Invoke();
+        }
+
+        /// <summary>
+        ///     Returns an object to the pool.
+        /// </summary>
+        /// <param name="item">The item to return.</param>
+        internal void PutObject(T item)
+        {
+            pool.Add(item);
+        }
+    }
+}
index 71eec3a092ef97488c934d0c808b60c73ed2717f..f2462f16b9313e618ae9c648e7640e3a6bb01552 100644 (file)
@@ -188,7 +188,7 @@ namespace Hazel
             Statistics.LogReceive(bytes.Length, bytes.Length + 4);
 
             //Fire DataReceived event
-            InvokeDataReceived(new DataEventArgs(bytes, SendOption.OrderedFragmentedReliable));
+            InvokeDataReceived(bytes, SendOption.OrderedFragmentedReliable);
         }
 
         /// <summary>
@@ -296,7 +296,7 @@ namespace Hazel
             //Invoke event outide lock if need be
             if (invoke)
             {
-                InvokeDisconnected(new DisconnectedEventArgs(e));
+                InvokeDisconnected(e);
 
                 Dispose();
             }
index f651008bcf3cb482f36ad946658575a848eacd0d..29e9d08215a3b45b51d2e46d6322fd0436886b5f 100644 (file)
@@ -85,9 +85,8 @@ namespace Hazel
                 //Sort the event out
                 TcpConnection tcpConnection = new TcpConnection(tcpSocket);
 
-                NewConnectionEventArgs args = new NewConnectionEventArgs(tcpConnection);
-
-                FireNewConnectionEvent(args);
+                //Invoke
+                InvokeNewConnection(tcpConnection);
 
                 tcpConnection.StartListening();
             }
index dbf48204e5f058a9d65390fe9c8ba300afccf186..08cee338f7b7e84985ed971aa694359512d0fa1f 100644 (file)
@@ -206,7 +206,7 @@ namespace Hazel
             }
             
             if (buffer != null)
-                InvokeDataReceived(new DataEventArgs(buffer, sendOption));
+                InvokeDataReceived(buffer, sendOption);
         }
 
         /// <summary>
@@ -230,7 +230,7 @@ namespace Hazel
             //Invoke event outide lock if need be
             if (invoke)
             {
-                InvokeDisconnected(new DisconnectedEventArgs(e));
+                InvokeDisconnected(e);
 
                 Dispose();
             }
index da0245520a01c9791b4a4af7a34592e86a95c209..de4677130b4f3b702b021f48092cf16f769bd193 100644 (file)
@@ -49,15 +49,34 @@ namespace Hazel
         /// <summary>
         ///     Class to hold packet data
         /// </summary>
-        class Packet
+        class Packet : IRecyclable
         {
+            /// <summary>
+            ///     Object pool for this event.
+            /// </summary>
+            static readonly ObjectPool<Packet> objectPool = new ObjectPool<Packet>(() => new Packet());
+
+            /// <summary>
+            ///     Returns an instance of this object from the pool.
+            /// </summary>
+            /// <returns></returns>
+            internal static Packet GetObject()
+            {
+                return objectPool.GetObject();
+            }
+
             public byte[] Data;
             public Timer Timer;
             public volatile int LastTimeout;
             public Action AckCallback;
-            public volatile bool Acknowledged = false;
+            public volatile bool Acknowledged;
+
+            Packet()
+            {
 
-            public Packet(byte[] data, Action<Packet> resendAction, int timeout, Action ackCallback)
+            }
+            
+            internal void Set(byte[] data, Action<Packet> resendAction, int timeout, Action ackCallback)
             {
                 Data = data;
                 
@@ -70,6 +89,15 @@ namespace Hazel
 
                 LastTimeout = timeout;
                 AckCallback = ackCallback;
+                Acknowledged = false;
+            }
+
+            /// <summary>
+            ///     Returns this object back to the object pool from whence it came.
+            /// </summary>
+            public void Recycle()
+            {
+                objectPool.PutObject(this);
             }
         }
 
@@ -93,7 +121,8 @@ namespace Hazel
                 bytes[2] = (byte)id;
 
                 //Create packet object
-                Packet packet = new Packet(
+                Packet packet = Packet.GetObject();
+                packet.Set(
                     bytes,
                     (Packet p) =>
                     {
@@ -103,7 +132,7 @@ namespace Hazel
                         lock (p.Timer)
                         {
                             if (!p.Acknowledged)
-                                p.Timer.Change(p.LastTimeout *= 2, Timeout.Infinite);
+                                p.Timer.Change(p.LastTimeout *= 2, Timeout.Infinite);       //TODO disconnect after x tries
                         }
 
                         Trace.WriteLine("Resend.");
@@ -188,6 +217,8 @@ namespace Hazel
                     if (packet.AckCallback != null)
                         packet.AckCallback.Invoke();
 
+                    packet.Recycle();
+
                     reliableDataPacketsSent.Remove(id);
                 }
             }
index 69981a21fe1ca3c8090518e14fe0344c7bb4a857..65d8484397db3e673d8d567d0fcc7f161738915d 100644 (file)
@@ -146,7 +146,7 @@ namespace Hazel
             if (aware)
                 connection.InvokeDataReceived(buffer);
             else
-                FireNewConnectionEvent(new NewConnectionEventArgs(connection));
+                InvokeNewConnection(connection);
         }
 
         /// <summary>
@@ -169,6 +169,11 @@ namespace Hazel
             {
                 throw new HazelException("Could not send data as a SocketException occured.", e);
             }
+            catch (ObjectDisposedException)
+            {
+                //Keep alive timer probably ran, ignore
+                return;
+            }
         }
 
         /// <summary>
index 5ea8a495f19cf54c932aeea7c28596a7d4bcc840..f1008a48f965b1501a6f2e4e2004b7acba468c4f 100644 (file)
@@ -85,7 +85,7 @@ namespace Hazel
            byte[] data = HandleReceive(buffer, buffer.Length);
 
            if (data != null)
-                InvokeDataReceived(new DataEventArgs(data, (SendOption)buffer[0]));
+                InvokeDataReceived(data, (SendOption)buffer[0]);
         }
 
         /// <summary>
@@ -109,7 +109,7 @@ namespace Hazel
             //Invoke event outide lock if need be
             if (invoke)
             {
-                InvokeDisconnected(new DisconnectedEventArgs(e));
+                InvokeDisconnected(e);
 
                 Dispose();
             }