示例#1
0
        /// <inheritdoc />
        public override string Lock(object key)
        {
            if (key == null)
            {
                throw new ArgumentNullException(nameof(key));
            }

            var lockKey = GetLockKey(key);

            Log.Debug("Locking key: '{0}'.", lockKey);
            var lockValue = _lockValueProvider.GetValue();

            using (var cacheLockValue = new CacheLockValue(lockValue))
            {
                object Context() => new KeyValuePair <string, CacheLockValue>(lockKey, cacheLockValue);

                return(_retryPolicy
                       .Execute(() =>
                {
                    if (!LockLocal(lockKey, cacheLockValue))
                    {
                        Log.Debug("Failed to acquire lock for key '{0}' in the local cache, retrying...", lockKey);
                        return null;                                 // Retry
                    }

                    cacheLockValue.Setup();
                    var subscriberCount = _subscriber.Publish(_synchronizationChannel, Serializer.Serialize(new CacheSynchronizationMessage
                    {
                        OperationType = OperationType.Lock,
                        Timestamp = DateTime.UtcNow.Ticks,
                        ClientId = _clientId,
                        Data = new LockData
                        {
                            LockKey = lockKey,
                            LockValue = lockValue
                        }
                    })) - 1;

                    if (subscriberCount == 0)
                    {
                        Log.Debug("Acquired lock for key '{0}', no other caches were involved.", lockKey);
                        // We are the only one subscribed
                        return cacheLockValue.Value;
                    }

                    Log.Debug("Waiting lock result from '{0}' other local caches.", subscriberCount);
                    IncreaseLock(cacheLockValue, subscriberCount);
                    if (!cacheLockValue.Semaphore.Wait(_lockAcquireTimeout) || cacheLockValue.Failed)
                    {
                        Log.Debug("Failed to acquire lock for key '{0}' from '{1}' other local caches, retrying...", lockKey, subscriberCount);
                        return null;
                    }

                    Log.Debug("Acquired lock for key '{0}', '{1}' other caches were involved.", lockKey, subscriberCount);
                    return cacheLockValue.Value;
                }, Context));
            }
        }
示例#2
0
        private bool LockManyLocal(string[] lockKeys, CacheLockValue lockValue)
        {
            foreach (var lockKey in lockKeys)
            {
                if (!LockLocal(lockKey, lockValue))
                {
                    return(false);
                }
            }

            return(true);
        }
示例#3
0
        private bool LockLocal(string lockKey, CacheLockValue lockValue)
        {
            lock (_lockLock)
            {
                var value = (CacheLockValue)_memoryCache.Get(lockKey);
                if (value != null && !value.Equals(lockValue))
                {
                    return(false);
                }

                _memoryCache.Put(lockKey, lockValue, _lockKeyTimeout);
                return(true);
            }
        }
示例#4
0
        private void IncreaseLock(CacheLockValue cacheLockValue, long value)
        {
            lock (cacheLockValue)
            {
                if (cacheLockValue.Failed)
                {
                    return;
                }

                cacheLockValue.RemainingLocks += value;
                Log.Debug("Remaining locks to acquire: '{0}'", cacheLockValue.RemainingLocks);
                if (cacheLockValue.RemainingLocks == 0)
                {
                    cacheLockValue.Semaphore.Release();
                }
            }
        }
        /// <inheritdoc />
        public override Task <string> LockManyAsync(object[] keys, CancellationToken cancellationToken)
        {
            if (keys == null)
            {
                throw new ArgumentNullException(nameof(keys));
            }
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <string>(cancellationToken));
            }
            return(InternalLockManyAsync());

            async Task <string> InternalLockManyAsync()
            {
                var lockKeys  = new string[keys.Length];
                var lockValue = _lockValueProvider.GetValue();

                for (var i = 0; i < keys.Length; i++)
                {
                    lockKeys[i] = GetLockKey(keys[i]);
                    Log.Debug("Locking key: '{0}'.", lockKeys[i]);
                }

                using (var cacheLockValue = new CacheLockValue(lockValue))
                {
                    object Context() => new KeyValuePair <string[], CacheLockValue>(lockKeys, cacheLockValue);

                    return(await(_retryPolicy
                                 .ExecuteAsync(async() =>
                    {
                        if (!LockManyLocal(lockKeys, cacheLockValue))
                        {
                            Log.Debug("Failed to acquire lock for '{0}' keys in the local cache, retrying...", lockKeys.Length);
                            return null;                                     // Retry
                        }

                        cacheLockValue.Setup();
                        var subscriberCount = await(_subscriber.PublishAsync(_synchronizationChannel, Serializer.Serialize(new CacheSynchronizationMessage
                        {
                            OperationType = OperationType.LockMany,
                            Timestamp = DateTime.UtcNow.Ticks,
                            ClientId = _clientId,
                            Data = new LockManyData
                            {
                                LockKeys = lockKeys,
                                LockValue = lockValue
                            }
                        }))).ConfigureAwait(false) - 1;

                        if (subscriberCount == 0)
                        {
                            Log.Debug("Acquired lock for '{0}' keys, no other caches were involved.", lockKeys.Length);
                            // We are the only one subscribed
                            return cacheLockValue.Value;
                        }

                        Log.Debug("Waiting lock result from '{0}' other local caches.", subscriberCount);
                        IncreaseLock(cacheLockValue, subscriberCount);
                        if (!await(cacheLockValue.Semaphore.WaitAsync(_lockAcquireTimeout, cancellationToken)).ConfigureAwait(false) || cacheLockValue.Failed)
                        {
                            Log.Debug("Failed to acquire lock for '{0}' keys from '{1}' other local caches, retrying...", lockKeys.Length, subscriberCount);
                            return null;
                        }

                        Log.Debug("Acquired lock for '{0}' keys, '{1}' other caches were involved.", lockKeys.Length, subscriberCount);
                        return cacheLockValue.Value;
                    }, Context, cancellationToken)).ConfigureAwait(false));
                }
            }
        }