This is an automated email from the ASF dual-hosted git repository. peterlee pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-compress.git
The following commit(s) were added to refs/heads/master by this push: new 101137b COMPRESS-539 : Update the IOUtils.skip to the latest implementation of Commons IO, and reuse the record buffer in TarArchiveInputStream. 101137b is described below commit 101137bfa0f3ae709c2a2771368b190ceb899ea0 Author: PeterAlfredLee <peteralfred...@gmail.com> AuthorDate: Sat Jul 4 19:11:41 2020 +0800 COMPRESS-539 : Update the IOUtils.skip to the latest implementation of Commons IO, and reuse the record buffer in TarArchiveInputStream. --- src/changes/changes.xml | 4 +++ .../archivers/tar/TarArchiveInputStream.java | 11 +++--- .../org/apache/commons/compress/utils/IOUtils.java | 42 +++++++++++----------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3a1c189..6247111 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -127,6 +127,10 @@ The <action> type attribute can be add,update,fix,remove. and methods are also modified/added. Github Pull Request #97. </action> + <action issue="COMPRESS-539" type="update" date="2020-07-04" due-to="Robin Schimpf"> + Update the IOUtils.skip to the latest implementation of Commons + IO, and reuse the record buffer in TarArchiveInputStream. + </action> </release> <release version="1.20" date="2020-02-08" description="Release 1.20"> diff --git a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java index 57bb601..bac1ee4 100644 --- a/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java +++ b/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java @@ -59,6 +59,9 @@ public class TarArchiveInputStream extends ArchiveInputStream { /** The size the TAR header */ private final int recordSize; + /** The buffer to store the TAR header **/ + private final byte[] recordBuffer; + /** The size of a block */ private final int blockSize; @@ -190,6 +193,7 @@ public class TarArchiveInputStream extends ArchiveInputStream { this.encoding = encoding; this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding); this.recordSize = recordSize; + this.recordBuffer = new byte[recordSize]; this.blockSize = blockSize; this.lenient = lenient; } @@ -519,16 +523,13 @@ public class TarArchiveInputStream extends ArchiveInputStream { * @throws IOException on error */ protected byte[] readRecord() throws IOException { - - final byte[] record = new byte[recordSize]; - - final int readNow = IOUtils.readFully(inputStream, record); + final int readNow = IOUtils.readFully(inputStream, recordBuffer); count(readNow); if (readNow != recordSize) { return null; } - return record; + return recordBuffer; } private void readGlobalPaxHeaders() throws IOException { diff --git a/src/main/java/org/apache/commons/compress/utils/IOUtils.java b/src/main/java/org/apache/commons/compress/utils/IOUtils.java index 7fa502a..f36070d 100644 --- a/src/main/java/org/apache/commons/compress/utils/IOUtils.java +++ b/src/main/java/org/apache/commons/compress/utils/IOUtils.java @@ -40,7 +40,7 @@ public final class IOUtils { // This buffer does not need to be synchronised because it is write only; the contents are ignored // Does not affect Immutability - private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE]; + private static byte[] SKIP_BUF; /** Private constructor to prevent instantiation of this utility class. */ private IOUtils(){ @@ -95,37 +95,39 @@ public final class IOUtils { * Skips the given number of bytes by repeatedly invoking skip on * the given input stream if necessary. * - * <p>In a case where the stream's skip() method returns 0 before - * the requested number of bytes has been skip this implementation - * will fall back to using the read() method.</p> - * * <p>This method will only skip less than the requested number of * bytes if the end of the input stream has been reached.</p> + * <p> + * This method is copied from Apache Commons IO with commit ID + * of 401d17349e7ec52d8fa866c35efd24103f332c29 * - * @param input stream to skip bytes in + * @param input stream to skip bytes in * @param numToSkip the number of bytes to skip * @return the number of bytes actually skipped * @throws IOException on error */ public static long skip(final InputStream input, long numToSkip) throws IOException { - final long available = numToSkip; - while (numToSkip > 0) { - final long skipped = input.skip(numToSkip); - if (skipped == 0) { - break; - } - numToSkip -= skipped; + if (numToSkip < 0) { + throw new IllegalArgumentException("Skip count must be non-negative, actual: " + numToSkip); } - - while (numToSkip > 0) { - final int read = readFully(input, SKIP_BUF, 0, - (int) Math.min(numToSkip, SKIP_BUF_SIZE)); - if (read < 1) { + /* + * N.B. no need to synchronize this because: - we don't care if the buffer is created multiple times (the data + * is ignored) - we always use the same size buffer, so if it it is recreated it will still be OK (if the buffer + * size were variable, we would need to synch. to ensure some other thread did not create a smaller one) + */ + if (SKIP_BUF == null) { + SKIP_BUF = new byte[SKIP_BUF_SIZE]; + } + long remain = numToSkip; + while (remain > 0) { + // See https://issues.apache.org/jira/browse/IO-203 for why we use read() rather than delegating to skip() + final long n = input.read(SKIP_BUF, 0, (int) Math.min(remain, SKIP_BUF_SIZE)); + if (n < 0) { // EOF break; } - numToSkip -= read; + remain -= n; } - return available - numToSkip; + return numToSkip - remain; } /**