private async Task EvictSessionAsync(SpannerClient evictionClient, Session evictionSession) { await TransactionPool.RemoveSessionAsync(evictionSession).ConfigureAwait(false); await evictionClient.DeleteSessionAsync(evictionSession.SessionName).ConfigureAwait(false); }
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(); } }
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); }
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); }