Given the following contact:
/// <summary> /// Thread Safety - This is NOT a thread safe connection /// Exception Safety - After an exception is thrown, it should be disposed and not used afterward /// Connection Pooling - It is expected that this will be part of a connection pool /// </summary> public class DistributedHashTableStorageClient
I decided that I needed to really didn’t want to pass the responsibility for that to the client, and that I wanted to handle that inside my library. Here is what I came up with:
public class DefaultConnectionPool { private static readonly ILog log = LogManager.GetLogger(typeof (DefaultConnectionPool)); readonly object locker = new object(); private readonly Dictionary<NodeEndpoint, LinkedList<PooledDistributedHashTableStorageClientConnection>> pooledConnections = new Dictionary<NodeEndpoint, LinkedList<PooledDistributedHashTableStorageClientConnection>>(); public IDistributedHashTableStorage Create(NodeEndpoint endpoint) { PooledDistributedHashTableStorageClientConnection storage = null; lock (locker) { LinkedList<PooledDistributedHashTableStorageClientConnection> value; if (pooledConnections.TryGetValue(endpoint, out value) && value.Count > 0) { storage = value.First.Value; value.RemoveFirst(); } } if (storage != null) { if (storage.Connected == false) { log.DebugFormat("Found unconnected connection in the pool for {0}", endpoint.Sync); try { storage.Dispose(); } catch (Exception e) { log.Debug("Error when disposing unconnected connection in the pool", e); } } else { return storage; } } log.DebugFormat("Creating new connection in the pool to {0}", endpoint.Sync); return new PooledDistributedHashTableStorageClientConnection(this, endpoint); } private void PutMeBack(PooledDistributedHashTableStorageClientConnection connection) { lock (locker) { LinkedList<PooledDistributedHashTableStorageClientConnection> value; if (pooledConnections.TryGetValue(connection.Endpoint, out value) == false) { pooledConnections[connection.Endpoint] = value = new LinkedList<PooledDistributedHashTableStorageClientConnection>(); } value.AddLast(connection); } log.DebugFormat("Put connection for {0} back in the pool", connection.Endpoint.Sync); } class PooledDistributedHashTableStorageClientConnection : DistributedHashTableStorageClient { private readonly DefaultConnectionPool pool; public PooledDistributedHashTableStorageClientConnection( DefaultConnectionPool pool, NodeEndpoint endpoint) : base(endpoint) { this.pool = pool; } public bool Connected { get { return client.Connected; } } public override void Dispose() { if(Marshal.GetExceptionCode() != 0)//we are here because of some sort of error { log.Debug("There was an error during the usage of pooled client connection, will not return it to the pool (may be poisioned)"); base.Dispose(); } else if(Connected == false) { log.Debug("The connection was disconnected, will not return connection to the pool"); base.Dispose(); } else { pool.PutMeBack(this); } } } }
I think that should pretty much cover everything I need.
Thoughts?
