Example #1
0
        private static IDbCommand CreateAcquireCommand(
            ConnectionOrTransaction connectionOrTransaction,
            string lockName,
            int timeoutMillis,
            Mode mode,
            out IDbDataParameter returnValue)
        {
            var command = connectionOrTransaction.Connection !.CreateCommand();

            command.Transaction    = connectionOrTransaction.Transaction;
            command.CommandText    = "dbo.sp_getapplock";
            command.CommandType    = CommandType.StoredProcedure;
            command.CommandTimeout = timeoutMillis >= 0
                                     // command timeout is in seconds. We always wait at least the lock timeout plus a buffer
                  ? (timeoutMillis / 1000) + 30
                                     // otherwise timeout is infinite so we use the infinite timeout of 0
                                     // (see https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout%28v=vs.110%29.aspx)
                  : 0;

            command.Parameters.Add(command.CreateParameter("Resource", lockName));
            command.Parameters.Add(command.CreateParameter("LockMode", GetModeString(mode)));
            command.Parameters.Add(command.CreateParameter("LockOwner", command.Transaction != null ? "Transaction" : "Session"));
            command.Parameters.Add(command.CreateParameter("LockTimeout", timeoutMillis));

            returnValue           = command.CreateParameter();
            returnValue.Direction = ParameterDirection.ReturnValue;
            command.Parameters.Add(returnValue);

            return(command);
        }
 public void Release(ConnectionOrTransaction connectionOrTransaction, string resourceName, Cookie lockCookie)
 {
     using var command   = CreateTextCommand(connectionOrTransaction, operationTimeoutMillis: Timeout.Infinite);
     command.CommandText = ReleaseQuery.Value;
     this.AddCommonParameters(command, resourceName, markerTableName: lockCookie.MarkerTable, ticketLockName: lockCookie.Ticket);
     command.ExecuteNonQuery();
 }
Example #3
0
        private static async Task <bool> ExecuteAcquireCommandAsync(ConnectionOrTransaction connectionOrTransaction, string lockName, int timeoutMillis, Mode mode, CancellationToken cancellationToken)
        {
            using var command = CreateAcquireCommand(connectionOrTransaction, lockName, timeoutMillis, mode, out var returnValue);
            await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);

            return(ParseExitCode((int)returnValue.Value));
        }
 private static void ExecuteReleaseCommand(ConnectionOrTransaction connectionOrTransaction, string lockName)
 {
     using (var command = CreateReleaseCommand(connectionOrTransaction, lockName, out var returnValue))
     {
         command.ExecuteNonQuery();
         ParseExitCode((int)returnValue.Value);
     }
 }
 private static bool ExecuteAcquireCommand(ConnectionOrTransaction connectionOrTransaction, string lockName, int timeoutMillis, Mode mode)
 {
     using (var command = CreateAcquireCommand(connectionOrTransaction, lockName, timeoutMillis, mode, out var returnValue))
     {
         command.ExecuteNonQuery();
         return(ParseExitCode((int)returnValue.Value));
     }
 }
        private static IDbCommand CreateTextCommand(ConnectionOrTransaction connectionOrTransaction, int operationTimeoutMillis)
        {
            var command = connectionOrTransaction.Connection !.CreateCommand();

            command.Transaction    = connectionOrTransaction.Transaction;
            command.CommandType    = CommandType.Text;
            command.CommandTimeout = SqlHelpers.GetCommandTimeout(operationTimeoutMillis);
            return(command);
        }
        public Cookie TryAcquire(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis)
        {
            var tryAcquireTask = this.TryAcquireAsync(connectionOrTransaction, resourceName, timeoutMillis, CancellationToken.None, isSyncOverAsync: true);

            try { return(tryAcquireTask.Result); }
            catch (AggregateException ex)
            {
                ExceptionDispatchInfo.Capture(ex.GetBaseException()).Throw();
                throw; // never hit
            }
        }
Example #8
0
        public static async Task ExecuteReleaseCommandAsync(ConnectionOrTransaction connectionOrTransaction, string lockName)
        {
            IDbDataParameter returnValue;

            using (var command = CreateReleaseCommand(connectionOrTransaction, lockName, out returnValue))
            {
                await command.ExecuteNonQueryAsync(CancellationToken.None);

                ParseExitCode((int)returnValue.Value);
            }
        }
Example #9
0
        private static IDbCommand CreateReleaseCommand(ConnectionOrTransaction connectionOrTransaction, string lockName, out IDbDataParameter returnValue)
        {
            var command = connectionOrTransaction.Connection !.CreateCommand();

            command.Transaction = connectionOrTransaction.Transaction;
            command.CommandText = "dbo.sp_releaseapplock";
            command.CommandType = CommandType.StoredProcedure;
            command.Parameters.Add(command.CreateParameter("Resource", lockName));
            command.Parameters.Add(command.CreateParameter("LockOwner", command.Transaction != null ? "Transaction" : "Session"));

            returnValue           = command.CreateParameter();
            returnValue.Direction = ParameterDirection.ReturnValue;
            command.Parameters.Add(returnValue);

            return(command);
        }
