private async Task <PooledSession> CreatePooledSessionAsync(CancellationToken cancellationToken)
            {
                bool success  = false;
                bool canceled = false;

                Interlocked.Increment(ref _inFlightSessionCreationCount);
                Interlocked.Increment(ref _liveOrRequestedSessionCount);
                try
                {
                    var callSettings = Client.Settings.CreateSessionSettings
                                       .WithExpiration(Expiration.FromTimeout(Options.Timeout))
                                       .WithCancellationToken(cancellationToken);
                    Session sessionProto;

                    bool acquiredSemaphore = false;
                    try
                    {
                        await Parent._sessionAcquisitionSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);

                        acquiredSemaphore = true;
                        sessionProto      = await Client.CreateSessionAsync(_createSessionRequest, callSettings).ConfigureAwait(false);

                        success = true;
                        return(PooledSession.FromSessionName(this, sessionProto.SessionName));
                    }
                    catch (OperationCanceledException)
                    {
                        canceled = true;
                        throw;
                    }
                    finally
                    {
                        if (acquiredSemaphore)
                        {
                            Parent._sessionAcquisitionSemaphore.Release();
                        }
                    }
                }
                finally
                {
                    // Atomically set _healthy and determine whether we were previously healthy, but only if either we've succeeded,
                    // or we failed for a reason other than cancellation. We don't want to go unhealthy just because a caller cancelled
                    // a cancellation token before we had chance to create the session.
                    if (success || !canceled)
                    {
                        bool wasHealthy = Interlocked.Exchange(ref _healthy, success ? 1 : 0) == 1;
                        if (wasHealthy != success)
                        {
                            Parent._logger.Info(() => $"Session pool for {_databaseName} is now {(success ? "healthy" : "unhealthy")}.");
                        }
                    }
                    // If this call failed, we can make another attempt.
                    if (!success)
                    {
                        Interlocked.Decrement(ref _liveOrRequestedSessionCount);
                    }
                    Interlocked.Decrement(ref _inFlightSessionCreationCount);
                }
            }
Пример #2
0
 /// <summary>
 /// Creates a <see cref="PooledSession"/> with a known name and transaction ID/mode, with the client associated
 /// with this pool, but is otherwise not part of this pool. This method does not query the server for the session state.
 /// When the returned <see cref="PooledSession"/> is released, it will not become part of this pool, and the transaction
 /// will not be rolled back.
 /// </summary>
 /// <remarks>
 /// This is typically used for partitioned queries, where the same session is used across multiple machines, so should
 /// not be reused by the pool.
 /// </remarks>
 /// <param name="sessionName">The name of the transaction. Must not be null.</param>
 /// <param name="transactionId">The ID of the transaction. Must not be null.</param>
 /// <param name="transactionMode">The mode of the transaction.</param>
 /// <returns>A <see cref="PooledSession"/> for the given session and transaction.</returns>
 public PooledSession CreateDetachedSession(SessionName sessionName, ByteString transactionId, ModeOneofCase transactionMode)
 {
     GaxPreconditions.CheckNotNull(sessionName, nameof(sessionName));
     GaxPreconditions.CheckNotNull(transactionId, nameof(transactionId));
     return(PooledSession.FromSessionName(_detachedSessionPool, sessionName).WithTransaction(transactionId, transactionMode));
 }