private Task RunInsertionInSeparateThread(ICacheKey key, IWriterCallback callback) { return(Task.Run(() => { _cache.Insert(key, callback); })); }
/// <summary> /// Inserts resource into file with key. /// </summary> /// <param name="key">Cache key.</param> /// <param name="callback"> /// Callback that writes to an output stream. /// </param> /// <returns>A sequence of bytes.</returns> public IBinaryResource Insert(ICacheKey key, IWriterCallback callback) { // Write to a temp file, then move it into place. // This allows more parallelism when writing files. SettableCacheEvent cacheEvent = SettableCacheEvent.Obtain().SetCacheKey(key); _cacheEventListener.OnWriteAttempt(cacheEvent); string resourceId; lock (_lock) { // For multiple resource ids associated with the same image, // we only write one file resourceId = CacheKeyUtil.GetFirstResourceId(key); } cacheEvent.SetResourceId(resourceId); try { // Getting the file is synchronized IInserter inserter = StartInsert(resourceId, key); try { inserter.WriteData(callback, key); // Committing the file is synchronized IBinaryResource resource = EndInsert(inserter, key, resourceId); cacheEvent.SetItemSize(resource.GetSize()) .SetCacheSize(_cacheStats.Size); _cacheEventListener.OnWriteSuccess(cacheEvent); return(resource); } finally { if (!inserter.CleanUp()) { Debug.WriteLine("Failed to delete temp file"); } } } catch (IOException ioe) { cacheEvent.SetException(ioe); _cacheEventListener.OnWriteException(cacheEvent); Debug.WriteLine("Failed inserting a file into the cache"); throw; } finally { cacheEvent.Recycle(); } }
/// <summary> /// Update the contents of the resource to be inserted. Executes /// outside the session lock. The writer callback will be provided /// with an output Stream to write to. For high efficiency client /// should make sure that data is written in big chunks (for example /// by employing BufferedInputStream or writing all data at once). /// </summary> /// <param name="callback">The write callback.</param> /// <param name="debugInfo">Helper object for debugging.</param> public void WriteData(IWriterCallback callback, object debugInfo) { FileStream fileStream; try { fileStream = _temporaryFile.Create(); } catch (Exception) { _parent._cacheErrorLogger.LogError( CacheErrorCategory.WRITE_UPDATE_FILE_NOT_FOUND, typeof(DefaultDiskStorage), "updateResource"); throw; } long length; try { callback.Write(fileStream); // Just in case underlying stream's close method doesn't flush: // we flush it manually and inside the try/catch fileStream.Flush(); length = fileStream.Position; } finally { // If it fails to close (or write the last piece) we really want // to know. Normally we would want this to be quiet because a // closing exception would hide one inside the try, but now we // really want to know if something fails at Flush or Close fileStream.Dispose(); } // This code should never throw, but if filesystem doesn't fail on a // failing /uncomplete close we want to know and manually fail if (_temporaryFile.Length != length) { throw new IncompleteFileException(length, _temporaryFile.Length); } }
public void TestSizeEvictionClearsIndex() { _clock.SetDateTime(DateTime.Now.Add(TimeSpan.FromDays(1))); ICacheKey key1 = PutOneThingInCache(); ICacheKey key2 = new SimpleCacheKey("bar"); ICacheKey key3 = new SimpleCacheKey("duck"); byte[] value2 = new byte[(int)FILE_CACHE_MAX_SIZE_HIGH_LIMIT]; value2[80] = 99; // 'c' IWriterCallback callback = WriterCallbacks.From(value2); _clock.SetDateTime(DateTime.Now.Add(TimeSpan.FromDays(2))); _cache.Insert(key2, callback); // Now over limit. Next write will evict key1 _clock.SetDateTime(DateTime.Now.Add(TimeSpan.FromDays(3))); _cache.Insert(key3, callback); Assert.IsFalse(_cache.HasKeySync(key1)); Assert.IsFalse(_cache.HasKey(key1)); Assert.IsTrue(_cache.HasKeySync(key3)); Assert.IsTrue(_cache.HasKey(key3)); }