Example #10
0
 public ExternalConnectionOrTransactionSqlDistributedLock(string lockName, ConnectionOrTransaction connectionOrTransaction)
 {
     this.lockName = lockName;
     this.connectionOrTransaction = connectionOrTransaction;
 }
Example #11
0
 void ISqlSynchronizationStrategy <object> .Release(ConnectionOrTransaction connectionOrTransaction, string resourceName, object lockCookie)
 {
     ExecuteReleaseCommand(connectionOrTransaction, resourceName);
 }
Example #12
0
 async Task <object?> ISqlSynchronizationStrategy <object> .TryAcquireAsync(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis, CancellationToken cancellationToken)
 {
     return(await ExecuteAcquireCommandAsync(connectionOrTransaction, resourceName, timeoutMillis, this.mode, cancellationToken).ConfigureAwait(false) ? Cookie : null);
 }
Example #13
0
 object?ISqlSynchronizationStrategy <object> .TryAcquire(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis)
 {
     return(ExecuteAcquireCommand(connectionOrTransaction, resourceName, timeoutMillis, this.mode) ? Cookie : null);
 }
Example #14
0
        private async Task <Cookie?> TryAcquireAsync(
            ConnectionOrTransaction connectionOrTransaction,
            string semaphoreName,
            int timeoutMillis,
            CancellationToken cancellationToken,
            bool isSyncOverAsync)
        {
            cancellationToken.ThrowIfCancellationRequested();
            string?markerTableName;

            // when we aren't supporting cancellation, we can use a simplified one-step algorithm. We treat a timeout of
            // zero in the same way: since there is no blocking, we don't need to bother with explicit cancellation support
            if (!cancellationToken.CanBeCanceled || timeoutMillis == 0)
            {
                using var command   = CreateTextCommand(connectionOrTransaction, operationTimeoutMillis: timeoutMillis);
                command.CommandText = AcquireNonCancelableQuery.Value;
                this.AddCommonParameters(command, semaphoreName, timeoutMillis: timeoutMillis);
                await ExecuteNonQueryAsync(command, CancellationToken.None, isSyncOverAsync).ConfigureAwait(false);

                return(await ProcessAcquireResultAsync(command.Parameters, timeoutMillis, cancellationToken, out markerTableName, out var ticketLockName).ConfigureAwait(false)
                    ? new Cookie(ticket: ticketLockName !, markerTable: markerTableName !)
                    : null);
            }

            // cancelable case

            using (var command = CreateTextCommand(connectionOrTransaction, operationTimeoutMillis: timeoutMillis))
            {
                command.CommandText = AcquireCancelablePreambleQuery.Value;
                this.AddCommonParameters(command, semaphoreName);
                // preamble is non-cancelable
                await ExecuteNonQueryAsync(command, CancellationToken.None, isSyncOverAsync).ConfigureAwait(false);

                if (await ProcessAcquireResultAsync(command.Parameters, timeoutMillis, cancellationToken, out markerTableName, out var ticketLockName).ConfigureAwait(false))
                {
                    return(new Cookie(ticket: ticketLockName !, markerTable: markerTableName !));
                }
            }

            using (var command = CreateTextCommand(connectionOrTransaction, operationTimeoutMillis: timeoutMillis))
            {
                command.CommandText = AcquireCancelableQuery.Value;
                this.AddCommonParameters(command, semaphoreName, timeoutMillis: timeoutMillis, markerTableName: markerTableName);
                try
                {
                    await ExecuteNonQueryAsync(command, cancellationToken, isSyncOverAsync).ConfigureAwait(false);
                }
                catch when(cancellationToken.IsCancellationRequested)
                {
                    // if we canceled the query, we need to perform cleanup to make sure we don't leave marker tables or held locks

                    using (var cleanupCommand = CreateTextCommand(connectionOrTransaction, operationTimeoutMillis: 0))
                    {
                        cleanupCommand.CommandText = CancellationCleanupQuery.Value;
                        this.AddCommonParameters(cleanupCommand, semaphoreName, markerTableName: markerTableName);
                        await ExecuteNonQueryAsync(cleanupCommand, CancellationToken.None, isSyncOverAsync).ConfigureAwait(false);
                    }

                    throw;
                }

                return(await ProcessAcquireResultAsync(command.Parameters, timeoutMillis, cancellationToken, out markerTableName, out var ticketLockName).ConfigureAwait(false)
                    ? new Cookie(ticket: ticketLockName !, markerTable: markerTableName !)
                    : null);
            }
        }
Example #15
0
 public Task <Cookie?> TryAcquireAsync(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis, CancellationToken cancellationToken)
 {
     return(this.TryAcquireAsync(connectionOrTransaction, resourceName, timeoutMillis, cancellationToken, isSyncOverAsync: false));
 }
Example #16
0
 public Cookie?TryAcquire(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis)
 {
     return(this.TryAcquireAsync(connectionOrTransaction, resourceName, timeoutMillis, CancellationToken.None, isSyncOverAsync: true)
            .GetAwaiter()
            .GetResult());
 }