mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Shard SimpleCache files into 10 sub-directories
Issue: #4253 PiperOrigin-RevId: 232659869
This commit is contained in:
parent
2169b9417f
commit
3845304e58
3 changed files with 39 additions and 7 deletions
|
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.NavigableSet;
|
import java.util.NavigableSet;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
|
@ -36,6 +37,14 @@ import java.util.TreeSet;
|
||||||
public final class SimpleCache implements Cache {
|
public final class SimpleCache implements Cache {
|
||||||
|
|
||||||
private static final String TAG = "SimpleCache";
|
private static final String TAG = "SimpleCache";
|
||||||
|
/**
|
||||||
|
* Cache files are distributed between a number of subdirectories. This helps to avoid poor
|
||||||
|
* performance in cases where the performance of the underlying file system (e.g. FAT32) scales
|
||||||
|
* badly with the number of files per directory. See
|
||||||
|
* https://github.com/google/ExoPlayer/issues/4253.
|
||||||
|
*/
|
||||||
|
private static final int SUBDIRECTORY_COUNT = 10;
|
||||||
|
|
||||||
private static final HashSet<File> lockedCacheDirs = new HashSet<>();
|
private static final HashSet<File> lockedCacheDirs = new HashSet<>();
|
||||||
|
|
||||||
private static boolean cacheFolderLockingDisabled;
|
private static boolean cacheFolderLockingDisabled;
|
||||||
|
|
@ -44,6 +53,7 @@ public final class SimpleCache implements Cache {
|
||||||
private final CacheEvictor evictor;
|
private final CacheEvictor evictor;
|
||||||
private final CachedContentIndex index;
|
private final CachedContentIndex index;
|
||||||
private final HashMap<String, ArrayList<Listener>> listeners;
|
private final HashMap<String, ArrayList<Listener>> listeners;
|
||||||
|
private final Random random;
|
||||||
|
|
||||||
private long totalSpace;
|
private long totalSpace;
|
||||||
private boolean released;
|
private boolean released;
|
||||||
|
|
@ -128,7 +138,8 @@ public final class SimpleCache implements Cache {
|
||||||
this.cacheDir = cacheDir;
|
this.cacheDir = cacheDir;
|
||||||
this.evictor = evictor;
|
this.evictor = evictor;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.listeners = new HashMap<>();
|
listeners = new HashMap<>();
|
||||||
|
random = new Random();
|
||||||
|
|
||||||
// Start cache initialization.
|
// Start cache initialization.
|
||||||
final ConditionVariable conditionVariable = new ConditionVariable();
|
final ConditionVariable conditionVariable = new ConditionVariable();
|
||||||
|
|
@ -271,8 +282,13 @@ public final class SimpleCache implements Cache {
|
||||||
removeStaleSpans();
|
removeStaleSpans();
|
||||||
}
|
}
|
||||||
evictor.onStartFile(this, key, position, length);
|
evictor.onStartFile(this, key, position, length);
|
||||||
return SimpleCacheSpan.getCacheFile(
|
// Randomly distribute files into subdirectories with a uniform distribution.
|
||||||
cacheDir, cachedContent.id, position, System.currentTimeMillis());
|
File fileDir = new File(cacheDir, Integer.toString(random.nextInt(SUBDIRECTORY_COUNT)));
|
||||||
|
if (!fileDir.exists()) {
|
||||||
|
fileDir.mkdir();
|
||||||
|
}
|
||||||
|
long lastAccessTimestamp = System.currentTimeMillis();
|
||||||
|
return SimpleCacheSpan.getCacheFile(fileDir, cachedContent.id, position, lastAccessTimestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ import java.util.regex.Pattern;
|
||||||
/** This class stores span metadata in filename. */
|
/** This class stores span metadata in filename. */
|
||||||
/* package */ final class SimpleCacheSpan extends CacheSpan {
|
/* package */ final class SimpleCacheSpan extends CacheSpan {
|
||||||
|
|
||||||
private static final String SUFFIX = ".v3.exo";
|
/* package */ static final String COMMON_SUFFIX = ".exo";
|
||||||
|
|
||||||
|
private static final String SUFFIX = ".v3" + COMMON_SUFFIX;
|
||||||
private static final Pattern CACHE_FILE_PATTERN_V1 = Pattern.compile(
|
private static final Pattern CACHE_FILE_PATTERN_V1 = Pattern.compile(
|
||||||
"^(.+)\\.(\\d+)\\.(\\d+)\\.v1\\.exo$", Pattern.DOTALL);
|
"^(.+)\\.(\\d+)\\.(\\d+)\\.v1\\.exo$", Pattern.DOTALL);
|
||||||
private static final Pattern CACHE_FILE_PATTERN_V2 = Pattern.compile(
|
private static final Pattern CACHE_FILE_PATTERN_V2 = Pattern.compile(
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ public class SimpleCacheTest {
|
||||||
NavigableSet<CacheSpan> cachedSpans = simpleCache.getCachedSpans(KEY_1);
|
NavigableSet<CacheSpan> cachedSpans = simpleCache.getCachedSpans(KEY_1);
|
||||||
assertThat(cachedSpans.isEmpty()).isTrue();
|
assertThat(cachedSpans.isEmpty()).isTrue();
|
||||||
assertThat(simpleCache.getCacheSpace()).isEqualTo(0);
|
assertThat(simpleCache.getCacheSpace()).isEqualTo(0);
|
||||||
assertThat(cacheDir.listFiles()).hasLength(0);
|
assertNoCacheFiles(cacheDir);
|
||||||
|
|
||||||
addCache(simpleCache, KEY_1, 0, 15);
|
addCache(simpleCache, KEY_1, 0, 15);
|
||||||
|
|
||||||
|
|
@ -233,7 +233,7 @@ public class SimpleCacheTest {
|
||||||
|
|
||||||
// Cache should be cleared
|
// Cache should be cleared
|
||||||
assertThat(simpleCache.getKeys()).isEmpty();
|
assertThat(simpleCache.getKeys()).isEmpty();
|
||||||
assertThat(cacheDir.listFiles()).hasLength(0);
|
assertNoCacheFiles(cacheDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -252,7 +252,7 @@ public class SimpleCacheTest {
|
||||||
|
|
||||||
// Cache should be cleared
|
// Cache should be cleared
|
||||||
assertThat(simpleCache.getKeys()).isEmpty();
|
assertThat(simpleCache.getKeys()).isEmpty();
|
||||||
assertThat(cacheDir.listFiles()).hasLength(0);
|
assertNoCacheFiles(cacheDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -391,6 +391,20 @@ public class SimpleCacheTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertNoCacheFiles(File dir) {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
assertNoCacheFiles(file);
|
||||||
|
} else {
|
||||||
|
assertThat(file.getName().endsWith(SimpleCacheSpan.COMMON_SUFFIX)).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] generateData(String key, int position, int length) {
|
private static byte[] generateData(String key, int position, int length) {
|
||||||
byte[] bytes = new byte[length];
|
byte[] bytes = new byte[length];
|
||||||
new Random((long) (key.hashCode() ^ position)).nextBytes(bytes);
|
new Random((long) (key.hashCode() ^ position)).nextBytes(bytes);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue