static internal DbConnectionPoolIdentity GetCurrent() { DbConnectionPoolIdentity current; using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { bool isNetwork = identity.User.IsWellKnown(WellKnownSidType.NetworkSid); string sidString = identity.User.Value; // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails //IntPtr token = identity.AccessToken.DangerousGetHandle(); //bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token); bool isRestricted = false; var lastIdentity = s_lastIdentity; if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) { current = lastIdentity; } else { current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork); } } s_lastIdentity = current; return(current); }
override public bool Equals(object value) { bool result = ((this == NoIdentity) || (this == value)); if (!result && (null != value)) { DbConnectionPoolIdentity that = ((DbConnectionPoolIdentity)value); result = ((_sidString == that._sidString) && (_isRestricted == that._isRestricted) && (_isNetwork == that._isNetwork)); } return(result); }
// only created by DbConnectionPoolGroup.GetConnectionPool internal DbConnectionPool( DbConnectionFactory connectionFactory, DbConnectionPoolGroup connectionPoolGroup, DbConnectionPoolIdentity identity, DbConnectionPoolProviderInfo connectionPoolProviderInfo) { Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup"); if ((null != identity) && identity.IsRestricted) { throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken); } _state = State.Initializing; lock (s_random) { // Random.Next is not thread-safe _cleanupWait = s_random.Next(12, 24) * 10 * 1000; // 2-4 minutes in 10 sec intervals } _connectionFactory = connectionFactory; _connectionPoolGroup = connectionPoolGroup; _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; _connectionPoolProviderInfo = connectionPoolProviderInfo; _identity = identity; _waitHandles = new PoolWaitHandles(); _errorWait = ERROR_WAIT_DEFAULT; _errorTimer = null; // No error yet. _objectList = new List <DbConnectionInternal>(MaxPoolSize); _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback _state = State.Running; //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls // StartBackgroundCallbacks after pool is actually in the collection }
private void PoolCreateRequest(object state) { // called by pooler to ensure pool requests are currently being satisfied - // creation mutex has not been obtained if (State.Running == _state) { // in case WaitForPendingOpen ever failed with no subsequent OpenAsync calls, // start it back up again if (!_pendingOpens.IsEmpty && _pendingOpensWaiting == 0) { Thread waitOpenThread = new Thread(WaitForPendingOpen); waitOpenThread.IsBackground = true; waitOpenThread.Start(); } // Before creating any new objects, reclaim any released objects that were // not closed. ReclaimEmancipatedObjects(); if (!ErrorOccurred) { if (NeedToReplenish) { // Check to see if pool was created using integrated security and if so, make // sure the identity of current user matches that of user that created pool. // If it doesn't match, do not create any objects on the ThreadPool thread, // since either Open will fail or we will open a object for this pool that does // not belong in this pool. The side effect of this is that if using integrated // security min pool size cannot be guaranteed. if (UsingIntegrateSecurity && !_identity.Equals(DbConnectionPoolIdentity.GetCurrent())) { return; } int waitResult = BOGUS_HANDLE; try { try { } finally { waitResult = WaitHandle.WaitAny(_waitHandles.GetHandles(withCreate: true), CreationTimeout); } if (CREATION_HANDLE == waitResult) { DbConnectionInternal newObj; // Check ErrorOccurred again after obtaining mutex if (!ErrorOccurred) { while (NeedToReplenish) { // Don't specify any user options because there is no outer connection associated with the new connection newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null); // We do not need to check error flag here, since we know if // CreateObject returned null, we are in error case. if (null != newObj) { PutNewObject(newObj); } else { break; } } } } else if (WaitHandle.WaitTimeout == waitResult) { // do not wait forever and potential block this worker thread // instead wait for a period of time and just requeue to try again QueuePoolCreateRequest(); } } finally { if (CREATION_HANDLE == waitResult) { // reuse waitResult and ignore its value _waitHandles.CreationSemaphore.Release(1); } } } } } }
internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactory) { // When this method returns null it indicates that the connection // factory should not use pooling. // We don't support connection pooling on Win9x; // PoolGroupOptions will only be null when we're not supposed to pool // connections. DbConnectionPool pool = null; if (null != _poolGroupOptions) { DbConnectionPoolIdentity currentIdentity = DbConnectionPoolIdentity.NoIdentity; if (_poolGroupOptions.PoolByIdentity) { // There is no concept of Windows identity on non-Windows platform. Hence we // cannot support Windows authentication. if (!ADP.IsWindows) { throw new PlatformNotSupportedException(SR.GetString(SR.ADP_FeatureNotSupportedOnNonWindowsPlatform, DbConnectionStringKeywords.IntegratedSecurity)); } // if we're pooling by identity (because integrated security is // being used for these connections) then we need to go out and // search for the connectionPool that matches the current identity. currentIdentity = DbConnectionPoolIdentity.GetCurrent(); // If the current token is restricted in some way, then we must // not attempt to pool these connections. if (currentIdentity.IsRestricted) { currentIdentity = null; } } if (null != currentIdentity) { if (!_poolCollection.TryGetValue(currentIdentity, out pool)) { // find the pool DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions); // optimistically create pool, but its callbacks are delayed until after actual add DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo); lock (this) { // Did someone already add it to the list? if (!_poolCollection.TryGetValue(currentIdentity, out pool)) { if (MarkPoolGroupAsActive()) { // If we get here, we know for certain that we there isn't // a pool that matches the current identity, so we have to // add the optimistically created one newPool.Startup(); // must start pool before usage bool addResult = _poolCollection.TryAdd(currentIdentity, newPool); Debug.Assert(addResult, "No other pool with current identity should exist at this point"); pool = newPool; newPool = null; } else { // else pool entry has been disabled so don't create new pools Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled"); } } else { // else found an existing pool to use instead Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds"); } } if (null != newPool) { // don't need to call connectionFactory.QueuePoolForRelease(newPool) because // pool callbacks were delayed and no risk of connections being created newPool.Shutdown(); } } // the found pool could be in any state } } if (null == pool) { lock (this) { // keep the pool entry state active when not pooling MarkPoolGroupAsActive(); } } return(pool); }