Add Cache.getCachedBytes

This will replace the need to use CacheUtil.getCached, and is part of refactoring
CacheUtil to only do writing (it will be renamed to CacheWriter in a subsequent
change).

PiperOrigin-RevId: 312366040
This commit is contained in:
olly 2020-05-19 23:29:30 +01:00 committed by tonihei
parent a42a1f49ed
commit e87221c938
3 changed files with 101 additions and 0 deletions

View File

@ -279,6 +279,18 @@ public interface Cache {
*/ */
long getCachedLength(String key, long position, long length); long getCachedLength(String key, long position, long length);
/**
* Returns the total number of cached bytes between {@code position} (inclusive) and {@code
* (position + length)} (exclusive) of a resource.
*
* @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 to check. {@link C#LENGTH_UNSET} is permitted, and is
* equivalent to passing {@link Long#MAX_VALUE}.
* @return The total number of cached bytes.
*/
long getCachedBytes(String key, long position, long length);
/** /**
* Applies {@code mutations} to the {@link ContentMetadata} for the given resource. A new {@link * 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. * CachedContent} is added if there isn't one already for the resource.

View File

@ -501,6 +501,29 @@ public final class SimpleCache implements Cache {
return cachedContent != null ? cachedContent.getCachedBytesLength(position, length) : -length; return cachedContent != null ? cachedContent.getCachedBytesLength(position, length) : -length;
} }
@Override
public synchronized long getCachedBytes(String key, long position, long length) {
long endPosition = length == C.LENGTH_UNSET ? Long.MAX_VALUE : position + length;
if (endPosition < 0) {
// The calculation rolled over (length is probably Long.MAX_VALUE).
endPosition = Long.MAX_VALUE;
}
long currentPosition = position;
long cachedBytes = 0;
while (currentPosition < endPosition) {
long maxRemainingLength = endPosition - currentPosition;
long blockLength = getCachedLength(key, currentPosition, maxRemainingLength);
if (blockLength > 0) {
cachedBytes += blockLength;
} else {
// There's a hole of length -blockLength.
blockLength = -blockLength;
}
currentPosition += blockLength;
}
return cachedBytes;
}
@Override @Override
public synchronized void applyContentMetadataMutations( public synchronized void applyContentMetadataMutations(
String key, ContentMetadataMutations mutations) throws CacheException { String key, ContentMetadataMutations mutations) throws CacheException {

View File

@ -409,6 +409,72 @@ public class SimpleCacheTest {
.isEqualTo(15); .isEqualTo(15);
} }
@Test
public void getCachedBytes_noCachedContent_returnsZero() {
SimpleCache simpleCache = getSimpleCache();
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ 100))
.isEqualTo(0);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ Long.MAX_VALUE))
.isEqualTo(0);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ LENGTH_UNSET))
.isEqualTo(0);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ 100))
.isEqualTo(0);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ Long.MAX_VALUE))
.isEqualTo(0);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ LENGTH_UNSET))
.isEqualTo(0);
}
@Test
public void getCachedBytes_withMultipleAdjacentSpans_returnsCachedBytes() throws Exception {
SimpleCache simpleCache = getSimpleCache();
CacheSpan cacheSpan = simpleCache.startReadWrite(KEY_1, /* position= */ 0);
addCache(simpleCache, KEY_1, /* position= */ 0, /* length= */ 25);
addCache(simpleCache, KEY_1, /* position= */ 25, /* length= */ 25);
simpleCache.releaseHoleSpan(cacheSpan);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ 100))
.isEqualTo(50);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ Long.MAX_VALUE))
.isEqualTo(50);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ LENGTH_UNSET))
.isEqualTo(50);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ 100))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ Long.MAX_VALUE))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ LENGTH_UNSET))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ 15))
.isEqualTo(15);
}
@Test
public void getCachedBytes_withMultipleNonAdjacentSpans_returnsCachedBytes() throws Exception {
SimpleCache simpleCache = getSimpleCache();
CacheSpan cacheSpan = simpleCache.startReadWrite(KEY_1, /* position= */ 0);
addCache(simpleCache, KEY_1, /* position= */ 0, /* length= */ 10);
addCache(simpleCache, KEY_1, /* position= */ 15, /* length= */ 35);
simpleCache.releaseHoleSpan(cacheSpan);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ 100))
.isEqualTo(45);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ Long.MAX_VALUE))
.isEqualTo(45);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 0, /* length= */ LENGTH_UNSET))
.isEqualTo(45);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ 100))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ Long.MAX_VALUE))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ LENGTH_UNSET))
.isEqualTo(30);
assertThat(simpleCache.getCachedBytes(KEY_1, /* position= */ 20, /* length= */ 10))
.isEqualTo(10);
}
/* Tests https://github.com/google/ExoPlayer/issues/3260 case. */ /* Tests https://github.com/google/ExoPlayer/issues/3260 case. */
@Test @Test
public void exceptionDuringEvictionByLeastRecentlyUsedCacheEvictorNotHang() throws Exception { public void exceptionDuringEvictionByLeastRecentlyUsedCacheEvictorNotHang() throws Exception {