private void AddLockToPool(string connectionString, MultiplexedConnectionLock @lock)
        {
            lock (this.@lock)
            {
                Queue <MultiplexedConnectionLock> existingPool;
                if (this.connectionStringPools.TryGetValue(connectionString, out existingPool))
                {
                    existingPool.Enqueue(@lock);
                }
                else
                {
                    var newPool = new Queue <MultiplexedConnectionLock>();
                    newPool.Enqueue(@lock);
                    this.connectionStringPools.Add(connectionString, newPool);

                    // if we're adding the first queue, start the cleanup thread
                    if (this.connectionStringPools.Count == 1)
                    {
                        // rather than replacing cleanup task, we continue on it. This ensures that we never end up in a state
                        // where two cleanup tasks are running at once. Since only cleanup can remove from the pools map, we'll
                        // never end up queueing up multiple cleanup tasks on top of one another
                        this.cleanupTask.ContinueWith(
                            (_, state) => Task.Run(() => ((MultiplexedConnectionLockPool)state).CleanupLoop()),
                            state: this,
                            continuationOptions: TaskContinuationOptions.ExecuteSynchronously
                            );
                    }
                }
            }
        }
        public IDisposable TryAcquire <TLockCookie>(
            string connectionString,
            string lockName,
            int timeoutMillis,
            ISqlSynchronizationStrategy <TLockCookie> strategy)
            where TLockCookie : class
        {
            // opportunistic phase: see if we can use a connection that is already holding a lock
            // to acquire the current lock
            var existingLock = this.GetExistingLockOrDefault(connectionString);

            if (existingLock != null)
            {
                try
                {
                    var opportunisticResult = existingLock.TryAcquire(lockName, timeoutMillis, strategy, opportunistic: true);
                    if (opportunisticResult.Handle != null)
                    {
                        return(opportunisticResult.Handle);
                    }

                    switch (opportunisticResult.Retry)
                    {
                    case MultiplexedConnectionLockRetry.NoRetry:
                        return(null);

                    case MultiplexedConnectionLockRetry.RetryOnThisLock:
                        var result = existingLock.TryAcquire(lockName, timeoutMillis, strategy, opportunistic: false);
                        return(result.Handle);

                    case MultiplexedConnectionLockRetry.Retry:
                        break;

                    default:
                        throw new InvalidOperationException("unexpected retry");
                    }
                }
                finally
                {
                    // since we took this lock from the pool, always return it to the pool
                    this.AddLockToPool(connectionString, existingLock);
                }
            }

            // normal phase: if we were not able to be opportunistic, ensure that we have a lock
            var         @lock  = new MultiplexedConnectionLock(connectionString);
            IDisposable handle = null;

            try
            {
                handle = @lock.TryAcquire(lockName, timeoutMillis, strategy, opportunistic: false).Handle;
            }
            finally
            {
                // only store the lock on success; otherwise there's no reason to keep it around
                if (handle != null)
                {
                    this.AddLockToPool(connectionString, @lock);
                }
                else
                {
                    @lock.Dispose();
                }
            }
            return(handle);
        }
Пример #3
0
        public async Task <IDisposable> TryAcquireAsync(
            string connectionString,
            string lockName,
            int timeoutMillis,
            SqlApplicationLock.Mode mode,
            CancellationToken cancellationToken)
        {
            // opportunistic phase: see if we can use a connection that is already holding a lock
            // to acquire the current lock
            var existingLock = this.GetExistingLockOrDefault(connectionString);

            if (existingLock != null)
            {
                try
                {
                    var opportunisticResult = await existingLock.TryAcquireAsync(lockName, timeoutMillis, mode, cancellationToken, opportunistic : true).ConfigureAwait(false);

                    if (opportunisticResult.Handle != null)
                    {
                        return(opportunisticResult.Handle);
                    }

                    switch (opportunisticResult.Retry)
                    {
                    case MultiplexedConnectionLockRetry.NoRetry:
                        return(null);

                    case MultiplexedConnectionLockRetry.RetryOnThisLock:
                        var result = await existingLock.TryAcquireAsync(lockName, timeoutMillis, mode, cancellationToken, opportunistic : false).ConfigureAwait(false);

                        return(result.Handle);

                    case MultiplexedConnectionLockRetry.Retry:
                        break;

                    default:
                        throw new InvalidOperationException("unexpected retry");
                    }
                }
                finally
                {
                    // since we took this lock from the pool, always return it to the pool
                    this.AddLockToPool(connectionString, existingLock);
                }
            }

            // normal phase: if we were not able to be opportunistic, ensure that we have a lock
            var         @lock  = new MultiplexedConnectionLock(connectionString);
            IDisposable handle = null;

            try
            {
                handle = (await @lock.TryAcquireAsync(lockName, timeoutMillis, mode, cancellationToken, opportunistic: false).ConfigureAwait(false)).Handle;
            }
            finally
            {
                // only store the lock on success; otherwise there's no reason to keep it around
                if (handle != null)
                {
                    this.AddLockToPool(connectionString, @lock);
                }
                else
                {
                    @lock.Dispose();
                }
            }
            return(handle);
        }
Пример #4
0
 public Handle(MultiplexedConnectionLock @lock, string lockName)
 {
     this.@lock    = @lock;
     this.lockName = lockName;
 }