public IDisposable TryAcquire(int timeoutMillis, SqlApplicationLock.Mode mode, IDisposable contextHandle)
        {
            if (contextHandle != null)
            {
                return(this.CreateContextLock(contextHandle).TryAcquire(timeoutMillis, mode, contextHandle: null));
            }

            IDisposable    result      = null;
            var            connection  = new SqlConnection(this.connectionString);
            SqlTransaction transaction = null;

            try
            {
                connection.Open();
                // when creating a transaction, the isolation level doesn't matter, since we're using sp_getapplock
                transaction = connection.BeginTransaction();
                if (SqlApplicationLock.ExecuteAcquireCommand(transaction, this.lockName, timeoutMillis, mode))
                {
                    result = new LockScope(transaction);
                }
            }
            finally
            {
                // if we fail to acquire or throw, make sure to clean up
                if (result == null)
                {
                    transaction?.Dispose();
                    connection.Dispose();
                }
            }

            return(result);
        }
        public async Task <IDisposable> TryAcquireAsync(int timeoutMillis, SqlApplicationLock.Mode mode, CancellationToken cancellationToken, IDisposable contextHandle = null)
        {
            if (contextHandle != null)
            {
                return(await this.CreateContextLock(contextHandle).TryAcquireAsync(timeoutMillis, mode, cancellationToken, contextHandle: null).ConfigureAwait(false));
            }

            IDisposable    result      = null;
            var            connection  = new SqlConnection(this.connectionString);
            SqlTransaction transaction = null;

            try
            {
                await connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                // when creating a transaction, the isolation level doesn't matter, since we're using sp_getapplock
                transaction = connection.BeginTransaction();
                if (await SqlApplicationLock.ExecuteAcquireCommandAsync(transaction, this.lockName, timeoutMillis, mode, cancellationToken).ConfigureAwait(false))
                {
                    result = new LockScope(transaction);
                }
            }
            finally
            {
                // if we fail to acquire or throw, make sure to clean up
                if (result == null)
                {
                    transaction?.Dispose();
                    connection.Dispose();
                }
            }

            return(result);
        }
        public async Task <IDisposable> TryAcquireAsync(int timeoutMillis, SqlApplicationLock.Mode mode, CancellationToken cancellationToken, IDisposable contextHandle)
        {
            if (contextHandle != null)
            {
                return(await this.CreateContextLock(contextHandle).TryAcquireAsync(timeoutMillis, mode, cancellationToken, contextHandle: null).ConfigureAwait(false));
            }

            IDisposable result     = null;
            var         connection = new SqlConnection(this.connectionString);

            try
            {
                await connection.OpenAsync(cancellationToken).ConfigureAwait(false);

                if (await SqlApplicationLock.ExecuteAcquireCommandAsync(connection, this.lockName, timeoutMillis, mode, cancellationToken).ConfigureAwait(false))
                {
                    result = new LockScope(connection, this.lockName);
                }
            }
            finally
            {
                // if we fail to acquire or throw, make sure to clean up the connection
                if (result == null)
                {
                    connection.Dispose();
                }
            }

            return(result);
        }
        public IDisposable TryAcquire(int timeoutMillis, SqlApplicationLock.Mode mode, IDisposable contextHandle)
        {
            if (contextHandle != null)
            {
                return(this.CreateContextLock(contextHandle).TryAcquire(timeoutMillis, mode, contextHandle: null));
            }

            IDisposable result     = null;
            var         connection = new SqlConnection(this.connectionString);

            try
            {
                connection.Open();
                if (SqlApplicationLock.ExecuteAcquireCommand(connection, this.lockName, timeoutMillis, mode))
                {
                    result = new LockScope(connection, this.lockName);
                }
            }
            finally
            {
                // if we fail to acquire or throw, make sure to clean up the connection
                if (result == null)
                {
                    connection.Dispose();
                }
            }

            return(result);
        }
