public void TestBasicOperations()
        {
            DefaultDiskStorage storage     = GetStorageSupplier(1).Get();
            string             resourceId1 = "R1";
            string             resourceId2 = "R2";

            // No file - get should fail
            IBinaryResource resource1 = storage.GetResource(resourceId1, null);

            Assert.IsNull(resource1);

            // Write out the file now
            byte[] key1Contents = new byte[] { 0, 1, 2 };
            WriteToStorage(storage, resourceId1, key1Contents);

            // Get should succeed now
            resource1 = storage.GetResource(resourceId1, null);
            Assert.IsNotNull(resource1);
            FileInfo underlyingFile = ((FileBinaryResource)resource1).File;

            CollectionAssert.AreEqual(key1Contents, Files.ToByteArray(underlyingFile));

            // Remove the file now - get should fail again
            underlyingFile.Delete();

            resource1 = storage.GetResource(resourceId1, null);
            Assert.IsNull(resource1);

            // No file
            IBinaryResource resource2 = storage.GetResource(resourceId2, null);

            Assert.IsNull(resource2);
        }
Exemple #2
0
        public void TestVersioning()
        {
            // Define data that will be written to cache
            ICacheKey key = new SimpleCacheKey("version_test");

            byte[] value = new byte[32];
            value[0] = 118; // 'v'

            // Set up cache with version == 1
            IDiskStorage     storage1 = CreateDiskStorage(TESTCACHE_CURRENT_VERSION);
            DiskStorageCache cache1   = CreateDiskCache(storage1, false);

            // Write test data to cache 1
            cache1.Insert(key, WriterCallbacks.From(value));

            // Get cached file
            IBinaryResource resource1 = GetResource(storage1, key);

            Assert.IsNotNull(resource1);

            // Set up cache with version == 2
            IDiskStorage     storageSupplier2 = CreateDiskStorage(TESTCACHE_NEXT_VERSION);
            DiskStorageCache cache2           = CreateDiskCache(storageSupplier2, false);

            // Write test data to cache 2
            cache2.Insert(key, WriterCallbacks.From(value));

            // Get cached file
            IBinaryResource resource2 = GetResource(storageSupplier2, key);

            Assert.IsNotNull(resource2);

            // Make sure filenames of the two file are different
            Assert.IsFalse(resource2.Equals(resource1));
        }
Exemple #3
0
 private byte[] GetContents(IBinaryResource resource)
 {
     using (Stream file = resource.OpenStream())
     {
         byte[] contents = ByteStreams.ToByteArray(file);
         return(contents);
     }
 }
