public IDatabaseConnectionMonitoringHandle GetMonitoringHandle() { lock (this.Lock) { // Since this will be called via non-thread-safe paths, we do a true // dispose check. This error should never reach callers unless they are // using non-thread-safe stuff concurrently if (this._state == State.Disposed) { throw new ObjectDisposedException(this.GetType().ToString()); } // If the connection is already closed, we'll never see a state change // event for the close so just return an already canceled handle if (this._state == State.AutoStopped || this._state == State.Stopped) { return(new AlreadyCanceledHandle()); } // If the connection does not support state monitoring, we can't produce // a monitoring handle if (this._stateChangedHandler == null) { return(NullHandle.Instance); } var hadRegisteredMonitoringHandles = this.HasRegisteredMonitoringHandlesNoLock; var connectionLostTokenSource = new CancellationTokenSource(); var handle = new MonitoringHandle(this, connectionLostTokenSource.Token); (this._monitoringHandleRegistrations ??= new Dictionary <MonitoringHandle, CancellationTokenSource>()) .Add(handle, connectionLostTokenSource); if (!this.StartMonitorWorkerIfNeededNoLock() && !hadRegisteredMonitoringHandles && this._state == State.Active) { // If we get here, it means we already had an active worker which was not monitoring (doing // keepalive). That worker is likely asleep, so we fire state changed to wake it up and have it // switch over to monitoring this.FireStateChangedNoLock(); } return(handle); } }
private void ReleaseMonitoringHandle(MonitoringHandle handle) { lock (this.Lock) { if (this._monitoringHandleRegistrations !.TryGetValue(handle, out var cancellationTokenSource)) { this._monitoringHandleRegistrations.Remove(handle); cancellationTokenSource.Dispose(); // If we've removed the last reason to be monitoring, fire state changed to stop the monitoring process. // Without this, the next query that attempts to acquire the connection lock will not think we are monitoring // and therefore will not fire state change. Then, it will get stuck waiting for the monitoring query to complete if (this._monitoringHandleRegistrations.Count == 0 && this._state == State.Active) { this.FireStateChangedNoLock(); } } } }