mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Make CacheUtil documentation clearer
Also fixed some other Cache related javadoc. Issue: #3374 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=181440687
This commit is contained in:
parent
11bae0af5a
commit
1fc250a9f3
10 changed files with 138 additions and 41 deletions
|
|
@ -127,23 +127,24 @@ public interface Cache {
|
|||
/**
|
||||
* A caller should invoke this method when they require data from a given position for a given
|
||||
* key.
|
||||
* <p>
|
||||
* If there is a cache entry that overlaps the position, then the returned {@link CacheSpan}
|
||||
*
|
||||
* <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
|
||||
* may read from the cache file, but does not acquire any locks.
|
||||
* <p>
|
||||
* If there is no cache entry overlapping {@code offset}, then the returned {@link CacheSpan}
|
||||
*
|
||||
* <p>If there is no cache entry overlapping {@code offset}, then the returned {@link CacheSpan}
|
||||
* defines a hole in the cache starting at {@code position} into which the caller may write as it
|
||||
* obtains the data from some other source. The returned {@link CacheSpan} serves as a lock.
|
||||
* Whilst the caller holds the lock it may write data into the hole. It may split data into
|
||||
* multiple files. When the caller has finished writing a file it should commit it to the cache
|
||||
* by calling {@link #commitFile(File)}. When the caller has finished writing, it must release
|
||||
* the lock by calling {@link #releaseHoleSpan}.
|
||||
* multiple files. When the caller has finished writing a file it should commit it to the cache by
|
||||
* calling {@link #commitFile(File)}. When the caller has finished writing, it must release the
|
||||
* lock by calling {@link #releaseHoleSpan}.
|
||||
*
|
||||
* @param key The key of the data being requested.
|
||||
* @param position The position of the data being requested.
|
||||
* @return The {@link CacheSpan}.
|
||||
* @throws InterruptedException If the thread was interrupted.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
CacheSpan startReadWrite(String key, long position) throws InterruptedException, CacheException;
|
||||
|
||||
|
|
@ -154,8 +155,10 @@ public interface Cache {
|
|||
* @param key The key of the data being requested.
|
||||
* @param position The position of the data being requested.
|
||||
* @return The {@link CacheSpan}. Or null if the cache entry is locked.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
@Nullable CacheSpan startReadWriteNonBlocking(String key, long position) throws CacheException;
|
||||
@Nullable
|
||||
CacheSpan startReadWriteNonBlocking(String key, long position) throws CacheException;
|
||||
|
||||
/**
|
||||
* Obtains a cache file into which data can be written. Must only be called when holding a
|
||||
|
|
@ -166,14 +169,16 @@ public interface Cache {
|
|||
* @param maxLength The maximum length of the data to be written. Used only to ensure that there
|
||||
* is enough space in the cache.
|
||||
* @return The file into which data should be written.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
File startFile(String key, long position, long maxLength) throws CacheException;
|
||||
|
||||
/**
|
||||
* Commits a file into the cache. Must only be called when holding a corresponding hole
|
||||
* {@link CacheSpan} obtained from {@link #startReadWrite(String, long)}
|
||||
* Commits a file into the cache. Must only be called when holding a corresponding hole {@link
|
||||
* CacheSpan} obtained from {@link #startReadWrite(String, long)}
|
||||
*
|
||||
* @param file A newly written cache file.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
void commitFile(File file) throws CacheException;
|
||||
|
||||
|
|
@ -189,6 +194,7 @@ public interface Cache {
|
|||
* Removes a cached {@link CacheSpan} from the cache, deleting the underlying file.
|
||||
*
|
||||
* @param span The {@link CacheSpan} to remove.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
void removeSpan(CacheSpan span) throws CacheException;
|
||||
|
||||
|
|
@ -210,15 +216,16 @@ public interface Cache {
|
|||
* @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.
|
||||
* @return The length of the cached or not cached data block length.
|
||||
*/
|
||||
long getCachedBytes(String key, long position, long length);
|
||||
long getCachedLength(String key, long position, long length);
|
||||
|
||||
/**
|
||||
* Sets the content length for the given key.
|
||||
*
|
||||
* @param key The cache key for the data.
|
||||
* @param length The length of the data.
|
||||
* @throws CacheException If an error is encountered.
|
||||
*/
|
||||
void setContentLength(String key, long length) throws CacheException;
|
||||
|
||||
|
|
@ -227,7 +234,8 @@ public interface Cache {
|
|||
* com.google.android.exoplayer2.C#LENGTH_UNSET} otherwise.
|
||||
*
|
||||
* @param key The cache key for the data.
|
||||
* @return The content length for the given key if one set, or {@link
|
||||
* com.google.android.exoplayer2.C#LENGTH_UNSET} otherwise.
|
||||
*/
|
||||
long getContentLength(String key);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import java.io.OutputStream;
|
|||
*/
|
||||
public final class CacheDataSink implements DataSink {
|
||||
|
||||
/** Default buffer size. */
|
||||
/** Default buffer size in bytes. */
|
||||
public static final int DEFAULT_BUFFER_SIZE = 20480;
|
||||
|
||||
private final Cache cache;
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ public final class CacheUtil {
|
|||
counters.alreadyCachedBytes = 0;
|
||||
counters.newlyCachedBytes = 0;
|
||||
while (left != 0) {
|
||||
long blockLength = cache.getCachedBytes(key, start,
|
||||
left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||
long blockLength =
|
||||
cache.getCachedLength(key, start, left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||
if (blockLength > 0) {
|
||||
counters.alreadyCachedBytes += blockLength;
|
||||
} else {
|
||||
|
|
@ -126,6 +126,12 @@ public final class CacheUtil {
|
|||
* Caches the data defined by {@code dataSpec} while skipping already cached data. Caching stops
|
||||
* early if end of input is reached and {@code enableEOFException} is false.
|
||||
*
|
||||
* <p>If a {@link PriorityTaskManager} is given, it's used to pause and resume caching depending
|
||||
* on {@code priority} and the priority of other tasks registered to the PriorityTaskManager.
|
||||
* Please note that it's the responsibility of the calling code to call {@link
|
||||
* PriorityTaskManager#add} to register with the manager before calling this method, and to call
|
||||
* {@link PriorityTaskManager#remove} afterwards to unregister.
|
||||
*
|
||||
* @param dataSpec Defines the data to be cached.
|
||||
* @param cache A {@link Cache} to store the data.
|
||||
* @param dataSource A {@link CacheDataSource} that works on the {@code cache}.
|
||||
|
|
@ -164,8 +170,8 @@ public final class CacheUtil {
|
|||
long start = dataSpec.absoluteStreamPosition;
|
||||
long left = dataSpec.length != C.LENGTH_UNSET ? dataSpec.length : cache.getContentLength(key);
|
||||
while (left != 0) {
|
||||
long blockLength = cache.getCachedBytes(key, start,
|
||||
left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||
long blockLength =
|
||||
cache.getCachedLength(key, start, left != C.LENGTH_UNSET ? left : Long.MAX_VALUE);
|
||||
if (blockLength > 0) {
|
||||
// Skip already cached data.
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ import java.util.TreeSet;
|
|||
* @param length The maximum length of the data to be returned.
|
||||
* @return the length of the cached or not cached data block length.
|
||||
*/
|
||||
public long getCachedBytes(long position, long length) {
|
||||
public long getCachedBytesLength(long position, long length) {
|
||||
SimpleCacheSpan span = getSpan(position);
|
||||
if (span.isHoleSpan()) {
|
||||
// We don't have a span covering the start of the queried region.
|
||||
|
|
|
|||
|
|
@ -385,13 +385,13 @@ public final class SimpleCache implements Cache {
|
|||
@Override
|
||||
public synchronized boolean isCached(String key, long position, long length) {
|
||||
CachedContent cachedContent = index.get(key);
|
||||
return cachedContent != null && cachedContent.getCachedBytes(position, length) >= length;
|
||||
return cachedContent != null && cachedContent.getCachedBytesLength(position, length) >= length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getCachedBytes(String key, long position, long length) {
|
||||
public synchronized long getCachedLength(String key, long position, long length) {
|
||||
CachedContent cachedContent = index.get(key);
|
||||
return cachedContent != null ? cachedContent.getCachedBytes(position, length) : -length;
|
||||
return cachedContent != null ? cachedContent.getCachedBytesLength(position, length) : -length;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.upstream.cache;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -35,19 +36,50 @@ import java.util.regex.Pattern;
|
|||
private static final Pattern CACHE_FILE_PATTERN_V3 = Pattern.compile(
|
||||
"^(\\d+)\\.(\\d+)\\.(\\d+)\\.v3\\.exo$", Pattern.DOTALL);
|
||||
|
||||
public static File getCacheFile(File cacheDir, int id, long position,
|
||||
long lastAccessTimestamp) {
|
||||
/**
|
||||
* Returns a new {@link File} instance from {@code cacheDir}, {@code id}, {@code position}, {@code
|
||||
* lastAccessTimestamp}.
|
||||
*
|
||||
* @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 lastAccessTimestamp The last access timestamp.
|
||||
* @return The cache file.
|
||||
*/
|
||||
public static File getCacheFile(File cacheDir, int id, long position, long lastAccessTimestamp) {
|
||||
return new File(cacheDir, id + "." + position + "." + lastAccessTimestamp + SUFFIX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a lookup span.
|
||||
*
|
||||
* @param key The cache key.
|
||||
* @param position The position of the {@link CacheSpan} in the original stream.
|
||||
* @return The span.
|
||||
*/
|
||||
public static SimpleCacheSpan createLookup(String key, long position) {
|
||||
return new SimpleCacheSpan(key, position, C.LENGTH_UNSET, C.TIME_UNSET, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an open hole span.
|
||||
*
|
||||
* @param key The cache key.
|
||||
* @param position The position of the {@link CacheSpan} in the original stream.
|
||||
* @return The span.
|
||||
*/
|
||||
public static SimpleCacheSpan createOpenHole(String key, long position) {
|
||||
return new SimpleCacheSpan(key, position, C.LENGTH_UNSET, C.TIME_UNSET, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a closed hole span.
|
||||
*
|
||||
* @param key The cache key.
|
||||
* @param position The position of the {@link CacheSpan} in the original stream.
|
||||
* @param length The length of the {@link CacheSpan}.
|
||||
* @return The span.
|
||||
*/
|
||||
public static SimpleCacheSpan createClosedHole(String key, long position, long length) {
|
||||
return new SimpleCacheSpan(key, position, length, C.TIME_UNSET, null);
|
||||
}
|
||||
|
|
@ -60,6 +92,7 @@ import java.util.regex.Pattern;
|
|||
* @return The span, or null if the file name is not correctly formatted, or if the id is not
|
||||
* present in the content index.
|
||||
*/
|
||||
@Nullable
|
||||
public static SimpleCacheSpan createCacheEntry(File file, CachedContentIndex index) {
|
||||
String name = file.getName();
|
||||
if (!name.endsWith(SUFFIX)) {
|
||||
|
|
@ -81,6 +114,15 @@ import java.util.regex.Pattern;
|
|||
Long.parseLong(matcher.group(3)), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrades the cache file if it is created by an earlier version of {@link SimpleCache}.
|
||||
*
|
||||
* @param file The cache file.
|
||||
* @param index Cached content index.
|
||||
* @return Upgraded cache file or {@code null} if the file name is not correctly formatted or the
|
||||
* file can not be renamed.
|
||||
*/
|
||||
@Nullable
|
||||
private static File upgradeFile(File file, CachedContentIndex index) {
|
||||
String key;
|
||||
String filename = file.getName();
|
||||
|
|
@ -106,8 +148,17 @@ import java.util.regex.Pattern;
|
|||
return newCacheFile;
|
||||
}
|
||||
|
||||
private SimpleCacheSpan(String key, long position, long length, long lastAccessTimestamp,
|
||||
File file) {
|
||||
/**
|
||||
* @param key The cache key.
|
||||
* @param position The position of the {@link CacheSpan} in the original stream.
|
||||
* @param length The length of the {@link CacheSpan}, or {@link C#LENGTH_UNSET} if this is an
|
||||
* open-ended hole.
|
||||
* @param lastAccessTimestamp The last access timestamp, or {@link C#TIME_UNSET} if {@link
|
||||
* #isCached} is false.
|
||||
* @param file The file corresponding to this {@link CacheSpan}, or null if it's a hole.
|
||||
*/
|
||||
private SimpleCacheSpan(
|
||||
String key, long position, long length, long lastAccessTimestamp, @Nullable File file) {
|
||||
super(key, position, length, lastAccessTimestamp, file);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,11 @@ import java.util.ArrayList;
|
|||
/** Assertion methods for {@link com.google.android.exoplayer2.upstream.cache.Cache}. */
|
||||
/* package */ final class CacheAsserts {
|
||||
|
||||
/** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */
|
||||
/**
|
||||
* Asserts that the cache content is equal to the data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException {
|
||||
ArrayList<FakeData> allData = fakeDataSet.getAllData();
|
||||
Uri[] uris = new Uri[allData.size()];
|
||||
|
|
@ -43,6 +47,8 @@ import java.util.ArrayList;
|
|||
|
||||
/**
|
||||
* Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings)
|
||||
throws IOException {
|
||||
|
|
@ -55,6 +61,8 @@ import java.util.ArrayList;
|
|||
|
||||
/**
|
||||
* Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
|
||||
throws IOException {
|
||||
|
|
@ -67,7 +75,11 @@ import java.util.ArrayList;
|
|||
assertThat(cache.getCacheSpace()).isEqualTo(totalLength);
|
||||
}
|
||||
|
||||
/** Asserts that the cache contains the given subset of data in the {@code fakeDataSet}. */
|
||||
/**
|
||||
* Asserts that the cache contains the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertDataCached(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
|
||||
throws IOException {
|
||||
for (Uri uri : uris) {
|
||||
|
|
@ -75,7 +87,11 @@ import java.util.ArrayList;
|
|||
}
|
||||
}
|
||||
|
||||
/** Asserts that the cache contains the given data for {@code uriString}. */
|
||||
/**
|
||||
* Asserts that the cache contains the given data for {@code uriString} or not.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertDataCached(Cache cache, Uri uri, byte[] expected) throws IOException {
|
||||
CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public final class CacheUtilTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public long getCachedBytes(String key, long position, long length) {
|
||||
public long getCachedLength(String key, long position, long length) {
|
||||
for (int i = 0; i < spansAndGaps.length; i++) {
|
||||
int spanOrGap = spansAndGaps[i];
|
||||
if (position < spanOrGap) {
|
||||
|
|
|
|||
|
|
@ -218,36 +218,36 @@ public class SimpleCacheTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testGetCachedBytes() throws Exception {
|
||||
public void testGetCachedLength() throws Exception {
|
||||
SimpleCache simpleCache = getSimpleCache();
|
||||
CacheSpan cacheSpan = simpleCache.startReadWrite(KEY_1, 0);
|
||||
|
||||
// No cached bytes, returns -'length'
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 0, 100)).isEqualTo(-100);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 0, 100)).isEqualTo(-100);
|
||||
|
||||
// Position value doesn't affect the return value
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 20, 100)).isEqualTo(-100);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 20, 100)).isEqualTo(-100);
|
||||
|
||||
addCache(simpleCache, KEY_1, 0, 15);
|
||||
|
||||
// Returns the length of a single span
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 0, 100)).isEqualTo(15);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 0, 100)).isEqualTo(15);
|
||||
|
||||
// Value is capped by the 'length'
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 0, 10)).isEqualTo(10);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 0, 10)).isEqualTo(10);
|
||||
|
||||
addCache(simpleCache, KEY_1, 15, 35);
|
||||
|
||||
// Returns the length of two adjacent spans
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 0, 100)).isEqualTo(50);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 0, 100)).isEqualTo(50);
|
||||
|
||||
addCache(simpleCache, KEY_1, 60, 10);
|
||||
|
||||
// Not adjacent span doesn't affect return value
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 0, 100)).isEqualTo(50);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 0, 100)).isEqualTo(50);
|
||||
|
||||
// Returns length of hole up to the next cached span
|
||||
assertThat(simpleCache.getCachedBytes(KEY_1, 55, 100)).isEqualTo(-5);
|
||||
assertThat(simpleCache.getCachedLength(KEY_1, 55, 100)).isEqualTo(-5);
|
||||
|
||||
simpleCache.releaseHoleSpan(cacheSpan);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,11 @@ import java.util.ArrayList;
|
|||
*/
|
||||
public final class CacheAsserts {
|
||||
|
||||
/** Asserts that the cache content is equal to the data in the {@code fakeDataSet}. */
|
||||
/**
|
||||
* Asserts that the cache content is equal to the data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet) throws IOException {
|
||||
ArrayList<FakeData> allData = fakeDataSet.getAllData();
|
||||
Uri[] uris = new Uri[allData.size()];
|
||||
|
|
@ -48,6 +52,8 @@ public final class CacheAsserts {
|
|||
|
||||
/**
|
||||
* Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, String... uriStrings)
|
||||
throws IOException {
|
||||
|
|
@ -60,6 +66,8 @@ public final class CacheAsserts {
|
|||
|
||||
/**
|
||||
* Asserts that the cache content is equal to the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertCachedData(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
|
||||
throws IOException {
|
||||
|
|
@ -72,7 +80,11 @@ public final class CacheAsserts {
|
|||
assertEquals(totalLength, cache.getCacheSpace());
|
||||
}
|
||||
|
||||
/** Asserts that the cache contains the given subset of data in the {@code fakeDataSet}. */
|
||||
/**
|
||||
* Asserts that the cache contains the given subset of data in the {@code fakeDataSet}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertDataCached(Cache cache, FakeDataSet fakeDataSet, Uri... uris)
|
||||
throws IOException {
|
||||
for (Uri uri : uris) {
|
||||
|
|
@ -80,7 +92,11 @@ public final class CacheAsserts {
|
|||
}
|
||||
}
|
||||
|
||||
/** Asserts that the cache contains the given data for {@code uriString}. */
|
||||
/**
|
||||
* Asserts that the cache contains the given data for {@code uriString}.
|
||||
*
|
||||
* @throws IOException If an error occurred reading from the Cache.
|
||||
*/
|
||||
public static void assertDataCached(Cache cache, Uri uri, byte[] expected) throws IOException {
|
||||
CacheDataSource dataSource = new CacheDataSource(cache, DummyDataSource.INSTANCE, 0);
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
|
|
|
|||
Loading…
Reference in a new issue