示例#1
0
        public async ValueTask <IDistributedSynchronizationHandle?> TryAcquireAsync <TLockCookie>(
            TimeoutValue timeout,
            IDbSynchronizationStrategy <TLockCookie> strategy,
            CancellationToken cancellationToken,
            IDistributedSynchronizationHandle?contextHandle)
            where TLockCookie : class
        {
            IDistributedSynchronizationHandle?result = null;
            IAsyncDisposable?connectionResource      = null;

            try
            {
                DatabaseConnection connection;
                if (contextHandle != null)
                {
                    connection = GetContextHandleConnection <TLockCookie>(contextHandle);
                }
                else
                {
                    connectionResource = connection = this._connectionFactory();
                    if (connection.IsExernallyOwned)
                    {
                        if (!connection.CanExecuteQueries)
                        {
                            throw new InvalidOperationException("The connection and/or transaction are disposed or closed");
                        }
                    }
                    else
                    {
                        await connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                        if (this._transactionScopedIfPossible) // for an internally-owned connection, we must create the transaction
                        {
                            await connection.BeginTransactionAsync().ConfigureAwait(false);
                        }
                    }
                }

                var lockCookie = await strategy.TryAcquireAsync(connection, this._name, timeout, cancellationToken).ConfigureAwait(false);

                if (lockCookie != null)
                {
                    result = new Handle <TLockCookie>(connection, strategy, this._name, lockCookie, transactionScoped: this._transactionScopedIfPossible && connection.HasTransaction, connectionResource);
                    if (!this._keepaliveCadence.IsInfinite)
                    {
                        connection.SetKeepaliveCadence(this._keepaliveCadence);
                    }
                }
            }
            finally
            {
                // if we fail to acquire or throw, make sure to clean up the connection
                if (result == null && connectionResource != null)
                {
                    await connectionResource.DisposeAsync().ConfigureAwait(false);
                }
            }

            return(result);
        }
        public async ValueTask <Result> TryAcquireAsync <TLockCookie>(
            string name,
            TimeoutValue timeout,
            IDbSynchronizationStrategy <TLockCookie> strategy,
            TimeoutValue keepaliveCadence,
            CancellationToken cancellationToken,
            bool opportunistic)
            where TLockCookie : class
        {
            using var mutextHandle = await this._mutex.TryAcquireAsync(opportunistic?TimeSpan.Zero : Timeout.InfiniteTimeSpan, cancellationToken).ConfigureAwait(false);

            if (mutextHandle == null)
            {
                // mutex wasn't free, so just give up
                Invariant.Require(opportunistic);
                // The current lock is busy so we allow retry but on a different lock instance. We can't safely dispose
                // since we never acquired the mutex so we can't check _heldLocks
                return(new Result(MultiplexedConnectionLockRetry.Retry, canSafelyDispose: false));
            }

            try
            {
                if (this._heldLocksToKeepaliveCadences.ContainsKey(name))
                {
                    // we won't try to hold the same lock twice on one connection. At some point, we could
                    // support this case in-memory using a counter for each multiply-held lock name and being careful
                    // with modes
                    return(this.GetFailureResultNoLock(isAlreadyHeld: true, opportunistic, timeout));
                }

                if (!this._connection.CanExecuteQueries)
                {
                    await this._connection.OpenAsync(cancellationToken).ConfigureAwait(false);
                }

                var lockCookie = await strategy.TryAcquireAsync(this._connection, name, opportunistic?TimeSpan.Zero : timeout, cancellationToken).ConfigureAwait(false);

                if (lockCookie != null)
                {
                    var handle = new ManagedFinalizationDistributedLockHandle(new Handle <TLockCookie>(this, strategy, name, lockCookie));
                    this._heldLocksToKeepaliveCadences.Add(name, keepaliveCadence);
                    if (!keepaliveCadence.IsInfinite)
                    {
                        this.SetKeepaliveCadenceNoLock();
                    }
                    return(new Result(handle));
                }

                // we failed to acquire the lock, so we should retry if we were being opportunistic and artificially
                // shortened the timeout
                return(this.GetFailureResultNoLock(isAlreadyHeld: false, opportunistic, timeout));
            }
            finally
            {
                await this.CloseConnectionIfNeededNoLockAsync().ConfigureAwait(false);
            }
        }