1 //----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------------------
4 namespace System.ServiceModel.Channels
6 using System.Collections.Generic;
7 using System.Diagnostics;
10 using System.Runtime.Diagnostics;
11 using System.ServiceModel;
12 using System.ServiceModel.Diagnostics;
13 using System.ServiceModel.Diagnostics.Application;
15 // code that pools items and closes/aborts them as necessary.
16 // shared by IConnection and IChannel users
17 abstract class CommunicationPool<TKey, TItem>
21 Dictionary<TKey, EndpointConnectionPool> endpointPools;
24 // need to make sure we prune over a certain number of endpoint pools
26 const int pruneThreshold = 30;
28 protected CommunicationPool(int maxCount)
30 this.maxCount = maxCount;
31 this.endpointPools = new Dictionary<TKey, EndpointConnectionPool>();
35 public int MaxIdleConnectionPoolCount
37 get { return this.maxCount; }
40 protected object ThisLock
45 protected abstract void AbortItem(TItem item);
47 [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")]
48 [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")]
49 protected abstract void CloseItem(TItem item, TimeSpan timeout);
50 protected abstract void CloseItemAsync(TItem item, TimeSpan timeout);
52 protected abstract TKey GetPoolKey(EndpointAddress address, Uri via);
54 protected virtual EndpointConnectionPool CreateEndpointConnectionPool(TKey key)
56 return new EndpointConnectionPool(this, key);
59 public bool Close(TimeSpan timeout)
72 this.OnClose(timeout);
80 List<TItem> PruneIfNecessary()
82 List<TItem> itemsToClose = null;
84 if (pruneAccrual > pruneThreshold)
87 itemsToClose = new List<TItem>();
89 // first prune the connection pool contents
90 foreach (EndpointConnectionPool pool in endpointPools.Values)
92 pool.Prune(itemsToClose);
95 // figure out which connection pools are now empty
96 List<TKey> endpointKeysToRemove = null;
97 foreach (KeyValuePair<TKey, EndpointConnectionPool> poolEntry in endpointPools)
99 if (poolEntry.Value.CloseIfEmpty())
101 if (endpointKeysToRemove == null)
103 endpointKeysToRemove = new List<TKey>();
105 endpointKeysToRemove.Add(poolEntry.Key);
109 // and then prune the connection pools themselves
110 if (endpointKeysToRemove != null)
112 for (int i = 0; i < endpointKeysToRemove.Count; i++)
114 endpointPools.Remove(endpointKeysToRemove[i]);
122 EndpointConnectionPool GetEndpointPool(TKey key, TimeSpan timeout)
124 EndpointConnectionPool result = null;
125 List<TItem> itemsToClose = null;
128 if (!endpointPools.TryGetValue(key, out result))
130 itemsToClose = PruneIfNecessary();
131 result = CreateEndpointConnectionPool(key);
132 endpointPools.Add(key, result);
136 Fx.Assert(result != null, "EndpointPool must be non-null at this point");
137 if (itemsToClose != null && itemsToClose.Count > 0)
139 // allocate half the remaining timeout for our g----ful shutdowns
140 TimeoutHelper timeoutHelper = new TimeoutHelper(TimeoutHelper.Divide(timeout, 2));
141 for (int i = 0; i < itemsToClose.Count; i++)
143 result.CloseIdleConnection(itemsToClose[i], timeoutHelper.RemainingTime());
150 public bool TryOpen()
156 // can't reopen connection pools since the registry purges them on close
167 protected virtual void OnClosed()
171 void OnClose(TimeSpan timeout)
173 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
174 foreach (EndpointConnectionPool pool in endpointPools.Values)
178 pool.Close(timeoutHelper.RemainingTime());
180 catch (CommunicationException exception)
182 if (DiagnosticUtility.ShouldTraceError)
184 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ConnectionPoolCloseException, SR.GetString(SR.TraceCodeConnectionPoolCloseException), this, exception);
187 catch (TimeoutException exception)
189 if (TD.CloseTimeoutIsEnabled())
191 TD.CloseTimeout(exception.Message);
193 if (DiagnosticUtility.ShouldTraceError)
195 TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ConnectionPoolCloseException, SR.GetString(SR.TraceCodeConnectionPoolCloseException), this, exception);
200 endpointPools.Clear();
203 public void AddConnection(TKey key, TItem connection, TimeSpan timeout)
205 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
206 EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime());
207 endpointPool.AddConnection(connection, timeoutHelper.RemainingTime());
210 public TItem TakeConnection(EndpointAddress address, Uri via, TimeSpan timeout, out TKey key)
212 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
213 key = this.GetPoolKey(address, via);
214 EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime());
215 return endpointPool.TakeConnection(timeoutHelper.RemainingTime());
218 public void ReturnConnection(TKey key, TItem connection, bool connectionIsStillGood, TimeSpan timeout)
220 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
221 EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime());
222 endpointPool.ReturnConnection(connection, connectionIsStillGood, timeoutHelper.RemainingTime());
225 // base class for our collection of Idle connections
226 protected abstract class IdleConnectionPool
228 public abstract int Count { get; }
229 public abstract bool Add(TItem item);
230 public abstract bool Return(TItem item);
231 public abstract TItem Take(out bool closeItem);
234 protected class EndpointConnectionPool
237 List<TItem> busyConnections;
239 IdleConnectionPool idleConnections;
240 CommunicationPool<TKey, TItem> parent;
242 public EndpointConnectionPool(CommunicationPool<TKey, TItem> parent, TKey key)
245 this.parent = parent;
246 this.busyConnections = new List<TItem>();
251 get { return this.key; }
254 IdleConnectionPool IdleConnections
258 if (idleConnections == null)
260 idleConnections = GetIdleConnectionPool();
263 return idleConnections;
267 protected CommunicationPool<TKey, TItem> Parent
269 get { return this.parent; }
272 protected object ThisLock
277 // close down the pool if empty
278 public bool CloseIfEmpty()
284 if (busyConnections.Count > 0)
289 if (idleConnections != null && idleConnections.Count > 0)
300 protected virtual void AbortItem(TItem item)
302 parent.AbortItem(item);
305 [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")]
306 [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")]
307 protected virtual void CloseItem(TItem item, TimeSpan timeout)
309 parent.CloseItem(item, timeout);
312 protected virtual void CloseItemAsync(TItem item, TimeSpan timeout)
314 parent.CloseItemAsync(item, timeout);
324 List<TItem> idleItemsToClose = null;
331 idleItemsToClose = SnapshotIdleConnections();
334 AbortConnections(idleItemsToClose);
337 [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")]
338 [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")]
339 public void Close(TimeSpan timeout)
341 List<TItem> itemsToClose = null;
348 itemsToClose = SnapshotIdleConnections();
353 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
354 for (int i = 0; i < itemsToClose.Count; i++)
356 this.CloseItem(itemsToClose[i], timeoutHelper.RemainingTime());
359 itemsToClose.Clear();
363 AbortConnections(itemsToClose);
367 void AbortConnections(List<TItem> idleItemsToClose)
369 for (int i = 0; i < idleItemsToClose.Count; i++)
371 this.AbortItem(idleItemsToClose[i]);
374 for (int i = 0; i < busyConnections.Count; i++)
376 this.AbortItem(busyConnections[i]);
378 busyConnections.Clear();
381 // must call under lock (ThisLock) since we are calling IdleConnections.Take()
382 List<TItem> SnapshotIdleConnections()
384 List<TItem> itemsToClose = new List<TItem>();
388 TItem item = IdleConnections.Take(out dummy);
392 itemsToClose.Add(item);
398 public void AddConnection(TItem connection, TimeSpan timeout)
400 bool closeConnection = false;
405 if (!IdleConnections.Add(connection))
407 closeConnection = true;
412 closeConnection = true;
418 CloseIdleConnection(connection, timeout);
422 protected virtual IdleConnectionPool GetIdleConnectionPool()
424 return new PoolIdleConnectionPool(parent.MaxIdleConnectionPoolCount);
427 public virtual void Prune(List<TItem> itemsToClose)
431 public TItem TakeConnection(TimeSpan timeout)
434 List<TItem> itemsToClose = null;
443 item = IdleConnections.Take(out closeItem);
451 busyConnections.Add(item);
455 if (itemsToClose == null)
457 itemsToClose = new List<TItem>();
459 itemsToClose.Add(item);
463 // cleanup any stale items accrued from IdleConnections
464 if (itemsToClose != null)
466 // and only allocate half the timeout passed in for our g----ful shutdowns
467 TimeoutHelper timeoutHelper = new TimeoutHelper(TimeoutHelper.Divide(timeout, 2));
468 for (int i = 0; i < itemsToClose.Count; i++)
470 CloseIdleConnection(itemsToClose[i], timeoutHelper.RemainingTime());
474 if (TD.ConnectionPoolMissIsEnabled())
476 if (item == null && busyConnections != null)
478 TD.ConnectionPoolMiss(key != null ? key.ToString() : string.Empty, busyConnections.Count);
485 public void ReturnConnection(TItem connection, bool connectionIsStillGood, TimeSpan timeout)
487 bool closeConnection = false;
488 bool abortConnection = false;
494 if (busyConnections.Remove(connection) && connectionIsStillGood)
496 if (!IdleConnections.Return(connection))
498 closeConnection = true;
503 abortConnection = true;
508 abortConnection = true;
514 CloseIdleConnection(connection, timeout);
516 else if (abortConnection)
518 this.AbortItem(connection);
519 OnConnectionAborted();
523 public void CloseIdleConnection(TItem connection, TimeSpan timeout)
525 bool throwing = true;
528 this.CloseItemAsync(connection, timeout);
538 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
544 this.AbortItem(connection);
549 protected virtual void OnConnectionAborted()
553 protected class PoolIdleConnectionPool
556 Pool<TItem> idleConnections;
559 public PoolIdleConnectionPool(int maxCount)
561 this.idleConnections = new Pool<TItem>(maxCount);
562 this.maxCount = maxCount;
565 public override int Count
567 get { return idleConnections.Count; }
570 public override bool Add(TItem connection)
572 return ReturnToPool(connection);
575 public override bool Return(TItem connection)
577 return ReturnToPool(connection);
580 bool ReturnToPool(TItem connection)
582 bool result = this.idleConnections.Return(connection);
585 if (TD.MaxOutboundConnectionsPerEndpointExceededIsEnabled())
587 TD.MaxOutboundConnectionsPerEndpointExceeded(SR.GetString(SR.TraceCodeConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached, maxCount));
589 if (DiagnosticUtility.ShouldTraceInformation)
591 TraceUtility.TraceEvent(TraceEventType.Information,
592 TraceCode.ConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached,
593 SR.GetString(SR.TraceCodeConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached, maxCount),
597 else if (TD.OutboundConnectionsPerEndpointRatioIsEnabled())
599 TD.OutboundConnectionsPerEndpointRatio(this.idleConnections.Count, maxCount);
605 public override TItem Take(out bool closeItem)
608 TItem ret = this.idleConnections.Take();
609 if (TD.OutboundConnectionsPerEndpointRatioIsEnabled())
611 TD.OutboundConnectionsPerEndpointRatio(this.idleConnections.Count, maxCount);
619 // all our connection pools support Idling out of connections and lease timeout
620 // (though Named Pipes doesn't leverage the lease timeout)
621 abstract class ConnectionPool : IdlingCommunicationPool<string, IConnection>
623 int connectionBufferSize;
624 TimeSpan maxOutputDelay;
627 protected ConnectionPool(IConnectionOrientedTransportChannelFactorySettings settings, TimeSpan leaseTimeout)
628 : base(settings.MaxOutboundConnectionsPerEndpoint, settings.IdleTimeout, leaseTimeout)
630 this.connectionBufferSize = settings.ConnectionBufferSize;
631 this.maxOutputDelay = settings.MaxOutputDelay;
632 this.name = settings.ConnectionPoolGroupName;
637 get { return this.name; }
640 protected override void AbortItem(IConnection item)
645 protected override void CloseItem(IConnection item, TimeSpan timeout)
647 item.Close(timeout, false);
650 protected override void CloseItemAsync(IConnection item, TimeSpan timeout)
652 item.Close(timeout, true);
655 public virtual bool IsCompatible(IConnectionOrientedTransportChannelFactorySettings settings)
658 (this.name == settings.ConnectionPoolGroupName) &&
659 (this.connectionBufferSize == settings.ConnectionBufferSize) &&
660 (this.MaxIdleConnectionPoolCount == settings.MaxOutboundConnectionsPerEndpoint) &&
661 (this.IdleTimeout == settings.IdleTimeout) &&
662 (this.maxOutputDelay == settings.MaxOutputDelay)
667 // Helper class used to manage the lifetime of a connection relative to its pool.
668 abstract class ConnectionPoolHelper
670 IConnectionInitiator connectionInitiator;
671 ConnectionPool connectionPool;
675 // key for rawConnection in the connection pool
676 string connectionKey;
678 // did rawConnection originally come from connectionPool?
679 bool isConnectionFromPool;
681 // the "raw" connection that should be stored in the pool
682 IConnection rawConnection;
684 // the "upgraded" connection built on top of the "raw" connection to be used for I/O
685 IConnection upgradedConnection;
687 EventTraceActivity eventTraceActivity;
689 public ConnectionPoolHelper(ConnectionPool connectionPool, IConnectionInitiator connectionInitiator, Uri via)
691 this.connectionInitiator = connectionInitiator;
692 this.connectionPool = connectionPool;
701 protected EventTraceActivity EventTraceActivity
705 if (this.eventTraceActivity == null)
707 this.eventTraceActivity = EventTraceActivity.GetFromThreadOrCreate();
709 return this.eventTraceActivity;
713 protected abstract IConnection AcceptPooledConnection(IConnection connection, ref TimeoutHelper timeoutHelper);
714 protected abstract IAsyncResult BeginAcceptPooledConnection(IConnection connection, ref TimeoutHelper timeoutHelper,
715 AsyncCallback callback, object state);
716 protected abstract IConnection EndAcceptPooledConnection(IAsyncResult result);
718 protected abstract TimeoutException CreateNewConnectionTimeoutException(TimeSpan timeout, TimeoutException innerException);
720 public IAsyncResult BeginEstablishConnection(TimeSpan timeout, AsyncCallback callback, object state)
722 return new EstablishConnectionAsyncResult(this, timeout, callback, state);
725 public IConnection EndEstablishConnection(IAsyncResult result)
727 return EstablishConnectionAsyncResult.End(result);
730 IConnection TakeConnection(TimeSpan timeout)
732 return this.connectionPool.TakeConnection(null, this.via, timeout, out this.connectionKey);
735 public IConnection EstablishConnection(TimeSpan timeout)
737 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
738 IConnection localRawConnection = null;
739 IConnection localUpgradedConnection = null;
740 bool localIsConnectionFromPool = true;
742 EventTraceActivity localEventTraceActivity = this.EventTraceActivity;
743 if (TD.EstablishConnectionStartIsEnabled())
745 TD.EstablishConnectionStart(localEventTraceActivity,
746 this.via != null ? this.via.AbsoluteUri : string.Empty);
749 // first try and use a connection from our pool (and use it if we successfully receive an ACK)
750 while (localIsConnectionFromPool)
752 localRawConnection = this.TakeConnection(timeoutHelper.RemainingTime());
753 if (localRawConnection == null)
755 localIsConnectionFromPool = false;
759 bool preambleSuccess = false;
762 localUpgradedConnection = AcceptPooledConnection(localRawConnection, ref timeoutHelper);
763 preambleSuccess = true;
766 catch (CommunicationException e)
768 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
769 // CommmunicationException is ok since it was a cached connection of unknown state
771 catch (TimeoutException e)
773 if (TD.OpenTimeoutIsEnabled())
775 TD.OpenTimeout(e.Message);
777 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
778 // ditto for TimeoutException
782 if (!preambleSuccess)
784 if (TD.ConnectionPoolPreambleFailedIsEnabled())
786 TD.ConnectionPoolPreambleFailed(localEventTraceActivity);
789 if (DiagnosticUtility.ShouldTraceInformation)
791 TraceUtility.TraceEvent(
792 TraceEventType.Information,
793 TraceCode.FailedAcceptFromPool,
795 SR.TraceCodeFailedAcceptFromPool,
796 timeoutHelper.RemainingTime()));
799 // This cannot throw TimeoutException since isConnectionStillGood is false (doesn't attempt a Close).
800 this.connectionPool.ReturnConnection(connectionKey, localRawConnection, false, TimeSpan.Zero);
806 // if there isn't anything in the pool, we need to use a new connection
807 if (!localIsConnectionFromPool)
809 bool success = false;
810 TimeSpan connectTimeout = timeoutHelper.RemainingTime();
815 localRawConnection = this.connectionInitiator.Connect(this.via, connectTimeout);
817 catch (TimeoutException e)
819 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateNewConnectionTimeoutException(
823 this.connectionInitiator = null;
824 localUpgradedConnection = AcceptPooledConnection(localRawConnection, ref timeoutHelper);
831 connectionKey = null;
832 if (localRawConnection != null)
834 localRawConnection.Abort();
840 SnapshotConnection(localUpgradedConnection, localRawConnection, localIsConnectionFromPool);
842 if (TD.EstablishConnectionStopIsEnabled())
844 TD.EstablishConnectionStop(localEventTraceActivity);
847 return localUpgradedConnection;
850 void SnapshotConnection(IConnection upgradedConnection, IConnection rawConnection, bool isConnectionFromPool)
856 upgradedConnection.Abort();
858 // cleanup our pool if necessary
859 if (isConnectionFromPool)
861 this.connectionPool.ReturnConnection(this.connectionKey, rawConnection, false, TimeSpan.Zero);
864 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
865 new CommunicationObjectAbortedException(
866 SR.GetString(SR.OperationAbortedDuringConnectionEstablishment, this.via)));
870 this.upgradedConnection = upgradedConnection;
871 this.rawConnection = rawConnection;
872 this.isConnectionFromPool = isConnectionFromPool;
879 ReleaseConnection(true, TimeSpan.Zero);
882 public void Close(TimeSpan timeout)
884 ReleaseConnection(false, timeout);
887 void ReleaseConnection(bool abort, TimeSpan timeout)
889 string localConnectionKey;
890 IConnection localUpgradedConnection;
891 IConnection localRawConnection;
896 localConnectionKey = this.connectionKey;
897 localUpgradedConnection = this.upgradedConnection;
898 localRawConnection = this.rawConnection;
900 this.upgradedConnection = null;
901 this.rawConnection = null;
904 if (localUpgradedConnection == null)
911 if (this.isConnectionFromPool)
913 this.connectionPool.ReturnConnection(localConnectionKey, localRawConnection, !abort, timeout);
919 localUpgradedConnection.Abort();
923 this.connectionPool.AddConnection(localConnectionKey, localRawConnection, timeout);
927 catch (CommunicationException e)
929 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
930 localUpgradedConnection.Abort();
934 class EstablishConnectionAsyncResult : AsyncResult
936 ConnectionPoolHelper parent;
937 TimeoutHelper timeoutHelper;
938 IConnection currentConnection;
939 IConnection rawConnection;
941 bool cleanupConnection;
942 TimeSpan connectTimeout;
943 static AsyncCallback onConnect;
944 static AsyncCallback onProcessConnection = Fx.ThunkCallback(new AsyncCallback(OnProcessConnection));
945 EventTraceActivity eventTraceActivity;
947 public EstablishConnectionAsyncResult(ConnectionPoolHelper parent,
948 TimeSpan timeout, AsyncCallback callback, object state)
949 : base(callback, state)
951 this.parent = parent;
952 this.timeoutHelper = new TimeoutHelper(timeout);
954 bool success = false;
955 bool completeSelf = false;
958 completeSelf = Begin();
976 EventTraceActivity EventTraceActivity
980 if (this.eventTraceActivity == null)
982 this.eventTraceActivity = new EventTraceActivity();
984 return this.eventTraceActivity;
988 public static IConnection End(IAsyncResult result)
990 EstablishConnectionAsyncResult thisPtr = AsyncResult.End<EstablishConnectionAsyncResult>(result);
992 if (TD.EstablishConnectionStopIsEnabled())
994 TD.EstablishConnectionStop(thisPtr.EventTraceActivity);
997 return thisPtr.currentConnection;
1002 if (TD.EstablishConnectionStartIsEnabled())
1004 TD.EstablishConnectionStart(this.EventTraceActivity, this.parent.connectionKey);
1007 IConnection connection = parent.TakeConnection(timeoutHelper.RemainingTime());
1009 TrackConnection(connection);
1011 // first try and use a connection from our pool
1012 bool openingFromPool;
1013 if (OpenUsingConnectionPool(out openingFromPool))
1018 if (openingFromPool)
1024 // if there isn't anything in the pool, we need to use a new connection
1025 return OpenUsingNewConnection();
1029 bool OpenUsingConnectionPool(out bool openingFromPool)
1031 openingFromPool = true;
1032 while (this.currentConnection != null)
1034 bool snapshotCollection = false;
1037 if (ProcessConnection())
1039 snapshotCollection = true;
1046 catch (CommunicationException e)
1048 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
1049 // CommunicationException is allowed for cached channels, as the connection
1051 Cleanup(); // remove residual state
1053 catch (TimeoutException e)
1055 if (TD.OpenTimeoutIsEnabled())
1057 TD.OpenTimeout(e.Message);
1059 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
1060 // ditto for TimeoutException
1061 Cleanup(); // remove residual state
1064 if (snapshotCollection) // connection succeeded. Snapshot and return
1066 SnapshotConnection();
1070 // previous connection failed, try again
1071 IConnection connection = parent.TakeConnection(timeoutHelper.RemainingTime());
1073 TrackConnection(connection);
1076 openingFromPool = false;
1080 bool OpenUsingNewConnection()
1082 this.newConnection = true;
1083 IAsyncResult result;
1087 this.connectTimeout = timeoutHelper.RemainingTime();
1089 if (onConnect == null)
1091 onConnect = Fx.ThunkCallback(new AsyncCallback(OnConnect));
1094 result = parent.connectionInitiator.BeginConnect(
1095 parent.via, this.connectTimeout, onConnect, this);
1097 catch (TimeoutException e)
1099 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1100 parent.CreateNewConnectionTimeoutException(connectTimeout, e));
1103 if (!result.CompletedSynchronously)
1108 return HandleConnect(result);
1111 bool HandleConnect(IAsyncResult connectResult)
1115 TrackConnection(parent.connectionInitiator.EndConnect(connectResult));
1117 catch (TimeoutException e)
1119 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1120 parent.CreateNewConnectionTimeoutException(connectTimeout, e));
1123 if (ProcessConnection())
1125 // success. Snapshot and return
1126 SnapshotConnection();
1135 bool ProcessConnection()
1137 IAsyncResult result = parent.BeginAcceptPooledConnection(this.rawConnection,
1138 ref timeoutHelper, onProcessConnection, this);
1139 if (!result.CompletedSynchronously)
1144 return HandleProcessConnection(result);
1147 bool HandleProcessConnection(IAsyncResult result)
1149 this.currentConnection = parent.EndAcceptPooledConnection(result);
1150 this.cleanupConnection = false;
1154 void SnapshotConnection()
1156 parent.SnapshotConnection(this.currentConnection, this.rawConnection, !this.newConnection);
1159 void TrackConnection(IConnection connection)
1161 this.cleanupConnection = true;
1162 this.rawConnection = connection;
1163 this.currentConnection = connection;
1168 if (this.cleanupConnection)
1170 if (this.newConnection)
1172 if (this.currentConnection != null)
1174 this.currentConnection.Abort();
1175 this.currentConnection = null;
1178 else if (this.rawConnection != null)
1180 if (DiagnosticUtility.ShouldTraceInformation)
1182 TraceUtility.TraceEvent(
1183 TraceEventType.Information,
1184 TraceCode.FailedAcceptFromPool,
1186 SR.TraceCodeFailedAcceptFromPool,
1187 this.timeoutHelper.RemainingTime()));
1190 // This cannot throw TimeoutException since isConnectionStillGood is false (doesn't attempt a Close).
1191 parent.connectionPool.ReturnConnection(parent.connectionKey, this.rawConnection,
1192 false, timeoutHelper.RemainingTime());
1193 this.currentConnection = null;
1194 this.rawConnection = null;
1197 this.cleanupConnection = false;
1201 static void OnConnect(IAsyncResult result)
1203 if (result.CompletedSynchronously)
1208 EstablishConnectionAsyncResult thisPtr = (EstablishConnectionAsyncResult)result.AsyncState;
1210 Exception completionException = null;
1214 completeSelf = thisPtr.HandleConnect(result);
1216 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1224 completeSelf = true;
1225 completionException = e;
1231 thisPtr.Complete(false, completionException);
1235 static void OnProcessConnection(IAsyncResult result)
1237 if (result.CompletedSynchronously)
1242 EstablishConnectionAsyncResult thisPtr = (EstablishConnectionAsyncResult)result.AsyncState;
1244 Exception completionException = null;
1248 bool snapshotCollection = false;
1251 completeSelf = thisPtr.HandleProcessConnection(result);
1254 snapshotCollection = true;
1257 catch (CommunicationException communicationException)
1259 if (!thisPtr.newConnection) // CommunicationException is ok from our cache
1261 DiagnosticUtility.TraceHandledException(communicationException, TraceEventType.Information);
1263 completeSelf = thisPtr.Begin();
1267 completeSelf = true;
1268 completionException = communicationException;
1271 catch (TimeoutException timeoutException)
1273 if (!thisPtr.newConnection) // TimeoutException is ok from our cache
1275 if (TD.OpenTimeoutIsEnabled())
1277 TD.OpenTimeout(timeoutException.Message);
1279 DiagnosticUtility.TraceHandledException(timeoutException, TraceEventType.Information);
1281 completeSelf = thisPtr.Begin();
1285 completeSelf = true;
1286 completionException = timeoutException;
1290 if (snapshotCollection)
1292 thisPtr.SnapshotConnection();
1295 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
1303 completeSelf = true;
1304 completionException = e;
1310 thisPtr.Complete(false, completionException);