From be098401e9f9b7fac109a35c760fe204e9ac20e2 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 18 May 2020 20:24:53 +0100 Subject: [PATCH] Cache: Improve documentation and terminology PiperOrigin-RevId: 312130813 --- .../android/exoplayer2/upstream/DataSpec.java | 33 +++---- .../offline/ProgressiveDownloader.java | 2 +- .../exoplayer2/offline/SegmentDownloader.java | 4 +- .../exoplayer2/upstream/cache/Cache.java | 91 ++++++++++--------- .../exoplayer2/upstream/cache/CacheSpan.java | 16 ++-- .../upstream/cache/CachedContent.java | 22 +++-- .../upstream/cache/CachedContentIndex.java | 33 ++++--- .../upstream/cache/SimpleCache.java | 2 +- .../upstream/cache/SimpleCacheSpan.java | 20 ++-- .../upstream/cache/CacheDataSourceTest.java | 2 +- .../upstream/cache/SimpleCacheTest.java | 2 +- 11 files changed, 120 insertions(+), 107 deletions(-) diff --git a/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java b/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java index cdbf3fee7d..395df63529 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/upstream/DataSpec.java @@ -27,9 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -/** - * Defines a region of data. - */ +/** Defines a region of data in a resource. */ public final class DataSpec { /** @@ -298,22 +296,21 @@ public final class DataSpec { } } - /** The {@link Uri} from which data should be read. */ + /** A {@link Uri} from which data belonging to the resource can be read. */ public final Uri uri; /** - * The offset of the data located at {@link #uri} within an original resource. + * The offset of the data located at {@link #uri} within the resource. * - *

Equal to 0 unless {@link #uri} provides access to a subset of an original resource. As an - * example, consider a resource that can be requested over the network and is 1000 bytes long. If - * {@link #uri} points to a local file that contains just bytes [200-300], then this field will be - * set to {@code 200}. + *

Equal to 0 unless {@link #uri} provides access to a subset of the resource. As an example, + * consider a resource that can be requested over the network and is 1000 bytes long. If {@link + * #uri} points to a local file that contains just bytes [200-300], then this field will be set to + * {@code 200}. * *

This field can be ignored except for in specific circumstances where the absolute position - * in the original resource is required in a {@link DataSource} chain. One example is when a - * {@link DataSource} needs to decrypt the content as it's read. In this case the absolute - * position in the original resource is typically needed to correctly initialize the decryption - * algorithm. + * in the resource is required in a {@link DataSource} chain. One example is when a {@link + * DataSource} needs to decrypt the content as it's read. In this case the absolute position in + * the resource is typically needed to correctly initialize the decryption algorithm. */ public final long uriPositionOffset; @@ -353,11 +350,11 @@ public final class DataSpec { public final Map httpRequestHeaders; /** - * The absolute position of the data in the full stream. + * The absolute position of the data in the resource. * * @deprecated Use {@link #position} except for specific use cases where the absolute position - * within the original resource is required within a {@link DataSource} chain. Where the - * absolute position is required, use {@code uriPositionOffset + position}. + * within the resource is required within a {@link DataSource} chain. Where the absolute + * position is required, use {@code uriPositionOffset + position}. */ @Deprecated public final long absoluteStreamPosition; @@ -370,8 +367,8 @@ public final class DataSpec { public final long length; /** - * A key that uniquely identifies the original stream. Used for cache indexing. May be null if the - * data spec is not intended to be used in conjunction with a cache. + * A key that uniquely identifies the resource. Used for cache indexing. May be null if the data + * spec is not intended to be used in conjunction with a cache. */ @Nullable public final String key; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java index 794b537ab6..434ca8fd5d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloader.java @@ -134,7 +134,7 @@ public final class ProgressiveDownloader implements Downloader { @Override public void remove() { - dataSource.getCache().removeSpans(dataSource.getCacheKeyFactory().buildCacheKey(dataSpec)); + dataSource.getCache().removeResource(dataSource.getCacheKeyFactory().buildCacheKey(dataSpec)); } private static final class ProgressForwarder implements CacheUtil.ProgressListener { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java index 3269d062ee..3358cc02c8 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloader.java @@ -205,13 +205,13 @@ public abstract class SegmentDownloader> impleme M manifest = getManifest(dataSource, manifestDataSpec); List segments = getSegments(dataSource, manifest, true); for (int i = 0; i < segments.size(); i++) { - cache.removeSpans(cacheKeyFactory.buildCacheKey(segments.get(i).dataSpec)); + cache.removeResource(cacheKeyFactory.buildCacheKey(segments.get(i).dataSpec)); } } catch (IOException e) { // Ignore exceptions when removing. } finally { // Always attempt to remove the manifest. - cache.removeSpans(cacheKeyFactory.buildCacheKey(manifestDataSpec)); + cache.removeResource(cacheKeyFactory.buildCacheKey(manifestDataSpec)); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java index b96388b8af..fe7d34850b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/Cache.java @@ -24,7 +24,20 @@ import java.util.NavigableSet; import java.util.Set; /** - * An interface for cache. + * A cache that supports partial caching of resources. + * + *

Terminology

+ * + * */ public interface Cache { @@ -108,51 +121,45 @@ public interface Cache { void release(); /** - * Registers a listener to listen for changes to a given key. + * Registers a listener to listen for changes to a given resource. * *

No guarantees are made about the thread or threads on which the listener is called, but it * is guaranteed that listener methods will be called in a serial fashion (i.e. one at a time) and * in the same order as events occurred. * - * @param key The key to listen to. + * @param key The cache key of the resource. * @param listener The listener to add. - * @return The current spans for the key. + * @return The current spans for the resource. */ NavigableSet addListener(String key, Listener listener); /** * Unregisters a listener. * - * @param key The key to stop listening to. + * @param key The cache key of the resource. * @param listener The listener to remove. */ void removeListener(String key, Listener listener); /** - * Returns the cached spans for a given cache key. + * Returns the cached spans for a given resource. * - * @param key The key for which spans should be returned. + * @param key The cache key of the resource. * @return The spans for the key. */ NavigableSet getCachedSpans(String key); - /** - * Returns all keys in the cache. - * - * @return All the keys in the cache. - */ + /** Returns the cache keys of all of the resources that are at least partially cached. */ Set getKeys(); /** * Returns the total disk space in bytes used by the cache. - * - * @return The total disk space in bytes. */ long getCacheSpace(); /** - * A caller should invoke this method when they require data from a given position for a given - * key. + * A caller should invoke this method when they require data starting from a given position in a + * given resource. * *

If there is a cache entry that overlaps the position, then the returned {@link CacheSpan} * defines the file in which the data is stored. {@link CacheSpan#isCached} is true. The caller @@ -168,8 +175,8 @@ public interface Cache { * *

This method may be slow and shouldn't normally be called on the main thread. * - * @param key The key of the data being requested. - * @param position The position of the data being requested. + * @param key The cache key of the resource. + * @param position The starting position in the resource from which data is required. * @return The {@link CacheSpan}. * @throws InterruptedException If the thread was interrupted. * @throws CacheException If an error is encountered. @@ -183,8 +190,8 @@ public interface Cache { * *

This method may be slow and shouldn't normally be called on the main thread. * - * @param key The key of the data being requested. - * @param position The position of the data being requested. + * @param key The cache key of the resource. + * @param position The starting position in the resource from which data is required. * @return The {@link CacheSpan}. Or null if the cache entry is locked. * @throws CacheException If an error is encountered. */ @@ -198,8 +205,8 @@ public interface Cache { * *

This method may be slow and shouldn't normally be called on the main thread. * - * @param key The cache key for the data. - * @param position The starting position of the data. + * @param key The cache key of the resource being written. + * @param position The starting position in the resource from which data will be written. * @param length The length of the data being written, or {@link C#LENGTH_UNSET} if unknown. Used * only to ensure that there is enough space in the cache. * @return The file into which data should be written. @@ -230,12 +237,12 @@ public interface Cache { void releaseHoleSpan(CacheSpan holeSpan); /** - * Removes all {@link CacheSpan CacheSpans} with the given key, deleting the underlying files. + * Removes all {@link CacheSpan CacheSpans} for a resource, deleting the underlying files. * - * @param key The cache key for the data. + * @param key The cache key of the resource being removed. */ @WorkerThread - void removeSpans(String key); + void removeResource(String key); /** * Removes a cached {@link CacheSpan} from the cache, deleting the underlying file. @@ -248,34 +255,36 @@ public interface Cache { void removeSpan(CacheSpan span); /** - * Queries if a range is entirely available in the cache. + * Returns whether the specified range of data in a resource is fully cached. * - * @param key The cache key for the data. - * @param position The starting position of the data. + * @param key The cache key of the resource. + * @param position The starting position of the data in the resource. * @param length The length of the data. * @return true if the data is available in the Cache otherwise false; */ boolean isCached(String key, long position, long length); /** - * Returns the length of the cached data block starting from the {@code position} to the block end - * up to {@code length} bytes. If the {@code position} isn't cached then -(the length of the gap - * to the next cached data up to {@code length} bytes) is returned. + * Returns the length of continuously cached data starting from {@code position}, up to a maximum + * of {@code maxLength}, of a resource. If {@code position} isn't cached then {@code -holeLength} + * is returned, where {@code holeLength} is the length of continuously uncached data starting from + * {@code position}, up to a maximum of {@code maxLength}. * - * @param key The cache key for the data. - * @param position The starting position of the data. - * @param length The maximum length of the data to be returned. - * @return The length of the cached or not cached data block length. + * @param key The cache key of the resource. + * @param position The starting position of the data in the resource. + * @param length The maximum length of the data or hole to be returned. + * @return The length of the continuously cached data, or {@code -holeLength} if {@code position} + * isn't cached. */ long getCachedLength(String key, long position, long length); /** - * Applies {@code mutations} to the {@link ContentMetadata} for the given key. A new {@link - * CachedContent} is added if there isn't one already with the given key. + * Applies {@code mutations} to the {@link ContentMetadata} for the given resource. A new {@link + * CachedContent} is added if there isn't one already for the resource. * *

This method may be slow and shouldn't normally be called on the main thread. * - * @param key The cache key for the data. + * @param key The cache key of the resource. * @param mutations Contains mutations to be applied to the metadata. * @throws CacheException If an error is encountered. */ @@ -284,10 +293,10 @@ public interface Cache { throws CacheException; /** - * Returns a {@link ContentMetadata} for the given key. + * Returns a {@link ContentMetadata} for the given resource. * - * @param key The cache key for the data. - * @return A {@link ContentMetadata} for the given key. + * @param key The cache key of the resource. + * @return The {@link ContentMetadata} for the resource. */ ContentMetadata getContentMetadata(String key); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java index bf51a69240..a4dacbe95c 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheSpan.java @@ -24,13 +24,9 @@ import java.io.File; */ public class CacheSpan implements Comparable { - /** - * The cache key that uniquely identifies the original stream. - */ + /** The cache key that uniquely identifies the resource. */ public final String key; - /** - * The position of the {@link CacheSpan} in the original stream. - */ + /** The position of the {@link CacheSpan} in the resource. */ public final long position; /** * The length of the {@link CacheSpan}, or {@link C#LENGTH_UNSET} if this is an open-ended hole. @@ -49,8 +45,8 @@ public class CacheSpan implements Comparable { * Creates a hole CacheSpan which isn't cached, has no last touch timestamp and no file * associated. * - * @param key The cache key that uniquely identifies the original stream. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key that uniquely identifies the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @param length The length of the {@link CacheSpan}, or {@link C#LENGTH_UNSET} if this is an * open-ended hole. */ @@ -61,8 +57,8 @@ public class CacheSpan implements Comparable { /** * Creates a CacheSpan. * - * @param key The cache key that uniquely identifies the original stream. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key that uniquely identifies the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @param length The length of the {@link CacheSpan}, or {@link C#LENGTH_UNSET} if this is an * open-ended hole. * @param lastTouchTimestamp The last touch timestamp, or {@link C#TIME_UNSET} if {@link diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java index 7abb9b3896..01671accf3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContent.java @@ -21,14 +21,14 @@ import com.google.android.exoplayer2.util.Log; import java.io.File; import java.util.TreeSet; -/** Defines the cached content for a single stream. */ +/** Defines the cached content for a single resource. */ /* package */ final class CachedContent { private static final String TAG = "CachedContent"; - /** The cache file id that uniquely identifies the original stream. */ + /** The cache id that uniquely identifies the resource. */ public final int id; - /** The cache key that uniquely identifies the original stream. */ + /** The cache key that uniquely identifies the resource. */ public final String key; /** The cached spans of this content. */ private final TreeSet cachedSpans; @@ -40,8 +40,8 @@ import java.util.TreeSet; /** * Creates a CachedContent. * - * @param id The cache file id. - * @param key The cache stream key. + * @param id The cache id of the resource. + * @param key The cache key of the resource. */ public CachedContent(int id, String key) { this(id, key, DefaultContentMetadata.EMPTY); @@ -106,13 +106,15 @@ import java.util.TreeSet; } /** - * Returns the length of the cached data block starting from the {@code position} to the block end - * up to {@code length} bytes. If the {@code position} isn't cached then -(the length of the gap - * to the next cached data up to {@code length} bytes) is returned. + * Returns the length of continuously cached data starting from {@code position}, up to a maximum + * of {@code maxLength}. If {@code position} isn't cached, then {@code -holeLength} is returned, + * where {@code holeLength} is the length of continuously un-cached data starting from {@code + * position}, up to a maximum of {@code maxLength}. * * @param position The starting position of the data. - * @param length The maximum length of the data to be returned. - * @return the length of the cached or not cached data block length. + * @param length The maximum length of the data or hole to be returned. + * @return The length of continuously cached data, or {@code -holeLength} if {@code position} + * isn't cached. */ public long getCachedBytesLength(long position, long length) { SimpleCacheSpan span = getSpan(position); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java index 43bf691701..62c831ca11 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CachedContentIndex.java @@ -48,6 +48,7 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -223,31 +224,35 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } /** - * Adds the given key to the index if it isn't there already. + * Adds a resource to the index, if it's not there already. * - * @param key The cache key that uniquely identifies the original stream. - * @return A new or existing CachedContent instance with the given key. + * @param key The cache key of the resource. + * @return The new or existing {@link CachedContent} corresponding to the resource. */ public CachedContent getOrAdd(String key) { @Nullable CachedContent cachedContent = keyToContent.get(key); return cachedContent == null ? addNew(key) : cachedContent; } - /** Returns a CachedContent instance with the given key or null if there isn't one. */ + /** + * Returns the {@link CachedContent} for a resource, or {@code null} if the resource is not + * present in the index. + * + * @param key The cache key of the resource. + */ @Nullable public CachedContent get(String key) { return keyToContent.get(key); } /** - * Returns a Collection of all CachedContent instances in the index. The collection is backed by - * the {@code keyToContent} map, so changes to the map are reflected in the collection, and - * vice-versa. If the map is modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), the results of the iteration are - * undefined. + * Returns a read only collection of all {@link CachedContent CachedContents} in the index. + * + *

Subsequent changes to the index are reflected in the returned collection. If the index is + * modified whilst iterating over the collection, the result of the iteration is undefined. */ public Collection getAll() { - return keyToContent.values(); + return Collections.unmodifiableCollection(keyToContent.values()); } /** Returns an existing or new id assigned to the given key. */ @@ -261,7 +266,11 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; return idToKey.get(id); } - /** Removes {@link CachedContent} with the given key from index if it's empty and not locked. */ + /** + * Removes a resource if its {@link CachedContent} is both empty and unlocked. + * + * @param key The cache key of the resource. + */ public void maybeRemove(String key) { @Nullable CachedContent cachedContent = keyToContent.get(key); if (cachedContent != null && cachedContent.isEmpty() && !cachedContent.isLocked()) { @@ -282,7 +291,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType; } } - /** Removes empty and not locked {@link CachedContent} instances from index. */ + /** Removes all resources whose {@link CachedContent CachedContents} are empty and unlocked. */ public void removeEmpty() { String[] keys = new String[keyToContent.size()]; keyToContent.keySet().toArray(keys); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java index 5d3f430d6e..0cb379b241 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCache.java @@ -471,7 +471,7 @@ public final class SimpleCache implements Cache { } @Override - public synchronized void removeSpans(String key) { + public synchronized void removeResource(String key) { Assertions.checkState(!released); for (CacheSpan span : getCachedSpans(key)) { removeSpanInternal(span); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java index d8a0671469..3a5279c949 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheSpan.java @@ -23,7 +23,7 @@ import java.io.File; import java.util.regex.Matcher; import java.util.regex.Pattern; -/** This class stores span metadata in filename. */ +/** A {@link CacheSpan} that encodes metadata into the names of the underlying cache files. */ /* package */ final class SimpleCacheSpan extends CacheSpan { /* package */ static final String COMMON_SUFFIX = ".exo"; @@ -42,7 +42,7 @@ import java.util.regex.Pattern; * * @param cacheDir The parent abstract pathname. * @param id The cache file id. - * @param position The position of the stored data in the original stream. + * @param position The position of the stored data in the resource. * @param timestamp The file timestamp. * @return The cache file. */ @@ -53,8 +53,8 @@ import java.util.regex.Pattern; /** * Creates a lookup span. * - * @param key The cache key. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key of the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @return The span. */ public static SimpleCacheSpan createLookup(String key, long position) { @@ -64,8 +64,8 @@ import java.util.regex.Pattern; /** * Creates an open hole span. * - * @param key The cache key. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key of the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @return The span. */ public static SimpleCacheSpan createOpenHole(String key, long position) { @@ -75,8 +75,8 @@ import java.util.regex.Pattern; /** * Creates a closed hole span. * - * @param key The cache key. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key of the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @param length The length of the {@link CacheSpan}. * @return The span. */ @@ -190,8 +190,8 @@ import java.util.regex.Pattern; } /** - * @param key The cache key. - * @param position The position of the {@link CacheSpan} in the original stream. + * @param key The cache key of the resource. + * @param position The position of the {@link CacheSpan} in the resource. * @param length The length of the {@link CacheSpan}, or {@link C#LENGTH_UNSET} if this is an * open-ended hole. * @param lastTouchTimestamp The last touch timestamp, or {@link C#TIME_UNSET} if {@link diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 133c6b3d73..b4c259689e 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -432,7 +432,7 @@ public final class CacheDataSourceTest { TestUtil.readExactly(cacheDataSource, 100); // Delete cached data. - cache.removeSpans(cacheDataSource.getCacheKeyFactory().buildCacheKey(unboundedDataSpec)); + cache.removeResource(cacheDataSource.getCacheKeyFactory().buildCacheKey(unboundedDataSpec)); assertCacheEmpty(cache); // Read the rest of the data. diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java index 08c63443b4..f2406f9922 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/SimpleCacheTest.java @@ -236,7 +236,7 @@ public class SimpleCacheTest { addCache(simpleCache, KEY_2, 20, 10); simpleCache.releaseHoleSpan(holeSpan); - simpleCache.removeSpans(KEY_1); + simpleCache.removeResource(KEY_1); assertThat(simpleCache.getCachedSpans(KEY_1)).isEmpty(); assertThat(simpleCache.getCachedSpans(KEY_2)).hasSize(1); }