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); }
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); }
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); }
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(); } }
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}"); } }