Exemple #4
0
        public void TestCacheFileWithIOException()
        {
            ICacheKey key1 = new SimpleCacheKey("aaa");

            // Before inserting, make sure files not exist.
            IBinaryResource resource1 = GetResource(key1);

            Assert.IsNull(resource1);

            // 1. Should not create cache files if IOException happens in the middle.
            IOException writeException = new IOException();

            try
            {
                _cache.Insert(key1, new WriterCallbackImpl(os =>
                {
                    throw writeException;
                }));

                Assert.Fail();
            }
            catch (IOException)
            {
                Assert.IsNull(GetResource(key1));
            }

            VerifyListenerOnWriteAttempt(key1);
            VerifyListenerOnWriteException(key1, writeException);

            // 2. Test a read failure from DiskStorage
            ICacheKey key2       = new SimpleCacheKey("bbb");
            int       value2Size = 42;

            byte[] value2 = new byte[value2Size];
            value2[25] = 98; // 'b'
            _cache.Insert(key2, WriterCallbacks.From(value2));

            VerifyListenerOnWriteAttempt(key2);
            string resourceId2 = VerifyListenerOnWriteSuccessAndGetResourceId(key2, value2Size);

            ((DiskStorageWithReadFailures)_storage).SetPoisonResourceId(resourceId2);

            Assert.IsNull(_cache.GetResource(key2));
            VerifyListenerOnReadException(key2, new IOException("Poisoned resource requested"));

            Assert.IsFalse(_cache.Probe(key2));
            VerifyListenerOnReadException(key2, new IOException("Poisoned resource requested"));

            DuplicatingCacheEventListener listener = (DuplicatingCacheEventListener)_cacheEventListener;

            Assert.IsTrue(listener.GetEvents("OnCleared").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnHit").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnMiss").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnEviction").Count == 0);
        }
        /// <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>
        /// Retrieves the file corresponding to the key, if it is in the cache.
        /// Also touches the item, thus changing its LRU timestamp. If the file
        /// is not present in the file cache, returns null.
        /// <para />
        /// This should NOT be called on the UI thread.
        /// </summary>
        /// <param name="key">The key to check.</param>
        /// <returns>
        /// The resource if present in cache, otherwise null.
        /// </returns>
        public IBinaryResource GetResource(ICacheKey key)
        {
            SettableCacheEvent cacheEvent = SettableCacheEvent
                                            .Obtain()
                                            .SetCacheKey(key);

            try
            {
                lock (_lock)
                {
                    IBinaryResource resource    = null;
                    IList <string>  resourceIds = CacheKeyUtil.GetResourceIds(key);
                    string          resourceId  = default(string);
                    foreach (var entry in resourceIds)
                    {
                        resourceId = entry;
                        cacheEvent.SetResourceId(resourceId);
                        resource = _storage.GetResource(resourceId, key);
                        if (resource != null)
                        {
                            break;
                        }
                    }

                    if (resource == null)
                    {
                        _cacheEventListener.OnMiss(cacheEvent);
                        _resourceIndex.Remove(resourceId);
                    }
                    else
                    {
                        _cacheEventListener.OnHit(cacheEvent);
                        _resourceIndex.Add(resourceId);
                    }

                    return(resource);
                }
            }
            catch (IOException ioe)
            {
                _cacheErrorLogger.LogError(
                    CacheErrorCategory.GENERIC_IO,
                    typeof(DiskStorageCache),
                    "GetResource");
                cacheEvent.SetException(ioe);
                _cacheEventListener.OnReadException(cacheEvent);
                return(null);
            }
            finally
            {
                cacheEvent.Recycle();
            }
        }
 /// <summary>
 /// Commits the provided temp file to the cache, renaming it to match
 /// the cache's hashing convention.
 /// </summary>
 private IBinaryResource EndInsert(
     IInserter inserter,
     ICacheKey key,
     string resourceId)
 {
     lock (_lock)
     {
         IBinaryResource resource = inserter.Commit(key);
         _resourceIndex.Add(resourceId);
         _cacheStats.Increment(resource.GetSize(), 1);
         return(resource);
     }
 }
