private async Task InternalAddOrUpdate(TKey key, CFileSource src, CancellationToken token, ICacheExpirationPolicy policy) { //at this point we are not responsible of disposing 'src' cause it's lifetime is wider than this method var path = await UploadToCacheAsync(src, token); _entries[key] = new CFileCacheEntry() { Created = DateTime.UtcNow, FilePath = path }.Pulse(policy); }
private async Task <CFileCacheEntry> InternalGetOrAdd(TKey key, Func <TKey, Task <CFileSource> > provider, CancellationToken token, ICacheExpirationPolicy policy) { CFileCacheEntry cacheEntry; if (_entries.TryGetValue(key, out cacheEntry)) { return(cacheEntry.Pulse(policy)); } //per key mutex required to avoid multiple file upload to cache by same key. //files are very large objects, so unnecessary actions with them should be avoided if possible. using (await _perKeyLock.LockAsync(key, token)) { if (_entries.TryGetValue(key, out cacheEntry)) { return(cacheEntry.Pulse(policy)); } token.ThrowIfCancellationRequested(); //we are responsible for creation and disposing of stream we created, so we wrap src in using directive. using (var src = await provider(key)) { token.ThrowIfCancellationRequested(); var path = await UploadToCacheAsync(src, token); cacheEntry = new CFileCacheEntry() { Created = DateTime.UtcNow, FilePath = path }; //###### _entries[key] = cacheEntry; return(cacheEntry.Pulse(policy)); } } }