private static CacheDataSource buildCacheDataSource(Context context, DataSource upstreamSource, boolean useAesEncryption) throws CacheException { File cacheDir = context.getExternalCacheDir(); Cache cache = new SimpleCache(new File(cacheDir, EXO_CACHE_DIR), new NoOpCacheEvictor()); emptyCache(cache); // Source and cipher final String secretKey = "testKey:12345678"; DataSource file = new FileDataSource(); DataSource cacheReadDataSource = useAesEncryption ? new AesCipherDataSource(Util.getUtf8Bytes(secretKey), file) : file; // Sink and cipher CacheDataSink cacheSink = new CacheDataSink(cache, EXO_CACHE_MAX_FILESIZE); byte[] scratch = new byte[3897]; DataSink cacheWriteDataSink = useAesEncryption ? new AesCipherDataSink(Util.getUtf8Bytes(secretKey), cacheSink, scratch) : cacheSink; return new CacheDataSource(cache, upstreamSource, cacheReadDataSource, cacheWriteDataSink, CacheDataSource.FLAG_BLOCK_ON_CACHE, null); // eventListener }
/** Stores the index data to index file if there is a change. */ public void store() throws CacheException { if (!changed) { return; } writeFile(); changed = false; }
/** * Copies the given span with an updated last access time. Passed span becomes invalid after this * call. * * @param cacheSpan Span to be copied and updated. * @return a span with the updated last access time. * @throws CacheException If renaming of the underlying span file failed. */ public SimpleCacheSpan touch(SimpleCacheSpan cacheSpan) throws CacheException { // Remove the old span from the in-memory representation. Assertions.checkState(cachedSpans.remove(cacheSpan)); // Obtain a new span with updated last access timestamp. SimpleCacheSpan newCacheSpan = cacheSpan.copyWithUpdatedLastAccessTime(id); // Rename the cache file if (!cacheSpan.file.renameTo(newCacheSpan.file)) { throw new CacheException("Renaming of " + cacheSpan.file + " to " + newCacheSpan.file + " failed."); } // Add the updated span back into the in-memory representation. cachedSpans.add(newCacheSpan); return newCacheSpan; }
private void evictCache(Cache cache, long requiredSpace) { while (currentSize + requiredSpace > maxBytes) { try { cache.removeSpan(leastRecentlyUsed.first()); } catch (CacheException e) { // do nothing. } } }
private void evictCache(Cache cache, long requiredSpace) { while (currentSize + requiredSpace > maxBytes && !leastRecentlyUsed.isEmpty()) { try { cache.removeSpan(leastRecentlyUsed.first()); } catch (CacheException e) { // do nothing. } } }
@Test public void testExceptionDuringEvictionByLeastRecentlyUsedCacheEvictorNotHang() throws Exception { CachedContentIndex index = Mockito.spy(new CachedContentIndex(cacheDir)); SimpleCache simpleCache = new SimpleCache(cacheDir, new LeastRecentlyUsedCacheEvictor(20), index); // Add some content. CacheSpan cacheSpan = simpleCache.startReadWrite(KEY_1, 0); addCache(simpleCache, KEY_1, 0, 15); // Make index.store() throw exception from now on. doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { throw new Cache.CacheException("SimpleCacheTest"); } }).when(index).store(); // Adding more content will make LeastRecentlyUsedCacheEvictor evict previous content. try { addCache(simpleCache, KEY_1, 15, 15); Assert.fail("Exception was expected"); } catch (CacheException e) { // do nothing. } simpleCache.releaseHoleSpan(cacheSpan); // Although store() has failed, it should remove the first span and add the new one. NavigableSet<CacheSpan> cachedSpans = simpleCache.getCachedSpans(KEY_1); assertThat(cachedSpans).isNotNull(); assertThat(cachedSpans).hasSize(1); assertThat(cachedSpans.pollFirst().position).isEqualTo(15); }
private static void emptyCache(Cache cache) throws CacheException { for (String key : cache.getKeys()) { for (CacheSpan span : cache.getCachedSpans(key)) { cache.removeSpan(span); } } // Sanity check that the cache really is empty now. assertThat(cache.getKeys().isEmpty()).isTrue(); }
private void handleBeforeThrow(IOException exception) { if (currentDataSource == cacheReadDataSource || exception instanceof CacheException) { seenCacheError = true; } }