Example #1
0
        private async Task EvictSessionAsync(SpannerClient evictionClient,
                                             Session evictionSession)
        {
            await TransactionPool.RemoveSessionAsync(evictionSession).ConfigureAwait(false);

            await evictionClient.DeleteSessionAsync(evictionSession.SessionName).ConfigureAwait(false);
        }
Example #2
0
        private bool TryPop(TransactionOptions transactionOptions, out SessionPoolEntry entry)
        {
            try
            {
                //we make a reasonable attempt at obtaining a session with the given TransactionOptions.
                //but its not guaranteed.
                lock (_sessionMruStack)
                {
                    if (_sessionMruStack.Count > 0)
                    {
                        Logger.Debug(() => "Searching for a session with matching transaction semantics.");
                        int indexToUse = -1;
                        for (int i = 0; i < _sessionMruStack.Count && i < MaximumLinearSearchDepth; i++)
                        {
                            entry = _sessionMruStack[i];
                            // GetLastUsedTransactionOptions returns null if the transaction pool doesn't know about the session.
                            // Our transactionOptions parameter is never null, but may be the default options. It's fine to treat
                            // those as equivalent; they'd never be used for a "real" transaction.
                            var lastUsedOptions = TransactionPool.GetLastUsedTransactionOptions(entry.Session) ?? s_defaultTransactionOptions;
                            if (Equals(lastUsedOptions, transactionOptions))
                            {
                                Logger.Debug(() => "found a session with matching transaction semantics.");
                                indexToUse = i;
                                if (transactionOptions?.ModeCase != TransactionOptions.ModeOneofCase.ReadWrite ||
                                    TransactionPool.IsPreWarmedTransactionReady(entry.Session))
                                {
                                    //if our prewarmed tx is ready, we can jump out immediately.
                                    break;
                                }
                            }
                        }
                        if (indexToUse == -1)
                        {
                            Logger.Debug(
                                () => "did not find a session with matching transaction semantics - popping at top.");
                            indexToUse = 0;
                        }
                        entry = _sessionMruStack[indexToUse];
                        _sessionMruStack.RemoveAt(indexToUse);

                        Interlocked.Decrement(ref s_activeSessionsPooled);
                        LogSessionsPooled();
                        return(true);
                    }
                }
                entry = default;
                return(false);
            }
            finally
            {
                OnPriorityChanged();
            }
        }
Example #3
0
        public async Task <Session> AcquireSessionAsync(TransactionOptions options, CancellationToken cancellationToken)
        {
            Logger.Debug(() => "Attempting to acquire a session from the pool.");
            SessionPoolEntry sessionEntry;

            if (!TryPop(options, out sessionEntry))
            {
                //create a new session, blocking or throwing if at the limit.
                await _sessionCreateThrottle.WaitAsync(cancellationToken).ConfigureAwait(false);

                try
                {
                    // Try to pop a session again after acquiring a throttle semaphore.
                    // we may have waited for quite a while and the pool may now have entries.
                    if (!TryPop(options, out sessionEntry))
                    {
                        Logger.Debug(
                            () => "Attempting to acquire a session from the pool failed - creating a new instance.");
                        Stopwatch sw = null;
                        if (Logger.LogPerformanceTraces)
                        {
                            sw = new Stopwatch();
                            sw.Start();
                        }

                        var result = await Key.Client.CreateSessionAsync(
                            new DatabaseName(Key.Project, Key.Instance, Key.Database), cancellationToken)
                                     .ConfigureAwait(false);

                        if (sw != null)
                        {
                            Logger.LogPerformanceCounterFn("Session.CreateTime", x => sw.ElapsedMilliseconds);
                        }
                        return(result);
                    }
                }
                finally
                {
                    _sessionCreateThrottle.Release();
                }
            }
            MarkUsed();
            //note that the evict task will only actually delete the session if it was able to remove it from the pool.
            //at this point, this is not possible because we removed it from the pool, so even if the task completes (which
            // is possible due to a race), it will see that the session isn't pooled and cancel out.
            sessionEntry.EvictTaskCancellationSource.Cancel();
            //any session leaving the pool will be in a state where its transaction warming (if started) is complete
            //and its eviction task has been canceled.
            await TransactionPool.WaitForPrewarm(sessionEntry.Session).ConfigureAwait(false);

            return(sessionEntry.Session);
        }
Example #4
0
        public void ReleaseSessionToPool(SpannerClient client, Session session)
        {
            Logger.Debug(() => "Placing session back into the pool and starting the evict timer.");
            //start evict timer.
            SessionPoolEntry entry = new SessionPoolEntry(session, new CancellationTokenSource());

            if (_options.UseTransactionWarming)
            {
                TransactionPool.StartPreWarmTransaction(client, entry.Session);
            }
            //kick off the pool eviction timer.  This gets canceled when the item is pulled from the pool.
            Task.Run(() => EvictSessionPoolEntry(entry.Session, entry.EvictTaskCancellationSource.Token),
                     entry.EvictTaskCancellationSource.Token);

            //It's very important that before we allow the new session to be in the pool
            //that the state of the session is such that it can be immediately consumed.
            Push(entry);
        }