Exemple #8
0
        public void TestCacheEventListener()
        {
            // 1. Add first cache file
            ICacheKey key1       = new SimpleCacheKey("foo");
            int       value1Size = 101;

            byte[] value1 = new byte[value1Size];
            value1[80] = 99; // 'c', just so it's not all zeros for the equality test below.
            IBinaryResource resource1 = _cache.Insert(key1, WriterCallbacks.From(value1));

            VerifyListenerOnWriteAttempt(key1);
            string resourceId1 = VerifyListenerOnWriteSuccessAndGetResourceId(key1, value1Size);

            IBinaryResource resource1Again = _cache.GetResource(key1);

            Assert.AreEqual(((FileBinaryResource)resource1).File.FullName,
                            ((FileBinaryResource)resource1Again).File.FullName);
            VerifyListenerOnHit(key1, resourceId1);

            IBinaryResource resource1Again2 = _cache.GetResource(key1);

            Assert.AreEqual(((FileBinaryResource)resource1).File.FullName,
                            ((FileBinaryResource)resource1Again2).File.FullName);
            VerifyListenerOnHit(key1, resourceId1);

            SimpleCacheKey  missingKey = new SimpleCacheKey("nonexistent_key");
            IBinaryResource res2       = _cache.GetResource(missingKey);

            Assert.IsNull(res2);
            VerifyListenerOnMiss(missingKey);

            DuplicatingCacheEventListener listener = (DuplicatingCacheEventListener)_cacheEventListener;

            listener.Clear();
            _cache.ClearAll();
            Assert.IsTrue(listener.GetEvents("OnCleared").Count != 0);
            Assert.IsTrue(listener.GetEvents("OnHit").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnMiss").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnWriteAttempt").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnWriteSuccess").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnReadException").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnWriteException").Count == 0);
            Assert.IsTrue(listener.GetEvents("OnEviction").Count == 0);
        }
        public void TestEntryIds()
        {
            DefaultDiskStorage storage = GetStorageSupplier(1).Get();

            byte[] value1 = new byte[101];
            byte[] value2 = new byte[102];
            byte[] value3 = new byte[103];
            value1[80] = 123;
            value2[80] = 45;
            value3[80] = 67;
            WriteFileToStorage(storage, "resourceId1", value1);
            WriteFileToStorage(storage, "resourceId2", value2);
            WriteFileToStorage(storage, "resourceId3", value3);

            // Check that resources are retrieved by the right name, before testing getEntries
            IBinaryResource res1 = storage.GetResource("resourceId1", null);
            IBinaryResource res2 = storage.GetResource("resourceId2", null);
            IBinaryResource res3 = storage.GetResource("resourceId3", null);

            CollectionAssert.AreEqual(value1, res1.Read());
            CollectionAssert.AreEqual(value2, res2.Read());
            CollectionAssert.AreEqual(value3, res3.Read());

            // Obtain entries and sort by name
            List <IEntry> entries = new List <IEntry>(storage.GetEntries());

            entries.Sort((a, b) =>
            {
                return(a.Id.CompareTo(b.Id));
            });

            Assert.AreEqual(3, entries.Count);
            Assert.AreEqual("resourceId1", entries[0].Id);
            Assert.AreEqual("resourceId2", entries[1].Id);
            Assert.AreEqual("resourceId3", entries[2].Id);
            CollectionAssert.AreEqual(value1, entries[0].Resource.Read());
            CollectionAssert.AreEqual(value2, entries[1].Resource.Read());
            CollectionAssert.AreEqual(value3, entries[2].Resource.Read());
        }
        /// <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;
            }
        }
        /// <summary>
        /// Gets the file cache path.
        /// </summary>
        /// <param name="uri">The image uri.</param>
        public Task <FileInfo> GetFileCachePath(Uri uri)
        {
            ICacheKey cacheKey = _cacheKeyFactory.GetEncodedCacheKey(
                ImageRequest.FromUri(uri), null);

            Task writeTask = _mainBufferedDiskCache.GetWriteToDiskCacheTask(cacheKey);

            if (writeTask != default(Task))
            {
                return(writeTask.ContinueWith(
                           task =>
                {
                    IBinaryResource resource = ImagePipelineFactory.Instance.GetMainDiskStorageCache().GetResource(cacheKey);
                    return ((FileBinaryResource)resource).File;
                },
                           TaskContinuationOptions.ExecuteSynchronously));
            }
            else
            {
                return(_mainBufferedDiskCache.Contains(cacheKey).ContinueWith(
                           task =>
                {
                    bool fileExists = task.Result;
                    if (fileExists)
                    {
                        IBinaryResource resource = ImagePipelineFactory.Instance.GetMainDiskStorageCache().GetResource(cacheKey);
                        return ((FileBinaryResource)resource).File;
                    }
                    else
                    {
                        return default(FileInfo);
                    }
                },
                           TaskContinuationOptions.ExecuteSynchronously));
            }
        }