Commit 41026495 by olly Committed by Oliver Woodman

Don't open DataSink if resolved length is 0

- It's wasted effort
- DataSpec reconstruction fails because creating a DataSpec with 0
  length isn't allowed.
- Also better document DataSink open/close, to be like DataSource.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=194778132
parent d1fdc518
...@@ -37,6 +37,9 @@ public interface DataSink { ...@@ -37,6 +37,9 @@ public interface DataSink {
/** /**
* Opens the sink to consume the specified data. * Opens the sink to consume the specified data.
* *
* <p>Note: If an {@link IOException} is thrown, callers must still call {@link #close()} to
* ensure that any partial effects of the invocation are cleaned up.
*
* @param dataSpec Defines the data to be consumed. * @param dataSpec Defines the data to be consumed.
* @throws IOException If an error occurs opening the sink. * @throws IOException If an error occurs opening the sink.
*/ */
...@@ -55,8 +58,10 @@ public interface DataSink { ...@@ -55,8 +58,10 @@ public interface DataSink {
/** /**
* Closes the sink. * Closes the sink.
* *
* <p>Note: This method must be called even if the corresponding call to {@link #open(DataSpec)}
* threw an {@link IOException}. See {@link #open(DataSpec)} for more details.
*
* @throws IOException If an error occurs closing the sink. * @throws IOException If an error occurs closing the sink.
*/ */
void close() throws IOException; void close() throws IOException;
} }
...@@ -28,6 +28,9 @@ public final class TeeDataSource implements DataSource { ...@@ -28,6 +28,9 @@ public final class TeeDataSource implements DataSource {
private final DataSource upstream; private final DataSource upstream;
private final DataSink dataSink; private final DataSink dataSink;
private boolean dataSinkNeedsClosing;
private long bytesRemaining;
/** /**
* @param upstream The upstream {@link DataSource}. * @param upstream The upstream {@link DataSource}.
* @param dataSink The {@link DataSink} into which data is written. * @param dataSink The {@link DataSink} into which data is written.
...@@ -39,24 +42,40 @@ public final class TeeDataSource implements DataSource { ...@@ -39,24 +42,40 @@ public final class TeeDataSource implements DataSource {
@Override @Override
public long open(DataSpec dataSpec) throws IOException { public long open(DataSpec dataSpec) throws IOException {
long dataLength = upstream.open(dataSpec); bytesRemaining = upstream.open(dataSpec);
if (dataSpec.length == C.LENGTH_UNSET && dataLength != C.LENGTH_UNSET) { if (bytesRemaining == 0) {
return 0;
}
if (dataSpec.length == C.LENGTH_UNSET && bytesRemaining != C.LENGTH_UNSET) {
// Reconstruct dataSpec in order to provide the resolved length to the sink. // Reconstruct dataSpec in order to provide the resolved length to the sink.
dataSpec = new DataSpec(dataSpec.uri, dataSpec.absoluteStreamPosition, dataSpec.position, dataSpec =
dataLength, dataSpec.key, dataSpec.flags); new DataSpec(
dataSpec.uri,
dataSpec.absoluteStreamPosition,
dataSpec.position,
bytesRemaining,
dataSpec.key,
dataSpec.flags);
} }
dataSinkNeedsClosing = true;
dataSink.open(dataSpec); dataSink.open(dataSpec);
return dataLength; return bytesRemaining;
} }
@Override @Override
public int read(byte[] buffer, int offset, int max) throws IOException { public int read(byte[] buffer, int offset, int max) throws IOException {
int num = upstream.read(buffer, offset, max); if (bytesRemaining == 0) {
if (num > 0) { return C.RESULT_END_OF_INPUT;
// TODO: Consider continuing even if disk writes fail. }
dataSink.write(buffer, offset, num); int bytesRead = upstream.read(buffer, offset, max);
if (bytesRead > 0) {
// TODO: Consider continuing even if writes to the sink fail.
dataSink.write(buffer, offset, bytesRead);
if (bytesRemaining != C.LENGTH_UNSET) {
bytesRemaining -= bytesRead;
}
} }
return num; return bytesRead;
} }
@Override @Override
...@@ -69,7 +88,10 @@ public final class TeeDataSource implements DataSource { ...@@ -69,7 +88,10 @@ public final class TeeDataSource implements DataSource {
try { try {
upstream.close(); upstream.close();
} finally { } finally {
dataSink.close(); if (dataSinkNeedsClosing) {
dataSinkNeedsClosing = false;
dataSink.close();
}
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment