protected async Task RemoveLeastRecentlyUsedCacheItemWhenOverMaxCacheSize(CancellationToken cancellationToken) { var cacheStore = await StateManager.GetOrAddAsync <IReliableDictionary <string, CachedItem> >(CacheStoreName); var cacheStoreMetadata = await StateManager.GetOrAddAsync <IReliableDictionary <string, CacheStoreMetadata> >(CacheStoreMetadataName); bool continueRemovingItems = true; while (continueRemovingItems) { continueRemovingItems = false; cancellationToken.ThrowIfCancellationRequested(); await RetryHelper.ExecuteWithRetry(StateManager, async (tx, cancelToken, state) => { var metadata = await cacheStoreMetadata.TryGetValueAsync(tx, CacheStoreMetadataKey, LockMode.Update); if (metadata.HasValue) { _log?.Invoke($"Size: {metadata.Value.Size} Max Size: {GetMaxSizeInBytes()}"); if (metadata.Value.Size > GetMaxSizeInBytes()) { Func <string, Task <ConditionalValue <CachedItem> > > getCacheItem = async(string cacheKey) => await cacheStore.TryGetValueAsync(tx, cacheKey, LockMode.Update); var linkedDictionaryHelper = new LinkedDictionaryHelper(getCacheItem, ByteSizeOffset); var firstItemKey = metadata.Value.FirstCacheKey; var firstCachedItem = (await getCacheItem(firstItemKey)).Value; // Move item to last item if cached item is not expired if (firstCachedItem.AbsoluteExpiration > _systemClock.UtcNow) { // remove cached item var removeResult = await linkedDictionaryHelper.Remove(metadata.Value, firstCachedItem); await ApplyChanges(tx, cacheStore, cacheStoreMetadata, removeResult); // add to last var addLastResult = await linkedDictionaryHelper.AddLast(removeResult.CacheStoreMetadata, firstItemKey, firstCachedItem, firstCachedItem.Value); await ApplyChanges(tx, cacheStore, cacheStoreMetadata, addLastResult); continueRemovingItems = addLastResult.CacheStoreMetadata.Size > GetMaxSizeInBytes(); } else // Remove { _log?.Invoke($"Auto Removing: {metadata.Value.FirstCacheKey}"); var result = await linkedDictionaryHelper.Remove(metadata.Value, firstCachedItem); await ApplyChanges(tx, cacheStore, cacheStoreMetadata, result); await cacheStore.TryRemoveAsync(tx, metadata.Value.FirstCacheKey); continueRemovingItems = result.CacheStoreMetadata.Size > GetMaxSizeInBytes(); } } } }); await Task.Delay(TimeSpan.FromMilliseconds(100), cancellationToken); } }
public async Task SetCachedItemAsync(string key, byte[] value, TimeSpan?slidingExpiration, DateTimeOffset?absoluteExpiration) { if (slidingExpiration.HasValue) { var now = _systemClock.UtcNow; absoluteExpiration = now.AddMilliseconds(slidingExpiration.Value.TotalMilliseconds); } var cacheStore = await StateManager.GetOrAddAsync <IReliableDictionary <string, CachedItem> >(CacheStoreName); var cacheStoreMetadata = await StateManager.GetOrAddAsync <IReliableDictionary <string, CacheStoreMetadata> >(CacheStoreMetadataName); await RetryHelper.ExecuteWithRetry(StateManager, async (tx, cancellationToken, state) => { _log?.Invoke($"Set cached item called with key: {key} on partition id: {Partition?.PartitionInfo.Id}"); Func <string, Task <ConditionalValue <CachedItem> > > getCacheItem = async(string cacheKey) => await cacheStore.TryGetValueAsync(tx, cacheKey, LockMode.Update); var linkedDictionaryHelper = new LinkedDictionaryHelper(getCacheItem, ByteSizeOffset); var cacheStoreInfo = (await cacheStoreMetadata.TryGetValueAsync(tx, CacheStoreMetadataKey, LockMode.Update)).Value ?? new CacheStoreMetadata(0, null, null); var existingCacheItem = (await getCacheItem(key)).Value; var cachedItem = ApplyAbsoluteExpiration(existingCacheItem, absoluteExpiration) ?? new CachedItem(value, null, null, slidingExpiration, absoluteExpiration); // empty linked dictionary if (cacheStoreInfo.FirstCacheKey == null) { var metadata = new CacheStoreMetadata(value.Length + ByteSizeOffset, key, key); await cacheStoreMetadata.SetAsync(tx, CacheStoreMetadataKey, metadata); await cacheStore.SetAsync(tx, key, cachedItem); } else { var cacheMetadata = cacheStoreInfo; // linked node already exists in dictionary if (existingCacheItem != null) { var removeResult = await linkedDictionaryHelper.Remove(cacheStoreInfo, cachedItem); cacheMetadata = removeResult.CacheStoreMetadata; await ApplyChanges(tx, cacheStore, cacheStoreMetadata, removeResult); } // add to last var addLastResult = await linkedDictionaryHelper.AddLast(cacheMetadata, key, cachedItem, value); await ApplyChanges(tx, cacheStore, cacheStoreMetadata, addLastResult); } }); }
public async Task RemoveCachedItemAsync(string key) { var cacheStore = await StateManager.GetOrAddAsync <IReliableDictionary <string, CachedItem> >(CacheStoreName); var cacheStoreMetadata = await StateManager.GetOrAddAsync <IReliableDictionary <string, CacheStoreMetadata> >(CacheStoreMetadataName); await RetryHelper.ExecuteWithRetry(StateManager, async (tx, cancellationToken, state) => { _log?.Invoke($"Remove cached item called with key: {key} on partition id: {Partition?.PartitionInfo.Id}"); var cacheResult = await cacheStore.TryRemoveAsync(tx, key); if (cacheResult.HasValue) { Func <string, Task <ConditionalValue <CachedItem> > > getCacheItem = async(string cacheKey) => await cacheStore.TryGetValueAsync(tx, cacheKey, LockMode.Update); var linkedDictionaryHelper = new LinkedDictionaryHelper(getCacheItem, ByteSizeOffset); var cacheStoreInfo = (await cacheStoreMetadata.TryGetValueAsync(tx, CacheStoreMetadataKey, LockMode.Update)).Value ?? new CacheStoreMetadata(0, null, null); var result = await linkedDictionaryHelper.Remove(cacheStoreInfo, cacheResult.Value); await ApplyChanges(tx, cacheStore, cacheStoreMetadata, result); } }); }