public void Return(MySqlSession session) { try { if (session.PoolGeneration == m_generation) { m_sessions.Enqueue(session); } else { session.DisposeAsync(IOBehavior.Synchronous, CancellationToken.None).ConfigureAwait(false); } } finally { m_session_semaphore.Release(); } }
public void Return(MySqlSession session) { try { lock (m_leasedSessions) m_leasedSessions.Remove(session.Id); if (SessionIsHealthy(session)) { lock (m_sessions) m_sessions.AddFirst(session); } else { session.DisposeAsync(IOBehavior.Synchronous, CancellationToken.None).ConfigureAwait(false); } } finally { m_sessionSemaphore.Release(); } }
private async Task CleanPoolAsync(IOBehavior ioBehavior, Func <MySqlSession, bool> shouldCleanFn, bool respectMinPoolSize, CancellationToken cancellationToken) { // synchronize access to this method as only one clean routine should be run at a time if (ioBehavior == IOBehavior.Asynchronous) { await m_cleanSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); } else { m_cleanSemaphore.Wait(cancellationToken); } try { var waitTimeout = TimeSpan.FromMilliseconds(10); while (true) { // if respectMinPoolSize is true, return if (leased sessions + waiting sessions <= minPoolSize) if (respectMinPoolSize) { lock (m_sessions) if (m_connectionSettings.MaximumPoolSize - m_sessionSemaphore.CurrentCount + m_sessions.Count <= m_connectionSettings.MinimumPoolSize) { return; } } // try to get an open slot; if this fails, connection pool is full and sessions will be disposed when returned to pool if (ioBehavior == IOBehavior.Asynchronous) { if (!await m_sessionSemaphore.WaitAsync(waitTimeout, cancellationToken).ConfigureAwait(false)) { return; } } else { if (!m_sessionSemaphore.Wait(waitTimeout, cancellationToken)) { return; } } try { // check for a waiting session MySqlSession session = null; lock (m_sessions) { if (m_sessions.Count > 0) { session = m_sessions.Last.Value; m_sessions.RemoveLast(); } } if (session == null) { return; } if (shouldCleanFn(session)) { // session should be cleaned; dispose it and keep iterating await session.DisposeAsync(ioBehavior, cancellationToken).ConfigureAwait(false); } else { // session should not be cleaned; put it back in the queue and stop iterating lock (m_sessions) m_sessions.AddLast(session); return; } } finally { m_sessionSemaphore.Release(); } } } finally { m_cleanSemaphore.Release(); } }
public async Task <MySqlSession> GetSessionAsync(MySqlConnection connection, IOBehavior ioBehavior, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); // if all sessions are used, see if any have been leaked and can be recovered // check at most once per second (although this isn't enforced via a mutex so multiple threads might block // on the lock in RecoverLeakedSessions in high-concurrency situations if (m_sessionSemaphore.CurrentCount == 0 && unchecked (((uint)Environment.TickCount) - m_lastRecoveryTime) >= 1000u) { RecoverLeakedSessions(); } // wait for an open slot (until the cancellationToken is cancelled, which is typically due to timeout) if (ioBehavior == IOBehavior.Asynchronous) { await m_sessionSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); } else { m_sessionSemaphore.Wait(cancellationToken); } try { // check for a waiting session MySqlSession session = null; lock (m_sessions) { if (m_sessions.Count > 0) { session = m_sessions.First.Value; m_sessions.RemoveFirst(); } } if (session != null) { bool reuseSession; if (session.PoolGeneration != m_generation) { reuseSession = false; } else { if (m_connectionSettings.ConnectionReset) { reuseSession = await session.TryResetConnectionAsync(m_connectionSettings, ioBehavior, cancellationToken).ConfigureAwait(false); } else { reuseSession = await session.TryPingAsync(ioBehavior, cancellationToken).ConfigureAwait(false); } } if (!reuseSession) { // session is either old or cannot communicate with the server await session.DisposeAsync(ioBehavior, cancellationToken).ConfigureAwait(false); } else { // pooled session is ready to be used; return it session.OwningConnection = new WeakReference <MySqlConnection>(connection); lock (m_leasedSessions) m_leasedSessions.Add(session.Id, session); return(session); } } // create a new session session = new MySqlSession(this, m_generation, Interlocked.Increment(ref m_lastId)); await session.ConnectAsync(m_connectionSettings, ioBehavior, cancellationToken).ConfigureAwait(false); session.OwningConnection = new WeakReference <MySqlConnection>(connection); lock (m_leasedSessions) m_leasedSessions.Add(session.Id, session); return(session); } catch { m_sessionSemaphore.Release(); throw; } }