internal ReliableStreamReader( SpannerClient spannerClient, ExecuteSqlRequest request, Session session, int timeoutSeconds) { _spannerClient = spannerClient; _request = request; _session = session; _timeoutSeconds = timeoutSeconds; _clock = SpannerSettings.GetDefault().Clock ?? SystemClock.Instance; _scheduler = SpannerSettings.GetDefault().Scheduler ?? SystemScheduler.Instance; _request.SessionAsSessionName = _session.SessionName; }
internal ReliableStreamReader( SpannerClient spannerClient, ExecuteSqlRequest request, Session session, int timeoutSeconds) { _spannerClient = GaxPreconditions.CheckNotNull(spannerClient, nameof(SpannerClient)); _request = GaxPreconditions.CheckNotNull(request, nameof(request)); _session = GaxPreconditions.CheckNotNull(session, nameof(session)); _timeoutSeconds = timeoutSeconds; _clock = SpannerSettings.GetDefault().Clock ?? SystemClock.Instance; _scheduler = SpannerSettings.GetDefault().Scheduler ?? SystemScheduler.Instance; _request.SessionAsSessionName = _session.SessionName; }
/// <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="client">The client using the session. Must not be null.</param> /// <param name="session">The session to release. Must not be null.</param> public void ReleaseToPool(SpannerClient client, Session session) { GaxPreconditions.CheckNotNull(client, nameof(client)); GaxPreconditions.CheckNotNull(session, nameof(session)); SessionPoolKey poolKey; if (_sessionsInUse.TryRemove(session, out poolKey)) { LogSessionsInUse(); try { if (IsSessionExpired(session)) { bool unused; s_blackListedSessions.TryRemove(session.Name, out unused); return; } var targetPool = _poolByClientAndDatabase.GetOrAdd( poolKey, key => new SessionPoolImpl(key, Options)); //Figure out if we want to pool this released session. targetPool.ReleaseSessionToPool(client, session); _priorityList.Add(targetPool); if (CurrentPooledSessions > Options.MaximumPooledSessions) { var evictionPool = _priorityList.GetTop(); var evictionClient = evictionPool?.Key.Client; var evictionSession = evictionPool?.AcquireEvictionCandidate(); if (evictionSession != null) { Task.Run(() => EvictSessionAsync(evictionClient, evictionSession)); } } } finally { //signal to any blocked requestor that they *may* be able to allocate a session. SignalAnyWaitingRequests(); } } else { Logger.Error(() => "An attempt was made to release a session to the pool, but the session was not originally allocated from the pool."); } }
/// <summary> /// Constructor with complete control that does not perform any validation. /// </summary> internal ResultStream( SpannerClient client, ReadOrQueryRequest request, Session session, CallSettings callSettings, int maxBufferSize, RetrySettings retrySettings) { _buffer = new LinkedList <PartialResultSet>(); _client = GaxPreconditions.CheckNotNull(client, nameof(client)); _request = GaxPreconditions.CheckNotNull(request, nameof(request)); _session = GaxPreconditions.CheckNotNull(session, nameof(session)); _callSettings = callSettings; _maxBufferSize = GaxPreconditions.CheckArgumentRange(maxBufferSize, nameof(maxBufferSize), 1, 10_000); _retrySettings = GaxPreconditions.CheckNotNull(retrySettings, nameof(retrySettings)); }
internal int GetPoolSize( SpannerClient spannerClient, string project, string spannerInstance, string spannerDatabase) { 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()); }
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) { client.StartPreWarmTransaction(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); }
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> /// Constructor with complete control, for testing purposes. /// </summary> internal SqlResultStream( SpannerClient client, ExecuteSqlRequest request, Session session, CallSettings callSettings, int maxBufferSize, BackoffSettings backoffSettings, IJitter backoffJitter) { _buffer = new LinkedList <PartialResultSet>(); _client = GaxPreconditions.CheckNotNull(client, nameof(client)); _request = GaxPreconditions.CheckNotNull(request, nameof(request)); _session = GaxPreconditions.CheckNotNull(session, nameof(session)); _callSettings = callSettings; _maxBufferSize = GaxPreconditions.CheckArgumentRange(maxBufferSize, nameof(maxBufferSize), 1, 10_000); _backoffSettings = GaxPreconditions.CheckNotNull(backoffSettings, nameof(backoffSettings)); _backoffJitter = GaxPreconditions.CheckNotNull(backoffJitter, nameof(backoffJitter)); }
private async Task CreateTransactionImplAsync(Session session, TransactionOptions options, Task oldPrewarmTask) { //we need to await for previous task completion anyway -- otherwise there is a bad race condition. //this is a little redundant, but just to be sure. if (oldPrewarmTask != null) { await oldPrewarmTask.ConfigureAwait(false); } var sw = Stopwatch.StartNew(); ActiveTransaction = await SpannerClient.BeginTransactionAsync(new BeginTransactionRequest { SessionAsSessionName = session.SessionName, Options = options }).WithSessionChecking(() => session).ConfigureAwait(false); Logger.LogPerformanceCounterFn("Transaction.Begin.Duration", x => sw.ElapsedMilliseconds); TransactionOptions = options; s_activeTransactionTable.AddOrUpdate(ActiveTransaction.Id, session, (id, s) => session); }
/// <summary> /// Creates a transaction with the given transaction options. /// Depending on the state of the session, this may or may not result in a request /// to Spanner over the network. /// </summary> /// <param name="client">The client to use for the transaction. Must not be null.</param> /// <param name="session">The session to use for the transaction. Must not be null.</param> /// <param name="options">The options for the transaction.</param> /// <returns>A task which, when completed, will result in a suitable transaction for the given parameters.</returns> public static async Task <Transaction> BeginPooledTransactionAsync(this SpannerClient client, Session session, TransactionOptions options) { GaxPreconditions.CheckNotNull(client, nameof(client)); GaxPreconditions.CheckNotNull(session, nameof(session)); var info = s_sessionInfoTable.GetOrAdd(session, s => new SessionInfo(client)); //we need to await for previous task completion anyway -- otherwise there is a bad race condition. await info.WaitForPreWarmAsync().ConfigureAwait(false); //now we see if we can return the prewarmed transaction. // a lot has to be correct for us to return the precreated transaction. // we have to have a valid transaction object. // it needs to exist in the activetransactiontable to indicate that it hasn't been closed // the options on it must equal the passed in options. if (info.HasActiveTransaction && s_activeTransactionTable.ContainsKey(info.ActiveTransaction.Id)) { if (info.TransactionOptions != null && info.TransactionOptions.Equals(options)) { Logger.LogPerformanceCounterFn("Transaction.CacheHit", (x) => x + 1); return(info.ActiveTransaction); } //cache hit, but no match on options Session ignored; s_activeTransactionTable.TryRemove(info.ActiveTransaction.Id, out ignored); } //ok, our cache hit didnt work for whatever reason. Let's create a transaction with the given options and return it. Logger.LogPerformanceCounterFn("Transaction.CacheMiss", (x) => x + 1); await info.CreateTransactionAsync(session, options).ConfigureAwait(false); if (info.ActiveTransaction != null) { s_activeTransactionTable.AddOrUpdate(info.ActiveTransaction.Id, session, (id, s) => session); } return(info.ActiveTransaction); }
/// <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); } }
public SessionInfo(SpannerClient spannerClient) { SpannerClient = spannerClient; }
/// <summary> /// Constructor for normal usage, with default buffer size, backoff settings and jitter. /// </summary> internal ResultStream(SpannerClient client, ReadOrQueryRequest request, Session session, CallSettings callSettings) : this(client, request, session, callSettings, DefaultMaxBufferSize, s_defaultRetrySettings) { }
/// <summary> /// Constructor for normal usage, with default buffer size, backoff settings and jitter. /// </summary> internal SqlResultStream(SpannerClient client, ExecuteSqlRequest request, Session session, CallSettings callSettings) : this(client, request, session, callSettings, DefaultMaxBufferSize, s_defaultBackoffSettings, RetrySettings.RandomJitter) { }