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(); }
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 } }
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); } }
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); }
public ExternalConnectionOrTransactionSqlDistributedLock(string lockName, ConnectionOrTransaction connectionOrTransaction) { this.lockName = lockName; this.connectionOrTransaction = connectionOrTransaction; }
void ISqlSynchronizationStrategy <object> .Release(ConnectionOrTransaction connectionOrTransaction, string resourceName, object lockCookie) { ExecuteReleaseCommand(connectionOrTransaction, resourceName); }
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); }
object?ISqlSynchronizationStrategy <object> .TryAcquire(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis) { return(ExecuteAcquireCommand(connectionOrTransaction, resourceName, timeoutMillis, this.mode) ? Cookie : null); }
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); } }
public Task <Cookie?> TryAcquireAsync(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis, CancellationToken cancellationToken) { return(this.TryAcquireAsync(connectionOrTransaction, resourceName, timeoutMillis, cancellationToken, isSyncOverAsync: false)); }
public Cookie?TryAcquire(ConnectionOrTransaction connectionOrTransaction, string resourceName, int timeoutMillis) { return(this.TryAcquireAsync(connectionOrTransaction, resourceName, timeoutMillis, CancellationToken.None, isSyncOverAsync: true) .GetAwaiter() .GetResult()); }