Provide an option to skip file descriptor sync in CacheDataSink

This commit is contained in:
Jianyong Xiao 2018-03-19 01:34:35 -07:00
parent 18b1ec7a2f
commit 05d5096b3a
6 changed files with 51 additions and 19 deletions

View File

@ -93,7 +93,7 @@ public final class DownloaderConstructorHelper {
} else {
DataSink cacheWriteDataSink = cacheWriteDataSinkFactory != null
? 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();
upstream = priorityTaskManager == null ? upstream
: new PriorityDataSource(upstream, priorityTaskManager, C.PRIORITY_DOWNLOAD);

View File

@ -43,6 +43,7 @@ public final class CacheDataSink implements DataSink {
private final Cache cache;
private final long maxCacheFileSize;
private final int bufferSize;
private final boolean skipFDSync;
private DataSpec dataSpec;
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
* a {@link DataSpec} whose size exceeds this value, then the data will be fragmented into
* multiple cache files.
* @param skipFDSync Skip file descriptor sync when closing current output stream.
*/
public CacheDataSink(Cache cache, long maxCacheFileSize) {
this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE);
public CacheDataSink(Cache cache, long maxCacheFileSize, boolean skipFDSync) {
this(cache, maxCacheFileSize, DEFAULT_BUFFER_SIZE, skipFDSync);
}
/**
@ -82,11 +84,13 @@ public final class CacheDataSink implements DataSink {
* multiple cache files.
* @param bufferSize The buffer size in bytes for writing to a cache file. A zero or negative
* 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.maxCacheFileSize = maxCacheFileSize;
this.bufferSize = bufferSize;
this.skipFDSync = skipFDSync;
}
@Override
@ -170,7 +174,9 @@ public final class CacheDataSink implements DataSink {
boolean success = false;
try {
outputStream.flush();
underlyingFileOutputStream.getFD().sync();
if (!skipFDSync) {
underlyingFileOutputStream.getFD().sync();
}
success = true;
} finally {
Util.closeQuietly(outputStream);

View File

@ -44,7 +44,7 @@ public final class CacheDataSinkFactory implements DataSink.Factory {
@Override
public DataSink createDataSink() {
return new CacheDataSink(cache, maxCacheFileSize, bufferSize);
return new CacheDataSink(cache, maxCacheFileSize, bufferSize, false);
}
}

View File

@ -157,7 +157,7 @@ public final class CacheDataSource implements DataSource {
*/
public CacheDataSource(Cache cache, DataSource upstream, @Flags int flags,
long maxCacheFileSize) {
this(cache, upstream, new FileDataSource(), new CacheDataSink(cache, maxCacheFileSize),
this(cache, upstream, new FileDataSource(), new CacheDataSink(cache, maxCacheFileSize, false),
flags, null);
}

View File

@ -79,29 +79,49 @@ public final class CacheDataSourceTest {
@Test
public void testCacheAndRead() throws Exception {
assertCacheAndRead(false, false);
assertCacheAndRead(false, false, false);
}
@Test
public void testCacheAndReadUnboundedRequest() throws Exception {
assertCacheAndRead(true, false);
assertCacheAndRead(true, false, false);
}
@Test
public void testCacheAndReadUnknownLength() throws Exception {
assertCacheAndRead(false, true);
assertCacheAndRead(false, true, false);
}
@Test
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
public void testUnsatisfiableRange() throws Exception {
// Bounded request but the content length is unknown. This forces all data to be cached but not
// 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
// 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();
}
private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength)
private void assertCacheAndRead(boolean unboundedRequest, boolean simulateUnknownLength,
boolean skipFDSync)
throws IOException {
// Read all data from upstream and write to cache
CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength);
CacheDataSource cacheDataSource = createCacheDataSource(false, simulateUnknownLength, skipFDSync);
assertReadDataContentLength(cacheDataSource, unboundedRequest, simulateUnknownLength);
// Just read from cache
@ -391,14 +412,19 @@ public final class CacheDataSourceTest {
private CacheDataSource createCacheDataSource(boolean setReadException,
boolean simulateUnknownLength) {
return createCacheDataSource(setReadException, simulateUnknownLength,
CacheDataSource.FLAG_BLOCK_ON_CACHE);
return createCacheDataSource(setReadException, simulateUnknownLength, false);
}
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,
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE));
new CacheDataSink(cache, MAX_CACHE_FILE_SIZE, skipFDSync));
}
private CacheDataSource createCacheDataSource(boolean setReadException,

View File

@ -166,7 +166,7 @@ public final class CacheDataSourceTest2 {
? new AesCipherDataSource(Util.getUtf8Bytes(secretKey), file) : file;
// 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];
DataSink cacheWriteDataSink = useAesEncryption
? new AesCipherDataSink(Util.getUtf8Bytes(secretKey), cacheSink, scratch) : cacheSink;