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;
        }
Example #2
0
        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;
        }
Example #3
0
        /// <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.");
            }
        }
Example #4
0
 /// <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());
        }
Example #6
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)
            {
                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);
        }
Example #7
0
        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));
 }
Example #9
0
            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);
            }
Example #10
0
        /// <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);
        }
Example #11
0
        /// <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);
            }
        }
Example #12
0
 public SessionInfo(SpannerClient spannerClient)
 {
     SpannerClient = spannerClient;
 }
Example #13
0
 /// <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)
 {
 }