mirror of
https://github.com/androidx/media.git
synced 2025-05-17 04:29:55 +08:00
Provide an option to skip file descriptor sync in CacheDataSink
This commit is contained in:
parent
18b1ec7a2f
commit
05d5096b3a
@ -93,7 +93,7 @@ public final class DownloaderConstructorHelper {
|
|||||||
} else {
|
} else {
|
||||||
DataSink cacheWriteDataSink = cacheWriteDataSinkFactory != null
|
DataSink cacheWriteDataSink = cacheWriteDataSinkFactory != null
|
||||||
? cacheWriteDataSinkFactory.createDataSink()
|
? cacheWriteDataSinkFactory.createDataSink()
|
||||||
: new CacheDataSink(cache, CacheDataSource.DEFAULT_MAX_CACHE_FILE_SIZE);
|
: new CacheDataSink(cache, CacheDataSource.DEFAULT_MAX_CACHE_FILE_SIZE, false);
|
||||||
DataSource upstream = upstreamDataSourceFactory.createDataSource();
|
DataSource upstream = upstreamDataSourceFactory.createDataSource();
|
||||||
upstream = priorityTaskManager == null ? upstream
|
upstream = priorityTaskManager == null ? upstream
|
||||||
: new PriorityDataSource(upstream, priorityTaskManager, C.PRIORITY_DOWNLOAD);
|
: new PriorityDataSource(upstream, priorityTaskManager, C.PRIORITY_DOWNLOAD);
|
||||||
|
@ -43,6 +43,7 @@ public final class CacheDataSink implements DataSink {
|
|||||||
private final Cache cache;
|
private final Cache cache;
|
||||||
private final long maxCacheFileSize;
|
private final long maxCacheFileSize;
|
||||||
private final int bufferSize;
|
private final int bufferSize;
|
||||||
|
private final boolean skipFDSync;
|
||||||
|
|
||||||
private DataSpec dataSpec;
|
private DataSpec dataSpec;
|
||||||
private File file;
|
private File file;
|
||||||
@ -70,9 +71,10 @@ public final class CacheDataSink implements DataSink {
|
|||||||
* @param maxCacheFileSize The maximum size of a cache file, in bytes. If the sink is opened for
|
* @param maxCacheFileSize The maximum size of a cache file, in bytes. If the sink is opened for
|
||||||
* a {@link DataSpec} whose size exceeds this value, then the data will be fragmented into
|
* a {@link DataSpec} whose size exceeds this value, then the data will be fragmented into
|
||||||
* multiple cache files.
|
* multiple cache files.
|
||||||
|
* @param skipFDSync Skip file descriptor sync when closing current output stream.
|
||||||
*/
|
*/
|
||||||
public CacheDataSink(Cache cache, long maxCacheFileSize) {
|
public CacheDataSink(Cache cache, long maxCacheFileSize, boolean skipFDSync) {
|
||||||
this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE);
|
this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE, skipFDSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,11 +84,13 @@ public final class CacheDataSink implements DataSink {
|
|||||||
* multiple cache files.
|
* multiple cache files.
|
||||||
* @param bufferSize The buffer size in bytes for writing to a cache file. A zero or negative
|
* @param bufferSize The buffer size in bytes for writing to a cache file. A zero or negative
|
||||||
* value disables buffering.
|
* value disables buffering.
|
||||||
|
* @param skipFDSync Skip file descriptor sync when closing current output stream.
|
||||||
*/
|
*/
|
||||||
public CacheDataSink(Cache cache, long maxCacheFileSize, int bufferSize) {
|
public CacheDataSink(Cache cache, long maxCacheFileSize, int bufferSize, boolean skipFDSync) {
|
||||||
this.cache = Assertions.checkNotNull(cache);
|
this.cache = Assertions.checkNotNull(cache);
|
||||||
this.maxCacheFileSize = maxCacheFileSize;
|
this.maxCacheFileSize = maxCacheFileSize;
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
|
this.skipFDSync = skipFDSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -170,7 +174,9 @@ public final class CacheDataSink implements DataSink {
|
|||||||
boolean success = false;
|
boolean success = false;
|
||||||
try {
|
try {
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
underlyingFileOutputStream.getFD().sync();
|
if (!skipFDSync) {
|
||||||
|
underlyingFileOutputStream.getFD().sync();
|
||||||
|
}
|
||||||
success = true;
|
success = true;
|
||||||
} finally {
|
} finally {
|
||||||
Util.closeQuietly(outputStream);
|
Util.closeQuietly(outputStream);
|
||||||
|
@ -44,7 +44,7 @@ public final class CacheDataSinkFactory implements DataSink.Factory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSink createDataSink() {
|
public DataSink createDataSink() {
|
||||||
return new CacheDataSink(cache, maxCacheFileSize, bufferSize);
|
return new CacheDataSink(cache, maxCacheFileSize, bufferSize, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ public final class CacheDataSource implements DataSource {
|
|||||||
*/
|
*/
|
||||||
public CacheDataSource(Cache cache, DataSource upstream, @Flags int flags,
|
public CacheDataSource(Cache cache, DataSource upstream, @Flags int flags,
|
||||||
long maxCacheFileSize) {
|
long maxCacheFileSize) {
|
||||||
this(cache, upstream, new FileDataSource(), new CacheDataSink(cache, maxCacheFileSize),
|
this(cache, upstream, new FileDataSource(), new CacheDataSink(cache, maxCacheFileSize, false),
|
||||||
flags, null);
|
flags, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,29 +79,49 @@ public final class CacheDataSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCacheAndRead() throws Exception {
|
public void testCacheAndRead() throws Exception {
|
||||||
assertCacheAndRead(false, false);
|
assertCacheAndRead(false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCacheAndReadUnboundedRequest() throws Exception {
|
public void testCacheAndReadUnboundedRequest() throws Exception {
|
||||||
assertCacheAndRead(true, false);
|
assertCacheAndRead(true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCacheAndReadUnknownLength() throws Exception {
|
public void testCacheAndReadUnknownLength() throws Exception {
|
||||||
assertCacheAndRead(false, true);
|
assertCacheAndRead(false, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCacheAndReadUnboundedRequestUnknownLength() throws Exception {
|
public void testCacheAndReadUnboundedRequestUnknownLength() throws Exception {
|
||||||
assertCacheAndRead(true, true);
|
assertCacheAndRead(true, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheAndReadSkipFDSync() throws Exception {
|
||||||
|
assertCacheAndRead(false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheAndReadUnboundedRequestSkipFDSync() throws Exception {
|
||||||
|
assertCacheAndRead(true, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheAndReadUnknownLengthSkipFDSync() throws Exception {
|
||||||
|
assertCacheAndRead(false, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheAndReadUnboundedRequestUnknownLengthSkipFDSync() throws Exception {
|
||||||
|
assertCacheAndRead(true, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnsatisfiableRange() throws Exception {
|
public void testUnsatisfiableRange() throws Exception {
|
||||||
// Bounded request but the content length is unknown. This forces all data to be cached but not
|
// Bounded request but the content length is unknown. This forces all data to be cached but not
|
||||||
// the length
|
// the length
|
||||||
assertCacheAndRead(false, true);
|
assertCacheAndRead(false, true, false);
|
||||||
|
|
||||||
// Now do an unbounded request. This will read all of the data from cache and then try to read
|
// Now do an unbounded request. This will read all of the data from cache and then try to read
|
||||||
// more from upstream which will cause to a 416 so CDS will store the length.
|
// more from upstream which will cause to a 416 so CDS will store the length.
|
||||||
@ -347,10 +367,11 @@ public final class CacheDataSourceTest {
|
|||||||
cacheDataSource.close();
|
cacheDataSource.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength)
|
private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength,
|
||||||
|
boolean skipFDSync)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// Read all data from upstream and write to cache
|
// Read all data from upstream and write to cache
|
||||||
CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength);
|
CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength, skipFDSync);
|
||||||
assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength);
|
assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength);
|
||||||
|
|
||||||
// Just read from cache
|
// Just read from cache
|
||||||
@ -391,14 +412,19 @@ public final class CacheDataSourceTest {
|
|||||||
|
|
||||||
private CacheDataSource createCacheDataSource(boolean setReadException,
|
private CacheDataSource createCacheDataSource(boolean setReadException,
|
||||||
boolean simulateUnknownLength) {
|
boolean simulateUnknownLength) {
|
||||||
return createCacheDataSource(setReadException, simulateUnknownLength,
|
return createCacheDataSource(setReadException, simulateUnknownLength, false);
|
||||||
CacheDataSource.FLAG_BLOCK_ON_CACHE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CacheDataSource createCacheDataSource(boolean setReadException,
|
private CacheDataSource createCacheDataSource(boolean setReadException,
|
||||||
boolean simulateUnknownLength, @CacheDataSource.Flags int flags) {
|
boolean simulateUnknownLength, boolean skipFDSync) {
|
||||||
|
return createCacheDataSource(setReadException, simulateUnknownLength,
|
||||||
|
CacheDataSource.FLAG_BLOCK_ON_CACHE, skipFDSync);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CacheDataSource createCacheDataSource(boolean setReadException,
|
||||||
|
boolean simulateUnknownLength, @CacheDataSource.Flags int flags, boolean skipFDSync) {
|
||||||
return createCacheDataSource(setReadException, simulateUnknownLength, flags,
|
return createCacheDataSource(setReadException, simulateUnknownLength, flags,
|
||||||
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE));
|
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE, skipFDSync));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CacheDataSource createCacheDataSource(boolean setReadException,
|
private CacheDataSource createCacheDataSource(boolean setReadException,
|
||||||
|
@ -166,7 +166,7 @@ public final class CacheDataSourceTest2 {
|
|||||||
? new AesCipherDataSource(Util.getUtf8Bytes(secretKey), file) : file;
|
? new AesCipherDataSource(Util.getUtf8Bytes(secretKey), file) : file;
|
||||||
|
|
||||||
// Sink and cipher
|
// Sink and cipher
|
||||||
CacheDataSink cacheSink = new CacheDataSink(cache, EXO_CACHE_MAX_FILESIZE);
|
CacheDataSink cacheSink = new CacheDataSink(cache, EXO_CACHE_MAX_FILESIZE, false);
|
||||||
byte[] scratch = new byte[3897];
|
byte[] scratch = new byte[3897];
|
||||||
DataSink cacheWriteDataSink = useAesEncryption
|
DataSink cacheWriteDataSink = useAesEncryption
|
||||||
? new AesCipherDataSink(Util.getUtf8Bytes(secretKey), cacheSink, scratch) : cacheSink;
|
? new AesCipherDataSink(Util.getUtf8Bytes(secretKey), cacheSink, scratch) : cacheSink;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user