Skip to content

Commit 82b0291

Browse files
author
Gary Gregory
committed
[IO-510] Add and adapt ReadAheadInputStream and
BufferedFileChannelInputStream from Apache Spark. Only shutdown the executor service if we own it.
1 parent 2f1e354 commit 82b0291

1 file changed

Lines changed: 32 additions & 13 deletions

File tree

src/main/java/org/apache/commons/io/input/ReadAheadInputStream.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.InputStream;
2020
import java.io.InterruptedIOException;
2121
import java.nio.ByteBuffer;
22+
import java.util.Objects;
2223
import java.util.concurrent.ExecutorService;
2324
import java.util.concurrent.Executors;
2425
import java.util.concurrent.TimeUnit;
@@ -105,6 +106,8 @@ private static Thread newThread(Runnable r) {
105106

106107
private final ExecutorService executorService;
107108

109+
private final boolean shutdownExecutorService;
110+
108111
private final Condition asyncReadComplete = stateChangeLock.newCondition();
109112

110113
/**
@@ -114,7 +117,7 @@ private static Thread newThread(Runnable r) {
114117
* @param bufferSizeInBytes The buffer size.
115118
*/
116119
public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes) {
117-
this(inputStream, bufferSizeInBytes, newExecutorService());
120+
this(inputStream, bufferSizeInBytes, newExecutorService(), true);
118121
}
119122

120123
/**
@@ -126,14 +129,28 @@ public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeI
126129
*/
127130
public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes,
128131
final ExecutorService executorService) {
132+
this(inputStream, bufferSizeInBytes, executorService, false);
133+
}
134+
135+
/**
136+
* Creates an instance with the specified buffer size and read-ahead threshold
137+
*
138+
* @param inputStream The underlying input stream.
139+
* @param bufferSizeInBytes The buffer size.
140+
* @param executorService An executor service for the read-ahead thread.
141+
* @param shutdownExecutorService Whether or not to shutdown the given ExecutorService on close.
142+
*/
143+
public ReadAheadInputStream(final InputStream inputStream, final int bufferSizeInBytes,
144+
final ExecutorService executorService, final boolean shutdownExecutorService) {
129145
if (bufferSizeInBytes <= 0) {
130146
throw new IllegalArgumentException(
131147
"bufferSizeInBytes should be greater than 0, but the value is " + bufferSizeInBytes);
132148
}
133-
this.executorService = executorService;
149+
this.executorService = Objects.requireNonNull(executorService, "executorService");
150+
this.underlyingInputStream = Objects.requireNonNull(inputStream, "inputStream");
151+
this.shutdownExecutorService = shutdownExecutorService;
134152
this.activeBuffer = ByteBuffer.allocate(bufferSizeInBytes);
135153
this.readAheadBuffer = ByteBuffer.allocate(bufferSizeInBytes);
136-
this.underlyingInputStream = inputStream;
137154
this.activeBuffer.flip();
138155
this.readAheadBuffer.flip();
139156
}
@@ -177,16 +194,18 @@ public void close() throws IOException {
177194
stateChangeLock.unlock();
178195
}
179196

180-
try {
181-
executorService.shutdownNow();
182-
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
183-
} catch (final InterruptedException e) {
184-
final InterruptedIOException iio = new InterruptedIOException(e.getMessage());
185-
iio.initCause(e);
186-
throw iio;
187-
} finally {
188-
if (isSafeToCloseUnderlyingInputStream) {
189-
underlyingInputStream.close();
197+
if (shutdownExecutorService) {
198+
try {
199+
executorService.shutdownNow();
200+
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
201+
} catch (final InterruptedException e) {
202+
final InterruptedIOException iio = new InterruptedIOException(e.getMessage());
203+
iio.initCause(e);
204+
throw iio;
205+
} finally {
206+
if (isSafeToCloseUnderlyingInputStream) {
207+
underlyingInputStream.close();
208+
}
190209
}
191210
}
192211
}

0 commit comments

Comments
 (0)