Skip to content

Commit

Permalink
Make CacheUtil only about writing
Browse files Browse the repository at this point in the history
A subsequent change will rename it to CacheWriter and make it instantiable.

Issue: #5978
PiperOrigin-RevId: 312648623
  • Loading branch information
ojw28 authored and tonihei committed May 21, 2020
1 parent 1154e80 commit 4384ef5
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
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;
Expand All @@ -30,6 +29,7 @@
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;
Expand Down Expand Up @@ -136,11 +136,18 @@ public final void download(@Nullable ProgressListener progressListener) throws I
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -57,38 +56,6 @@ public interface ProgressListener {
@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.
Expand Down Expand Up @@ -157,23 +124,26 @@ public static void cache(
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 {
Expand Down Expand Up @@ -206,15 +176,6 @@ public static void cache(
}
}

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}.
*
Expand Down Expand Up @@ -309,12 +270,6 @@ private static long readAndDiscard(
}
}

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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
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;
Expand Down Expand Up @@ -104,65 +103,6 @@ public void tearDown() {
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);
Expand Down

0 comments on commit 4384ef5

Please sign in to comment.