Exemple #1
0
        private bool ExecuteOperation(string cacheKey, object value, long timestamp, int clientId, bool publish, bool remove)
        {
            var message = publish
                                ? Serializer.Serialize(new CacheSynchronizationMessage
            {
                OperationType = remove ? OperationType.Remove : OperationType.Put,
                ClientId      = _clientId,
                Timestamp     = timestamp,
                Data          = remove
                                                ? (object)cacheKey
                                                : new PutData
                {
                    Key   = cacheKey,
                    Value = value
                }
            })
                                : null;
            var cacheValue = (CacheValue)_memoryCache.Get(cacheKey);

            if (cacheValue == null && TryPutLocal())
            {
                return(!remove);
            }

            var lockValue = cacheValue.Lock;

            lockValue.Wait();
            try
            {
                if (!IsActionValid(timestamp, clientId))
                {
                    return(false);
                }

                cacheValue = (CacheValue)_memoryCache.Get(cacheKey);

                // When a different thread calls TryPutLocal at the begining of the method
                // and gets the lock before the current thread we have to retry to put as the lock
                // value is not valid anymore
                if (cacheValue == null && TryPutLocal())                 // The key expired in the meantime
                {
                    return(!remove);
                }

                if (lockValue != cacheValue.Lock)
                {
                    return(ExecuteOperation(cacheKey, value, timestamp, clientId, publish, remove));
                }

                if (cacheValue.Timestamp == timestamp)
                {
                    if (Log.IsDebugEnabled())
                    {
                        Log.Debug(
                            "The timestamp for the key '{0}' is equal to the current one... " +
                            "comparing the client id in order to determine who has a higher priority. ", cacheKey);
                    }

                    if (cacheValue.ClientId > clientId)
                    {
                        return(false);
                    }
                }
                else if (cacheValue.Timestamp > timestamp)
                {
                    return(false);
                }

                if (cacheValue is RemovedCacheValue)
                {
                    if (remove)
                    {
                        cacheValue.Timestamp = timestamp;
                        cacheValue.ClientId  = clientId;
                        cacheValue.Version   = _version;
                    }
                    else
                    {
                        cacheValue = new CacheValue(value, timestamp, clientId, _version, cacheValue.Lock);
                    }
                }
                else
                {
                    if (remove)
                    {
                        cacheValue = new RemovedCacheValue(timestamp, clientId, _version, cacheValue.Lock);
                    }
                    else
                    {
                        cacheValue.Value     = value;
                        cacheValue.Timestamp = timestamp;
                        cacheValue.ClientId  = clientId;
                        cacheValue.Version   = _version;
                    }
                }

                if (remove)
                {
                    _memoryCache.Put(cacheKey, cacheValue, _maxSynchronizationTime);
                }
                else
                {
                    _memoryCache.Put(cacheKey, cacheValue);
                }

                if (publish)
                {
                    Publish(message);
                }

                return(true);
            }
            finally
            {
                lockValue.Release();
            }

            bool TryPutLocal()
            {
                _writeLock.Wait();
                try
                {
                    cacheValue = (CacheValue)_memoryCache.Get(cacheKey);
                    if (cacheValue != null)
                    {
                        return(false);
                    }

                    if (remove)
                    {
                        _memoryCache.Put(cacheKey, new RemovedCacheValue(timestamp, clientId, _version), _maxSynchronizationTime);
                    }
                    else
                    {
                        _memoryCache.Put(cacheKey, new CacheValue(value, timestamp, clientId, _version));
                    }

                    if (publish)
                    {
                        Publish(message);
                    }

                    return(true);
                }
                finally
                {
                    _writeLock.Release();
                }
            }
        }
