private PooledSession(SessionPool.ISessionPool pool, SessionName sessionName, ByteString transactionId, ModeOneofCase transactionMode, DateTime evictionTime, long refreshTicks) { GaxPreconditions.CheckArgument( (transactionId == null) == (transactionMode == ModeOneofCase.None), nameof(transactionMode), "Transaction mode and ID don't match."); _pool = pool; SessionName = GaxPreconditions.CheckNotNull(sessionName, nameof(sessionName)); TransactionId = transactionId; TransactionMode = transactionMode; _session = new Session { SessionName = SessionName }; _evictionTime = evictionTime; _refreshTicks = refreshTicks; }
private Task <PooledSession> GetSessionAcquisitionTask(ModeOneofCase transactionMode, CancellationToken cancellationToken) { // Three scenarios for initial session picking: // - No transaction options: take a read-only session as-is // - Read/write transaction options: take a read/write session as-is // - Other options (a non-single-use read-only bound, or PDML): take a read-only session, but fetch a transaction with it before returning it. // If there's no session of the appropriate type, take the other kind instead - at the cost of either wasting an existing read/write // transaction, or having to acquire a read/write transaction. ConcurrentQueue <PooledSession> preferredQueue = _readOnlySessions; ConcurrentQueue <PooledSession> alternateQueue = _readWriteSessions; if (transactionMode == ModeOneofCase.ReadWrite) { preferredQueue = _readWriteSessions; alternateQueue = _readOnlySessions; } lock (_lock) { // First try the pool. if (preferredQueue.TryDequeue(out var session) || alternateQueue.TryDequeue(out session)) { // Slight inefficiency wrapping this in a task, but it makes the implementation simpler. return(Task.FromResult(session)); } // No pool entries. // If the pool is currently healthy, register a TCS in the queue that will be checked by incoming sessions. if (Healthy) { TaskCompletionSource <PooledSession> receivingTcs = new TaskCompletionSource <PooledSession>(); _pendingAcquisitions.Enqueue(receivingTcs); return(receivingTcs.WithCancellationToken(cancellationToken)); } else { // Otherwise, drop out of the lock to create a session from scratch "inline" (still asynchronously, but not via an in-flight request). } } // Effectively the "else" block above, but outside the lock return(CreatePooledSessionAsync(cancellationToken)); }
/// <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)); }
public void ClearMode() { modeCase_ = ModeOneofCase.None; mode_ = null; }
internal PooledSession WithTransaction(ByteString transactionId, ModeOneofCase transactionMode) { MarkAsDisposed(); return(new PooledSession(_pool, SessionName, transactionId, transactionMode, _evictionTime, _refreshTicks)); }
/// <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) => CreateDetachedSession(sessionName, transactionId, transactionMode, readTimestamp: null);
internal PooledSession WithTransaction(ByteString transactionId, ModeOneofCase transactionMode) => new PooledSession(_pool, SessionName, transactionId, transactionMode, _evictionTime, _refreshTicks);