/// <summary> /// Allocates a session from the pool if possible, or creates a new Spanner Session. /// </summary> /// <param name="spannerClient">The client to associate with the session. Must not be null.</param> /// <param name="project">The project of the session. Must not be null.</param> /// <param name="spannerInstance">The instance of the session. Must not be null.</param> /// <param name="spannerDatabase">The database of the session. Must not be null.</param> /// <param name="options">The transaction options for the session. Must not be null.</param> /// <param name="cancellationToken">A cancellation token for the asynchronous operation.</param> /// <returns>A task which, when completed, will return the session.</returns> public async Task <Session> CreateSessionFromPoolAsync( SpannerClient spannerClient, string project, string spannerInstance, string spannerDatabase, TransactionOptions options, CancellationToken cancellationToken) { GaxPreconditions.CheckNotNull(spannerClient, nameof(spannerClient)); GaxPreconditions.CheckNotNull(project, nameof(project)); GaxPreconditions.CheckNotNull(spannerInstance, nameof(spannerInstance)); GaxPreconditions.CheckNotNull(spannerDatabase, nameof(spannerDatabase)); GaxPreconditions.CheckNotNull(options, nameof(options)); await StartSessionCreatingAsync(cancellationToken).ConfigureAwait(false); Session sessionResult = null; SessionPoolKey sessionPoolKey = default; try { sessionPoolKey = new SessionPoolKey(spannerClient, project, spannerInstance, spannerDatabase); SessionPoolImpl targetPool = _poolByClientAndDatabase.GetOrAdd(sessionPoolKey, key => new SessionPoolImpl(key, Options)); sessionResult = await targetPool.AcquireSessionAsync(options, cancellationToken).ConfigureAwait(false); // Refresh the MRU list which tells us what sessions need to be trimmed from the pool when we want // to add another poolEntry. return(sessionResult); } finally { EndSessionCreating(sessionResult, sessionPoolKey); } }
private static void ReSortMru(SessionPoolImpl targetPool) { lock (s_priorityListSync) { if (s_priorityList.Count > 1) { s_priorityList.Remove(targetPool); s_priorityList.Add(targetPool, targetPool); } } }
// Only present for testing. internal int GetPoolSize(SpannerClient spannerClient, string project, string spannerInstance, string spannerDatabase) { GaxPreconditions.CheckNotNull(spannerClient, nameof(spannerClient)); GaxPreconditions.CheckNotNull(project, nameof(project)); GaxPreconditions.CheckNotNull(spannerInstance, nameof(spannerInstance)); GaxPreconditions.CheckNotNull(spannerDatabase, nameof(spannerDatabase)); var sessionPoolKey = new SessionPoolKey(spannerClient, project, spannerInstance, spannerDatabase); SessionPoolImpl targetPool = _poolByClientAndDatabase.GetOrAdd(sessionPoolKey, key => new SessionPoolImpl(key, Options)); return(targetPool.GetPoolSize()); }
/// <summary> /// Releases a session back into the pool, possibly causing another entry to be evicted if the maximum pool size has been /// reached. /// </summary> /// <param name="session"></param> /// <param name="client"></param> /// <returns></returns> public static void ReleaseToPool(this SpannerClient client, Session session) { session.ThrowIfNull(nameof(session)); SessionPoolKey poolKey; if (s_sessionsInUse.TryRemove(session, out poolKey)) { LogSessionsInUse(); SignalAnyWaitingRequests(); if (IsSessionExpired(session)) { bool unused; s_blackListedSessions.TryRemove(session.Name, out unused); return; } SessionPoolImpl targetPool = s_poolByClientAndDatabase.GetOrAdd(poolKey, key => new SessionPoolImpl(key)); SpannerClient evictionClient = poolKey.Client; Session evictionSession = null; //Figure out if we want to pool this released session. lock (s_priorityListSync) { targetPool.ReleaseSessionToPool(client, session); if (CurrentPooledSessions > MaximumPooledSessions) { var evictionPool = s_priorityList.First().Value; evictionClient = evictionPool.Key.Client; evictionSession = evictionPool.AcquireEvictionCandidate(); ReSortMru(evictionPool); } ReSortMru(targetPool); } if (evictionSession != null) { Task.Run(() => EvictSessionAsync(evictionClient, evictionSession)); } } else { Logger.Error( () => "An attempt was made to release a session to the pool," + " but the session was not originally allocated from the pool."); } }
internal int GetPoolSize( SpannerClient spannerClient, string project, string spannerInstance, string spannerDatabase) { project.ThrowIfNullOrEmpty(nameof(project)); spannerInstance.ThrowIfNullOrEmpty(nameof(spannerInstance)); spannerDatabase.ThrowIfNullOrEmpty(nameof(spannerDatabase)); var sessionPoolKey = new SessionPoolKey(spannerClient, project, spannerInstance, spannerDatabase); SessionPoolImpl targetPool = _poolByClientAndDatabase.GetOrAdd(sessionPoolKey, key => new SessionPoolImpl(key, Options)); return(targetPool.GetPoolSize()); }
/// <summary> /// Allocates a session from the pool if possible, or creates a new Spanner Session. /// </summary> /// <param name="spannerClient"></param> /// <param name="project"></param> /// <param name="spannerInstance"></param> /// <param name="spannerDatabase"></param> /// <param name="options"></param> /// <param name="cancellationToken"></param> /// <returns></returns> public static async Task <Session> CreateSessionFromPoolAsync( this SpannerClient spannerClient, string project, string spannerInstance, string spannerDatabase, TransactionOptions options, CancellationToken cancellationToken) { project.ThrowIfNullOrEmpty(nameof(project)); spannerInstance.ThrowIfNullOrEmpty(nameof(spannerInstance)); spannerDatabase.ThrowIfNullOrEmpty(nameof(spannerDatabase)); await StartSessionCreatingAsync(cancellationToken).ConfigureAwait(false); Session sessionResult = null; SessionPoolKey sessionPoolKey = default(SessionPoolKey); try { sessionPoolKey = new SessionPoolKey(spannerClient, project, spannerInstance, spannerDatabase); SessionPoolImpl targetPool = s_poolByClientAndDatabase.GetOrAdd(sessionPoolKey, key => new SessionPoolImpl(key)); sessionResult = await targetPool.AcquireSessionAsync(options, cancellationToken).ConfigureAwait(false); //refresh the mru list which tells us what sessions need to be trimmed from the pool when we want // to add another poolEntry. ReSortMru(targetPool); return(sessionResult); } finally { EndSessionCreating(sessionResult, sessionPoolKey); } }