Cleanup stream usage WRT filters
As it is right now some streams leak out of the filter construct. This change clarifies responsibilities and fixes stream leaks Change-Id: Ib9717d43a701a06a502434d64214d13a392de5ab Signed-off-by: Markus Duft <markus.duft@ssi-schaefer.com> Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
parent
d3ed64bcd4
commit
a3f8edbf6a
|
@ -167,6 +167,7 @@ public int run() throws IOException {
|
||||||
}
|
}
|
||||||
LfsPointer lfsPointer = new LfsPointer(loid, size);
|
LfsPointer lfsPointer = new LfsPointer(loid, size);
|
||||||
lfsPointer.encode(out);
|
lfsPointer.encode(out);
|
||||||
|
in.close();
|
||||||
out.close();
|
out.close();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -174,6 +175,7 @@ public int run() throws IOException {
|
||||||
if (aOut != null) {
|
if (aOut != null) {
|
||||||
aOut.abort();
|
aOut.abort();
|
||||||
}
|
}
|
||||||
|
in.close();
|
||||||
out.close();
|
out.close();
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,23 +116,29 @@ static void register() {
|
||||||
* @param db
|
* @param db
|
||||||
* a {@link org.eclipse.jgit.lib.Repository} object.
|
* a {@link org.eclipse.jgit.lib.Repository} object.
|
||||||
* @param in
|
* @param in
|
||||||
* a {@link java.io.InputStream} object.
|
* a {@link java.io.InputStream} object. The stream is closed in
|
||||||
|
* any case.
|
||||||
* @param out
|
* @param out
|
||||||
* a {@link java.io.OutputStream} object.
|
* a {@link java.io.OutputStream} object.
|
||||||
* @throws java.io.IOException
|
* @throws java.io.IOException
|
||||||
|
* in case of an error
|
||||||
*/
|
*/
|
||||||
public SmudgeFilter(Repository db, InputStream in, OutputStream out)
|
public SmudgeFilter(Repository db, InputStream in, OutputStream out)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
super(in, out);
|
super(in, out);
|
||||||
Lfs lfs = new Lfs(db);
|
try {
|
||||||
LfsPointer res = LfsPointer.parseLfsPointer(in);
|
Lfs lfs = new Lfs(db);
|
||||||
if (res != null) {
|
LfsPointer res = LfsPointer.parseLfsPointer(in);
|
||||||
AnyLongObjectId oid = res.getOid();
|
if (res != null) {
|
||||||
Path mediaFile = lfs.getMediaFile(oid);
|
AnyLongObjectId oid = res.getOid();
|
||||||
if (!Files.exists(mediaFile)) {
|
Path mediaFile = lfs.getMediaFile(oid);
|
||||||
downloadLfsResource(lfs, db, res);
|
if (!Files.exists(mediaFile)) {
|
||||||
|
downloadLfsResource(lfs, db, res);
|
||||||
|
}
|
||||||
|
this.in = Files.newInputStream(mediaFile);
|
||||||
}
|
}
|
||||||
this.in = Files.newInputStream(mediaFile);
|
} finally {
|
||||||
|
in.close(); // make sure the swapped stream is closed properly.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +153,7 @@ public SmudgeFilter(Repository db, InputStream in, OutputStream out)
|
||||||
* the objects to download
|
* the objects to download
|
||||||
* @return the paths of all mediafiles which have been downloaded
|
* @return the paths of all mediafiles which have been downloaded
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
|
* @since 4.11
|
||||||
*/
|
*/
|
||||||
public static Collection<Path> downloadLfsResource(Lfs lfs, Repository db,
|
public static Collection<Path> downloadLfsResource(Lfs lfs, Repository db,
|
||||||
LfsPointer... res) throws IOException {
|
LfsPointer... res) throws IOException {
|
||||||
|
@ -228,33 +235,39 @@ public static Collection<Path> downloadLfsResource(Lfs lfs, Repository db,
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public int run() throws IOException {
|
public int run() throws IOException {
|
||||||
int totalRead = 0;
|
try {
|
||||||
int length = 0;
|
int totalRead = 0;
|
||||||
if (in != null) {
|
int length = 0;
|
||||||
byte[] buf = new byte[8192];
|
if (in != null) {
|
||||||
while ((length = in.read(buf)) != -1) {
|
byte[] buf = new byte[8192];
|
||||||
out.write(buf, 0, length);
|
while ((length = in.read(buf)) != -1) {
|
||||||
totalRead += length;
|
out.write(buf, 0, length);
|
||||||
|
totalRead += length;
|
||||||
|
|
||||||
// when threshold reached, loop back to the caller. otherwise we
|
// when threshold reached, loop back to the caller.
|
||||||
// could only support files up to 2GB (int return type)
|
// otherwise we could only support files up to 2GB (int
|
||||||
// properly. we will be called again as long as we don't return
|
// return type) properly. we will be called again as long as
|
||||||
// -1 here.
|
// we don't return -1 here.
|
||||||
if (totalRead >= MAX_COPY_BYTES) {
|
if (totalRead >= MAX_COPY_BYTES) {
|
||||||
// leave streams open - we need them in the next call.
|
// leave streams open - we need them in the next call.
|
||||||
return totalRead;
|
return totalRead;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (totalRead == 0 && length == -1) {
|
if (totalRead == 0 && length == -1) {
|
||||||
// we're totally done :)
|
// we're totally done :) cleanup all streams
|
||||||
in.close();
|
in.close();
|
||||||
|
out.close();
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalRead;
|
||||||
|
} catch (IOException e) {
|
||||||
|
in.close(); // clean up - we swapped this stream.
|
||||||
out.close();
|
out.close();
|
||||||
return length;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
return totalRead;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,9 @@ public abstract class FilterCommand {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for FilterCommand
|
* Constructor for FilterCommand
|
||||||
|
* <p>
|
||||||
|
* FilterCommand implementors are required to manage the in and out streams
|
||||||
|
* (close on success and/or exception).
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in
|
||||||
* The {@link java.io.InputStream} this command should read from
|
* The {@link java.io.InputStream} this command should read from
|
||||||
|
@ -84,6 +87,9 @@ public FilterCommand(InputStream in, OutputStream out) {
|
||||||
* number of bytes it read from {@link #in}. It should be called in a loop
|
* number of bytes it read from {@link #in}. It should be called in a loop
|
||||||
* until it returns -1 signaling that the {@link java.io.InputStream} is
|
* until it returns -1 signaling that the {@link java.io.InputStream} is
|
||||||
* completely processed.
|
* completely processed.
|
||||||
|
* <p>
|
||||||
|
* On successful completion (return -1) or on Exception, the streams
|
||||||
|
* {@link #in} and {@link #out} are closed by the implementation.
|
||||||
*
|
*
|
||||||
* @return the number of bytes read from the {@link java.io.InputStream} or
|
* @return the number of bytes read from the {@link java.io.InputStream} or
|
||||||
* -1. -1 means that the {@link java.io.InputStream} is completely
|
* -1. -1 means that the {@link java.io.InputStream} is completely
|
||||||
|
|
|
@ -476,7 +476,7 @@ private InputStream filterClean(InputStream in, OperationType opType)
|
||||||
while (command.run() != -1) {
|
while (command.run() != -1) {
|
||||||
// loop as long as command.run() tells there is work to do
|
// loop as long as command.run() tells there is work to do
|
||||||
}
|
}
|
||||||
return buffer.openInputStream();
|
return buffer.openInputStreamWithAutoDestroy();
|
||||||
}
|
}
|
||||||
FS fs = repository.getFS();
|
FS fs = repository.getFS();
|
||||||
ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand,
|
ProcessBuilder filterProcessBuilder = fs.runInShell(filterCommand,
|
||||||
|
@ -499,7 +499,7 @@ filterCommand, getEntryPathString(),
|
||||||
RawParseUtils.decode(result.getStderr()
|
RawParseUtils.decode(result.getStderr()
|
||||||
.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
|
.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
|
||||||
}
|
}
|
||||||
return result.getStdout().openInputStream();
|
return result.getStdout().openInputStreamWithAutoDestroy();
|
||||||
}
|
}
|
||||||
return in;
|
return in;
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ public LfsInputStream(InputStream stream, long length) {
|
||||||
* in case of an error opening the stream to the buffer.
|
* in case of an error opening the stream to the buffer.
|
||||||
*/
|
*/
|
||||||
public LfsInputStream(TemporaryBuffer buffer) throws IOException {
|
public LfsInputStream(TemporaryBuffer buffer) throws IOException {
|
||||||
this.stream = buffer.openInputStream();
|
this.stream = buffer.openInputStreamWithAutoDestroy();
|
||||||
this.length = buffer.length();
|
this.length = buffer.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,6 +313,26 @@ public InputStream openInputStream() throws IOException {
|
||||||
return new BlockInputStream();
|
return new BlockInputStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as {@link #openInputStream()} but handling destruction of any
|
||||||
|
* associated resources automatically when closing the returned stream.
|
||||||
|
*
|
||||||
|
* @return an InputStream which will automatically destroy any associated
|
||||||
|
* temporary file on {@link #close()}
|
||||||
|
* @throws IOException
|
||||||
|
* in case of an error.
|
||||||
|
* @since 4.11
|
||||||
|
*/
|
||||||
|
public InputStream openInputStreamWithAutoDestroy() throws IOException {
|
||||||
|
return new BlockInputStream() {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
super.close();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset this buffer for reuse, purging all buffered content.
|
* Reset this buffer for reuse, purging all buffered content.
|
||||||
*/
|
*/
|
||||||
|
@ -505,6 +525,20 @@ public InputStream openInputStream() throws IOException {
|
||||||
return new FileInputStream(onDiskFile);
|
return new FileInputStream(onDiskFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream openInputStreamWithAutoDestroy() throws IOException {
|
||||||
|
if (onDiskFile == null) {
|
||||||
|
return super.openInputStreamWithAutoDestroy();
|
||||||
|
}
|
||||||
|
return new FileInputStream(onDiskFile) {
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
super.close();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
|
|
Loading…
Reference in New Issue