Commit be098401 by olly Committed by Oliver Woodman

Cache: Improve documentation and terminology

PiperOrigin-RevId: 312130813
parent ba33f604
......@@ -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.
*
* <p>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}.
* <p>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}.
*
* <p>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<String, String> 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;
......
......@@ -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 {
......
......@@ -205,13 +205,13 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
M manifest = getManifest(dataSource, manifestDataSpec);
List<Segment> 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));
}
}
......
......@@ -24,7 +24,20 @@ import java.util.NavigableSet;
import java.util.Set;
/**
* An interface for cache.
* A cache that supports partial caching of resources.
*
* <h3>Terminology</h3>
*
* <ul>
* <li>A <em>resource</em> is a complete piece of logical data, for example a complete media file.
* <li>A <em>cache key</em> uniquely identifies a resource. URIs are often suitable for use as
* cache keys, however this is not always the case. URIs are not suitable when caching
* resources obtained from a service that generates multiple URIs for the same underlying
* resource, for example because the service uses expiring URIs as a form of access control.
* <li>A <em>cache span</em> is a byte range within a resource, which may or may not be cached. A
* cache span that's not cached is called a <em>hole span</em>. A cache span that is cached
* corresponds to a single underlying file in the cache.
* </ul>
*/
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.
*
* <p>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<CacheSpan> 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<CacheSpan> 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<String> 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.
*
* <p>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 {
*
* <p>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 {
*
* <p>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 {
*
* <p>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.
*
* <p>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);
}
......@@ -24,13 +24,9 @@ import java.io.File;
*/
public class CacheSpan implements Comparable<CacheSpan> {
/**
* 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<CacheSpan> {
* 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<CacheSpan> {
/**
* 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
......
......@@ -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<SimpleCacheSpan> 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);
......
......@@ -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.
*
* <p>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<CachedContent> 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);
......
......@@ -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);
......
......@@ -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
......
......@@ -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.
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment