mirror of
https://github.com/samsonjs/media.git
synced 2026-04-10 12:05:47 +00:00
Add Cache.getCachedBytes() which returns the length of the cached or not data block length
This method can be used to determine not cached parts of a content. The 'length' parameter allows quicker responses without going through all adjacent spans. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=149005688
This commit is contained in:
parent
247da48e9d
commit
e40bba2852
4 changed files with 89 additions and 41 deletions
|
|
@ -192,6 +192,41 @@ public class SimpleCacheTest extends InstrumentationTestCase {
|
|||
assertEquals(0, cacheDir.listFiles().length);
|
||||
}
|
||||
|
||||
|
||||
public void testGetCachedBytes() throws Exception {
|
||||
SimpleCache simpleCache = getSimpleCache();
|
||||
CacheSpan cacheSpan = simpleCache.startReadWrite(KEY_1, 0);
|
||||
|
||||
// No cached bytes, returns -'length'
|
||||
assertEquals(-100, simpleCache.getCachedBytes(KEY_1, 0, 100));
|
||||
|
||||
// Position value doesn't affect the return value
|
||||
assertEquals(-100, simpleCache.getCachedBytes(KEY_1, 20, 100));
|
||||
|
||||
addCache(simpleCache, KEY_1, 0, 15);
|
||||
|
||||
// Returns the length of a single span
|
||||
assertEquals(15, simpleCache.getCachedBytes(KEY_1, 0, 100));
|
||||
|
||||
// Value is capped by the 'length'
|
||||
assertEquals(10, simpleCache.getCachedBytes(KEY_1, 0, 10));
|
||||
|
||||
addCache(simpleCache, KEY_1, 15, 35);
|
||||
|
||||
// Returns the length of two adjacent spans
|
||||
assertEquals(50, simpleCache.getCachedBytes(KEY_1, 0, 100));
|
||||
|
||||
addCache(simpleCache, KEY_1, 60, 10);
|
||||
|
||||
// Not adjacent span doesn't affect return value
|
||||
assertEquals(50, simpleCache.getCachedBytes(KEY_1, 0, 100));
|
||||
|
||||
// Returns length of hole up to the next cached span
|
||||
assertEquals(-5, simpleCache.getCachedBytes(KEY_1, 55, 100));
|
||||
|
||||
simpleCache.releaseHoleSpan(cacheSpan);
|
||||
}
|
||||
|
||||
private SimpleCache getSimpleCache() {
|
||||
return new SimpleCache(cacheDir, new NoOpCacheEvictor());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,6 +198,18 @@ public interface Cache {
|
|||
*/
|
||||
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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
long getCachedBytes(String key, long position, long length);
|
||||
|
||||
/**
|
||||
* Sets the content length for the given key.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -106,43 +106,49 @@ import java.util.TreeSet;
|
|||
* which defines the maximum extents of the hole in the cache.
|
||||
*/
|
||||
public SimpleCacheSpan getSpan(long position) {
|
||||
SimpleCacheSpan span = getSpanInternal(position);
|
||||
if (!span.isCached) {
|
||||
SimpleCacheSpan ceilEntry = cachedSpans.ceiling(span);
|
||||
return ceilEntry == null ? SimpleCacheSpan.createOpenHole(key, position)
|
||||
: SimpleCacheSpan.createClosedHole(key, position, ceilEntry.position - position);
|
||||
SimpleCacheSpan lookupSpan = SimpleCacheSpan.createLookup(key, position);
|
||||
SimpleCacheSpan floorSpan = cachedSpans.floor(lookupSpan);
|
||||
if (floorSpan != null && floorSpan.position + floorSpan.length > position) {
|
||||
return floorSpan;
|
||||
}
|
||||
return span;
|
||||
SimpleCacheSpan ceilSpan = cachedSpans.ceiling(lookupSpan);
|
||||
return ceilSpan == null ? SimpleCacheSpan.createOpenHole(key, position)
|
||||
: SimpleCacheSpan.createClosedHole(key, position, ceilSpan.position - position);
|
||||
}
|
||||
|
||||
/** Queries if a range is entirely available in the cache. */
|
||||
public boolean isCached(long position, long length) {
|
||||
SimpleCacheSpan floorSpan = getSpanInternal(position);
|
||||
if (!floorSpan.isCached) {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public long getCachedBytes(long position, long length) {
|
||||
SimpleCacheSpan span = getSpan(position);
|
||||
if (span.isHoleSpan()) {
|
||||
// We don't have a span covering the start of the queried region.
|
||||
return false;
|
||||
return -Math.min(span.isOpenEnded() ? Long.MAX_VALUE : span.length, length);
|
||||
}
|
||||
long queryEndPosition = position + length;
|
||||
long currentEndPosition = floorSpan.position + floorSpan.length;
|
||||
if (currentEndPosition >= queryEndPosition) {
|
||||
// floorSpan covers the queried region.
|
||||
return true;
|
||||
}
|
||||
for (SimpleCacheSpan next : cachedSpans.tailSet(floorSpan, false)) {
|
||||
if (next.position > currentEndPosition) {
|
||||
// There's a hole in the cache within the queried region.
|
||||
return false;
|
||||
}
|
||||
// We expect currentEndPosition to always equal (next.position + next.length), but
|
||||
// perform a max check anyway to guard against the existence of overlapping spans.
|
||||
currentEndPosition = Math.max(currentEndPosition, next.position + next.length);
|
||||
if (currentEndPosition >= queryEndPosition) {
|
||||
// We've found spans covering the queried region.
|
||||
return true;
|
||||
long currentEndPosition = span.position + span.length;
|
||||
if (currentEndPosition < queryEndPosition) {
|
||||
for (SimpleCacheSpan next : cachedSpans.tailSet(span, false)) {
|
||||
if (next.position > currentEndPosition) {
|
||||
// There's a hole in the cache within the queried region.
|
||||
break;
|
||||
}
|
||||
// We expect currentEndPosition to always equal (next.position + next.length), but
|
||||
// perform a max check anyway to guard against the existence of overlapping spans.
|
||||
currentEndPosition = Math.max(currentEndPosition, next.position + next.length);
|
||||
if (currentEndPosition >= queryEndPosition) {
|
||||
// We've found spans covering the queried region.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We ran out of spans before covering the queried region.
|
||||
return false;
|
||||
return Math.min(currentEndPosition - position, length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -190,15 +196,4 @@ import java.util.TreeSet;
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the span containing the position. If there isn't one, it returns the lookup span it
|
||||
* used for searching.
|
||||
*/
|
||||
private SimpleCacheSpan getSpanInternal(long position) {
|
||||
SimpleCacheSpan lookupSpan = SimpleCacheSpan.createLookup(key, position);
|
||||
SimpleCacheSpan floorSpan = cachedSpans.floor(lookupSpan);
|
||||
return floorSpan == null || floorSpan.position + floorSpan.length <= position ? lookupSpan
|
||||
: floorSpan;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,7 +354,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.isCached(position, length);
|
||||
return cachedContent != null && cachedContent.getCachedBytes(position, length) >= length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized long getCachedBytes(String key, long position, long length) {
|
||||
CachedContent cachedContent = index.get(key);
|
||||
return cachedContent != null ? cachedContent.getCachedBytes(position, length) : -length;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in a new issue