Make CacheUtil only about writing

A subsequent change will rename it to CacheWriter and make it instantiable.

Issue: #5978
PiperOrigin-RevId: 312648623
This commit is contained in:
olly 2020-05-21 12:00:56 +01:00 committed by tonihei
parent 1154e8098a
commit 4384ef5b73
3 changed files with 25 additions and 123 deletions

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
import android.net.Uri;
import android.util.Pair;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
@ -30,6 +29,7 @@ import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheKeyFactory;
import com.google.android.exoplayer2.upstream.cache.CacheUtil;
import com.google.android.exoplayer2.upstream.cache.ContentMetadata;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import com.google.android.exoplayer2.util.Util;
@ -136,11 +136,18 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M>> impleme
long contentLength = 0;
long bytesDownloaded = 0;
for (int i = segments.size() - 1; i >= 0; i--) {
Segment segment = segments.get(i);
Pair<Long, Long> segmentLengthAndBytesDownloaded =
CacheUtil.getCached(segment.dataSpec, cache, cacheKeyFactory);
long segmentLength = segmentLengthAndBytesDownloaded.first;
long segmentBytesDownloaded = segmentLengthAndBytesDownloaded.second;
DataSpec dataSpec = segments.get(i).dataSpec;
String cacheKey = cacheKeyFactory.buildCacheKey(dataSpec);
long segmentLength = dataSpec.length;
if (segmentLength == C.LENGTH_UNSET) {
long resourceLength =
ContentMetadata.getContentLength(cache.getContentMetadata(cacheKey));
if (resourceLength != C.LENGTH_UNSET) {
segmentLength = resourceLength - dataSpec.position;
}
}
long segmentBytesDownloaded =
cache.getCachedBytes(cacheKey, dataSpec.position, segmentLength);
bytesDownloaded += segmentBytesDownloaded;
if (segmentLength != C.LENGTH_UNSET) {
if (segmentLength == segmentBytesDownloaded) {

View File

@ -15,7 +15,6 @@
*/
package com.google.android.exoplayer2.upstream.cache;
import android.util.Pair;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.google.android.exoplayer2.C;
@ -57,38 +56,6 @@ public final class CacheUtil {
@Deprecated
public static final CacheKeyFactory DEFAULT_CACHE_KEY_FACTORY = CacheKeyFactory.DEFAULT;
/**
* Queries the cache to obtain the request length and the number of bytes already cached for a
* given {@link DataSpec}.
*
* @param dataSpec Defines the data to be checked.
* @param cache A {@link Cache} which has the data.
* @param cacheKeyFactory An optional factory for cache keys.
* @return A pair containing the request length and the number of bytes that are already cached.
*/
public static Pair<Long, Long> getCached(
DataSpec dataSpec, Cache cache, @Nullable CacheKeyFactory cacheKeyFactory) {
String key = buildCacheKey(dataSpec, cacheKeyFactory);
long position = dataSpec.position;
long requestLength = getRequestLength(dataSpec, cache, key);
long bytesAlreadyCached = 0;
long bytesLeft = requestLength;
while (bytesLeft != 0) {
long blockLength = cache.getCachedLength(key, position, bytesLeft);
if (blockLength > 0) {
bytesAlreadyCached += blockLength;
} else {
blockLength = -blockLength;
if (blockLength == Long.MAX_VALUE) {
break;
}
}
position += blockLength;
bytesLeft -= bytesLeft == C.LENGTH_UNSET ? 0 : blockLength;
}
return Pair.create(requestLength, bytesAlreadyCached);
}
/**
* Caches the data defined by {@code dataSpec}, skipping already cached data. Caching stops early
* if the end of the input is reached.
@ -157,23 +124,26 @@ public final class CacheUtil {
Assertions.checkNotNull(temporaryBuffer);
Cache cache = dataSource.getCache();
CacheKeyFactory cacheKeyFactory = dataSource.getCacheKeyFactory();
String key = buildCacheKey(dataSpec, cacheKeyFactory);
long bytesLeft;
String cacheKey = dataSource.getCacheKeyFactory().buildCacheKey(dataSpec);
long requestLength = dataSpec.length;
if (requestLength == C.LENGTH_UNSET) {
long resourceLength = ContentMetadata.getContentLength(cache.getContentMetadata(cacheKey));
if (resourceLength != C.LENGTH_UNSET) {
requestLength = resourceLength - dataSpec.position;
}
}
long bytesCached = cache.getCachedBytes(cacheKey, dataSpec.position, requestLength);
@Nullable ProgressNotifier progressNotifier = null;
if (progressListener != null) {
progressNotifier = new ProgressNotifier(progressListener);
Pair<Long, Long> lengthAndBytesAlreadyCached = getCached(dataSpec, cache, cacheKeyFactory);
progressNotifier.init(lengthAndBytesAlreadyCached.first, lengthAndBytesAlreadyCached.second);
bytesLeft = lengthAndBytesAlreadyCached.first;
} else {
bytesLeft = getRequestLength(dataSpec, cache, key);
progressNotifier.init(requestLength, bytesCached);
}
long position = dataSpec.position;
long bytesLeft = requestLength;
while (bytesLeft != 0) {
throwExceptionIfCanceled(isCanceled);
long blockLength = cache.getCachedLength(key, position, bytesLeft);
long blockLength = cache.getCachedLength(cacheKey, position, bytesLeft);
if (blockLength > 0) {
// Skip already cached data.
} else {
@ -206,15 +176,6 @@ public final class CacheUtil {
}
}
private static long getRequestLength(DataSpec dataSpec, Cache cache, String key) {
if (dataSpec.length != C.LENGTH_UNSET) {
return dataSpec.length;
} else {
long contentLength = ContentMetadata.getContentLength(cache.getContentMetadata(key));
return contentLength == C.LENGTH_UNSET ? C.LENGTH_UNSET : contentLength - dataSpec.position;
}
}
/**
* Reads and discards all data specified by the {@code dataSpec}.
*
@ -309,12 +270,6 @@ public final class CacheUtil {
}
}
private static String buildCacheKey(
DataSpec dataSpec, @Nullable CacheKeyFactory cacheKeyFactory) {
return (cacheKeyFactory != null ? cacheKeyFactory : CacheKeyFactory.DEFAULT)
.buildCacheKey(dataSpec);
}
private static void throwExceptionIfCanceled(@Nullable AtomicBoolean isCanceled)
throws InterruptedIOException {
if (isCanceled != null && isCanceled.get()) {

View File

@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
@ -104,65 +103,6 @@ public final class CacheUtilTest {
Util.recursiveDelete(tempFolder);
}
@Test
public void getCachedNoData() {
Pair<Long, Long> contentLengthAndBytesCached =
CacheUtil.getCached(
new DataSpec(Uri.parse("test")), mockCache, /* cacheKeyFactory= */ null);
assertThat(contentLengthAndBytesCached.first).isEqualTo(C.LENGTH_UNSET);
assertThat(contentLengthAndBytesCached.second).isEqualTo(0);
}
@Test
public void getCachedDataUnknownLength() {
// Mock there is 100 bytes cached at the beginning
mockCache.spansAndGaps = new int[] {100};
Pair<Long, Long> contentLengthAndBytesCached =
CacheUtil.getCached(
new DataSpec(Uri.parse("test")), mockCache, /* cacheKeyFactory= */ null);
assertThat(contentLengthAndBytesCached.first).isEqualTo(C.LENGTH_UNSET);
assertThat(contentLengthAndBytesCached.second).isEqualTo(100);
}
@Test
public void getCachedNoDataKnownLength() {
mockCache.contentLength = 1000;
Pair<Long, Long> contentLengthAndBytesCached =
CacheUtil.getCached(
new DataSpec(Uri.parse("test")), mockCache, /* cacheKeyFactory= */ null);
assertThat(contentLengthAndBytesCached.first).isEqualTo(1000);
assertThat(contentLengthAndBytesCached.second).isEqualTo(0);
}
@Test
public void getCached() {
mockCache.contentLength = 1000;
mockCache.spansAndGaps = new int[] {100, 100, 200};
Pair<Long, Long> contentLengthAndBytesCached =
CacheUtil.getCached(
new DataSpec(Uri.parse("test")), mockCache, /* cacheKeyFactory= */ null);
assertThat(contentLengthAndBytesCached.first).isEqualTo(1000);
assertThat(contentLengthAndBytesCached.second).isEqualTo(300);
}
@Test
public void getCachedFromNonZeroPosition() {
mockCache.contentLength = 1000;
mockCache.spansAndGaps = new int[] {100, 100, 200};
Pair<Long, Long> contentLengthAndBytesCached =
CacheUtil.getCached(
new DataSpec(Uri.parse("test"), /* position= */ 100, /* length= */ C.LENGTH_UNSET),
mockCache,
/* cacheKeyFactory= */ null);
assertThat(contentLengthAndBytesCached.first).isEqualTo(900);
assertThat(contentLengthAndBytesCached.second).isEqualTo(200);
}
@Test
public void cache() throws Exception {
FakeDataSet fakeDataSet = new FakeDataSet().setRandomData("test_data", 100);