Exemple #2
0
        private bool ExecuteOperation(string cacheKey, object value, bool publish, bool remove)
        {
            var invalidationMessage = publish
                                ? _serializer.Serialize(new CacheKeyInvalidationMessage
            {
                ClientId = _clientId,
                Key      = cacheKey
            })
                                : null;

            var cacheValue = (CacheValue)_memoryCache.Get(cacheKey);

            if (cacheValue == null && TryPutLocal())
            {
                return(!remove);
            }

            var lockValue = cacheValue.Lock;

            lockValue.Wait();
            try
            {
                cacheValue = (CacheValue)_memoryCache.Get(cacheKey);

                // When a different thread calls TryPutLocal at the begining of the method
                // and gets the lock before the current thread we have to retry to put as the lock
                // value is not valid anymore
                if (cacheValue == null && TryPutLocal())                 // The key expired in the meantime
                {
                    return(!remove);
                }

                if (lockValue != cacheValue.Lock)
                {
                    return(false);
                }

                if (cacheValue is RemovedCacheValue)
                {
                    if (remove)
                    {
                        cacheValue.Version = _version;
                    }
                    else
                    {
                        cacheValue = new CacheValue(value, _version, cacheValue.Lock);
                    }
                }
                else
                {
                    if (remove)
                    {
                        cacheValue = new RemovedCacheValue(_version, cacheValue.Lock);
                    }
                    else
                    {
                        cacheValue.Value   = value;
                        cacheValue.Version = _version;
                    }
                }

                return(PutAndPublish());
            }
            finally
            {
                lockValue.Release();
            }

            bool TryPutLocal()
            {
                _writeLock.Wait();
                try
                {
                    cacheValue = (CacheValue)_memoryCache.Get(cacheKey);
                    if (cacheValue != null)
                    {
                        return(false);
                    }

                    return(PutAndPublish());
                }
                finally
                {
                    _writeLock.Release();
                }
            }

            bool PutAndPublish()
            {
                if (remove)
                {
                    RemoveLocal(cacheKey, new RemovedCacheValue(_version));
                }
                else
                {
                    PutLocal(cacheKey, new CacheValue(value, _version));
                }

                if (publish)
                {
                    ExecuteOperation(cacheKey, value, invalidationMessage, remove);
                }

                return(true);
            }
        }
Exemple #3
0
        private async Task <bool> ExecuteOperationAsync(string cacheKey, object value, bool publish, bool remove, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            var invalidationMessage = publish
                                ? _serializer.Serialize(new CacheKeyInvalidationMessage
            {
                ClientId = _clientId,
                Key      = cacheKey
            })
                                : null;

            var cacheValue = (CacheValue)_memoryCache.Get(cacheKey);

            cancellationToken.ThrowIfCancellationRequested();
            if (cacheValue == null && await(TryPutLocalAsync()).ConfigureAwait(false))
            {
                return(!remove);
            }

            var lockValue = cacheValue.Lock;

            await(lockValue.WaitAsync(cancellationToken)).ConfigureAwait(false);
            try
            {
                cacheValue = (CacheValue)_memoryCache.Get(cacheKey);
                cancellationToken.ThrowIfCancellationRequested();

                // When a different thread calls TryPutLocal at the begining of the method
                // and gets the lock before the current thread we have to retry to put as the lock
                // value is not valid anymore
                if (cacheValue == null && await(TryPutLocalAsync()).ConfigureAwait(false))                  // The key expired in the meantime
                {
                    return(!remove);
                }

                if (lockValue != cacheValue.Lock)
                {
                    return(false);
                }

                if (cacheValue is RemovedCacheValue)
                {
                    if (remove)
                    {
                        cacheValue.Version = _version;
                    }
                    else
                    {
                        cacheValue = new CacheValue(value, _version, cacheValue.Lock);
                    }
                }
                else
                {
                    if (remove)
                    {
                        cacheValue = new RemovedCacheValue(_version, cacheValue.Lock);
                    }
                    else
                    {
                        cacheValue.Value   = value;
                        cacheValue.Version = _version;
                    }
                }
                cancellationToken.ThrowIfCancellationRequested();

                return(await(PutAndPublishAsync()).ConfigureAwait(false));
            }
            finally
            {
                lockValue.Release();
            }

            async Task <bool> TryPutLocalAsync()
            {
                await(_writeLock.WaitAsync(cancellationToken)).ConfigureAwait(false);
                try
                {
                    cacheValue = (CacheValue)_memoryCache.Get(cacheKey);
                    if (cacheValue != null)
                    {
                        return(false);
                    }

                    return(await(PutAndPublishAsync()).ConfigureAwait(false));
                }
                finally
                {
                    _writeLock.Release();
                }
            }

            async Task <bool> PutAndPublishAsync()
            {
                if (remove)
                {
                    RemoveLocal(cacheKey, new RemovedCacheValue(_version));
                }
                else
                {
                    PutLocal(cacheKey, new CacheValue(value, _version));
                }

                if (publish)
                {
                    await(ExecuteOperationAsync(cacheKey, value, invalidationMessage, remove)).ConfigureAwait(false);
                }

                return(true);
            }
        }