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