Ejemplo n.º 5
0
        public async Task <IDisposable> TryAcquireAsync(int timeoutMillis, SqlApplicationLock.Mode mode, CancellationToken cancellationToken, IDisposable contextHandle)
        {
            this.CheckConnection();

            return(await SqlApplicationLock.ExecuteAcquireCommandAsync(new ConnectionOrTransaction(this.transaction), this.lockName, timeoutMillis, mode, cancellationToken).ConfigureAwait(false)
                ? new LockScope(this)
                : null);
        }
Ejemplo n.º 6
0
        public IDisposable TryAcquire(int timeoutMillis, SqlApplicationLock.Mode mode, IDisposable contextHandle)
        {
            this.CheckConnection();

            return(SqlApplicationLock.ExecuteAcquireCommand(new ConnectionOrTransaction(this.transaction), this.lockName, timeoutMillis, mode)
                ? new LockScope(this)
                : null);
        }
Ejemplo n.º 7
0
        private void Release()
        {
            if (this.transaction.Connection?.IsClosedOrBroken() ?? true)
            {
                // lost the connection or transaction disposed, so the lock was already released released
                return;
            }

            SqlApplicationLock.ExecuteReleaseCommand(new ConnectionOrTransaction(this.transaction), this.lockName);
        }
 private static void ReleaseLock(SqlConnection connection, string lockName)
 {
     try
     {
         // explicit release is required due to connection pooling. For a pooled connection,
         // simply calling Dispose() will not release the lock: it just returns the connection
         // to the pool
         SqlApplicationLock.ExecuteReleaseCommand(connection, lockName);
     }
     finally
     {
         connection.Dispose();
     }
 }
Ejemplo n.º 9
0
        private static Task <bool> ProcessAcquireResultAsync(
            IDataParameterCollection parameters,
            int timeoutMillis,
            CancellationToken cancellationToken,
            out string?markerTableName,
            out string?ticketLockName)
        {
            var resultCode = (int)((IDbDataParameter)parameters[ResultCodeParameter]).Value;

            switch (resultCode)
            {
            case SuccessCode:
                ticketLockName  = (string)((IDbDataParameter)parameters[TicketLockNameParameter]).Value;
                markerTableName = (string)((IDbDataParameter)parameters[MarkerTableNameParameter]).Value;
                return(TrueTask);

            case FinishedPreambleWithoutAcquiringCode:
                ticketLockName  = null;
                markerTableName = (string)((IDbDataParameter)parameters[MarkerTableNameParameter]).Value;
                return(FalseTask);

            case FailedToAcquireWithSpaceRemainingCode:
                throw new InvalidOperationException($"An internal semaphore algorithm error ({resultCode}) occurred: failed to acquire a ticket despite indication that tickets are available");

            case BusyWaitTimeoutCode:
                ticketLockName = markerTableName = null;
                return(FalseTask);

            case AllTicketsHeldByCurrentSessionCode:
                // whenever we hit this case, it's a deadlock. If the user asked us to wait forever, we just throw. However,
                // if the user asked us to wait a specified amount of time we will wait in C#. There are other justifiable policies
                // but this one seems relatively safe and likely to do what you want. It seems reasonable that no one intends to hang
                // forever but also reasonable that someone should be able to test for lock acquisition without getting a throw
                if (timeoutMillis == Timeout.Infinite)
                {
                    throw new DeadlockException("Deadlock detected: attempt to acquire the semaphore cannot succeed because all tickets are held by the current connection");
                }

                ticketLockName = markerTableName = null;

                async Task <bool> DelayFalseAsync()
                {
                    await Task.Delay(timeoutMillis, cancellationToken).ConfigureAwait(false);

                    return(false);
                }

                return(DelayFalseAsync());

            case SqlApplicationLock.TimeoutExitCode:
                ticketLockName = markerTableName = null;
                return(FalseTask);

            default:
                if (resultCode < 0)
                {
                    SqlApplicationLock.ParseExitCode(resultCode);
                }
                throw new InvalidOperationException($"Unexpected semaphore algorithm result code {resultCode}");
            }
        }