/// <summary> /// Performs key-value loop up in staging area and file cache. /// Any error manifests itself as a miss, i.e. returns false. /// </summary> /// <param name="key">The cache key.</param> /// <returns> /// true if the image is found in staging area or File cache, /// false if not found. /// </returns> private bool CheckInStagingAreaAndFileCache(ICacheKey key) { EncodedImage result = _stagingArea.Get(key); if (result != null) { result.Dispose(); Debug.WriteLine($"Found image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaHit(); return(true); } else { Debug.WriteLine($"Did not find image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaMiss(); try { return(_fileCache.HasKey(key)); } catch (Exception) { return(false); } } }
private Task <EncodedImage> GetAsync(ICacheKey key, AtomicBoolean isCancelled) { try { if (isCancelled.Value) { throw new OperationCanceledException(); } EncodedImage result = _stagingArea.Get(key); if (result != null) { Debug.WriteLine($"Found image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaHit(); } else { Debug.WriteLine($"Did not find image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaMiss(); try { IPooledByteBuffer buffer = ReadFromDiskCache(key); if (buffer == null) { return(Task.FromResult(default(EncodedImage))); } CloseableReference <IPooledByteBuffer> reference = CloseableReference <IPooledByteBuffer> .of(buffer); try { result = new EncodedImage(reference); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely(reference); } } catch (Exception) { return(Task.FromResult(default(EncodedImage))); } } return(Task.FromResult(result)); } catch (Exception) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache read for { key.ToString() }"); throw; } }
/// <summary> /// Removes the item from the disk cache and the staging area. /// </summary> public Task Remove(ICacheKey key) { Preconditions.CheckNotNull(key); _stagingArea.Remove(key); Task writeTask = default(Task); _writeToDiskCacheTasks.TryRemove(key, out writeTask); try { return(_writeExecutor.Execute(() => { _stagingArea.Remove(key); _fileCache.Remove(key); })); } catch (Exception) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache remove for { key.ToString() }"); throw; } }
/// <summary> /// Writes to disk cache. /// </summary> private void WriteToDiskCache(ICacheKey key, EncodedImage encodedImage) { Debug.WriteLine($"About to write to disk-cache for key { key.ToString() }"); try { _fileCache.Insert(key, new WriterCallbackImpl(os => { _pooledByteStreams.Copy(encodedImage.GetInputStream(), os); })); Debug.WriteLine($"Successful disk-cache write for key { key.ToString() }"); } catch (IOException) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to write to disk-cache for key { key.ToString() }"); } }
/// <summary> /// Performs disk cache read. In case of any exception null is returned. /// </summary> private IPooledByteBuffer ReadFromDiskCache(ICacheKey key) { try { Debug.WriteLine($"Disk cache read for { key.ToString() }"); IBinaryResource diskCacheResource = _fileCache.GetResource(key); if (diskCacheResource == null) { Debug.WriteLine($"Disk cache miss for { key.ToString() }"); _imageCacheStatsTracker.OnDiskCacheMiss(); return(null); } else { Debug.WriteLine($"Found entry in disk cache for { key.ToString() }"); _imageCacheStatsTracker.OnDiskCacheHit(); } IPooledByteBuffer byteBuffer; using (Stream inputStream = diskCacheResource.OpenStream()) { byteBuffer = _pooledByteBufferFactory.NewByteBuffer( inputStream, (int)diskCacheResource.GetSize()); } Debug.WriteLine($"Successful read from disk cache for { key.ToString() }"); return(byteBuffer); } catch (Exception) { // TODO: 3697790 log failures // TODO: 5258772 - uncomment line below // _fileCache.Remove(key); Debug.WriteLine($"Exception reading from cache for { key.ToString() }"); _imageCacheStatsTracker.OnDiskCacheGetFail(); throw; } }
public async Task AddAsync <TItem>(ICacheKey key, TItem item) { _logger.LogTrace($"{TAG} AddAsync called for {key.ToString()}"); if (item == null) { return; } var cacheOptions = new MemoryCacheEntryOptions(); cacheOptions.SetSlidingExpiration(TimeSpan.FromMinutes(30)); _logger.LogTrace($"{TAG} Adding item to cache."); await Task.Run(() => _cache.Set(key.Key, item, cacheOptions)); }
private Task <bool> ContainsAsync(ICacheKey key) { try { return(_readExecutor.Execute(() => CheckInStagingAreaAndFileCache(key))); } catch (Exception) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache read for { key.ToString() }"); throw; } }
/// <summary> /// Associates encodedImage with given key in disk cache. /// Disk write is performed on background thread, so the /// caller of this method is not blocked. /// </summary> public Task Put(ICacheKey key, EncodedImage encodedImage) { Preconditions.CheckNotNull(key); Preconditions.CheckArgument(EncodedImage.IsValid(encodedImage)); // Store encodedImage in staging area _stagingArea.Put(key, encodedImage); // Write to disk cache. This will be executed on background thread, // so increment the ref count. When this write completes // (with success/failure), then we will bump down the ref count again. EncodedImage finalEncodedImage = EncodedImage.CloneOrNull(encodedImage); try { Task writeTask = _writeExecutor.Execute(() => { try { WriteToDiskCache(key, finalEncodedImage); } finally { _stagingArea.Remove(key, finalEncodedImage); EncodedImage.CloseSafely(finalEncodedImage); // Removes write task after it's completed. Task writeTaskCompleted = default(Task); _writeToDiskCacheTasks.TryRemove(key, out writeTaskCompleted); } }); _writeToDiskCacheTasks.TryAdd(key, writeTask); return(writeTask); } catch (Exception) { // We failed to enqueue cache write. Log failure and decrement ref count // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache write for { key.ToString() }"); _stagingArea.Remove(key, encodedImage); EncodedImage.CloseSafely(finalEncodedImage); // Removes write task due to error. Task writeTaskCompleted = default(Task); _writeToDiskCacheTasks.TryRemove(key, out writeTaskCompleted); throw; } }
private static string SecureHashKey(ICacheKey key) { byte[] utf8Bytes = Encoding.UTF8.GetBytes(key.ToString()); return(SecureHashUtil.MakeSHA1HashBase64(utf8Bytes)); }
/// <summary> /// Determine if an valid entry for the key exists in the staging area. /// </summary> public bool ContainsKey(ICacheKey key) { lock (_mapGate) { Preconditions.CheckNotNull(key); EncodedImage storedEncodedImage = default(EncodedImage); if (!_map.TryGetValue(key, out storedEncodedImage)) { return(false); } if (!EncodedImage.IsValid(storedEncodedImage)) { // Reference is not valid, this means that someone cleared reference // while it was still in use. // Log error TODO: 3697790 _map.Remove(key); Debug.WriteLine($"Found closed reference { storedEncodedImage.GetHashCode() } for key { key.ToString() } ({ key.GetHashCode() })"); return(false); } return(true); } }
public async Task <TItem> GetAsync <TItem>(ICacheKey key) where TItem : class { _logger.LogTrace($"{TAG} GetAsync called for {key.ToString()}"); return(await Task.Run(() => _cache.Get <TItem>(key.Key))); }
private Task <EncodedImage> FoundPinnedImage(ICacheKey key, EncodedImage pinnedImage) { Debug.WriteLine($"Found image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaHit(); return(Task.FromResult(pinnedImage)); }