Miscellaneous improvements to "jar".
Martin Buchholz
martinrb at google.com
Mon Jun 29 23:52:24 UTC 2009
On Sun, Jun 28, 2009 at 22:47, Xueming Shen <Xueming.Shen at sun.com> wrote:
>
> Looks fine.
>
> (1) "import java.nio.file.Paths" is not used by anyone.
Let's make sure to start using nio2 then...
>
> (2)nio2 APIs are good, but now I can't not just copy/paste the jar Main to
> 6.x:-)
>
That *is* a problem. Fortunately, it's a small change.
Is there anything else stopping the jdk6 version from being identical to
jdk7?
Martin
>
> sherman
>
>
> Martin Buchholz wrote:
>
>>
>>
>> On Fri, Jun 26, 2009 at 10:33, Xueming Shen <Xueming.Shen at sun.com<mailto:
>> Xueming.Shen at sun.com>> wrote:
>>
>> The latest version looks good. 2 nit comments
>>
>> (1) it's reasonable to have createTempFileInSamDirectoryAs
>> separate out, but I would
>> keep the directoryOf within it. Yes, it's "clearer":-)
>>
>>
>> Done.
>>
>> }
>> /**
>> - * A variant of File.getParentFile that always returns a valid
>> - * directory (i.e. returns new File(".") where File.getParentFile
>> - * would return null).
>> - */
>> - private static File directoryOf(File file) {
>> - File dir = file.getParentFile();
>> - return (dir != null) ? dir : new File(".");
>> - }
>> -
>> - /**
>> * Creates a new empty temporary file in the same directory as the
>> * specified file. A variant of File.createTempFile.
>> */
>> private static File createTempFileInSameDirectoryAs(File file)
>> throws IOException {
>> - return File.createTempFile("jartmp", null, directoryOf(file));
>> + File dir = file.getParentFile();
>> + if (dir == null)
>> + dir = new File(".");
>> + return File.createTempFile("jartmp", null, dir);
>> }
>> private boolean ok;
>>
>>
>>
>> (2)the "updateOK" in dumpIndex really serves nobody but "clearer":-)
>>
>>
>> I tried to improve dumpIndex by
>> - removing updateOk variable.
>> - using Path.moveTo is more likely to be atomic, so that
>> a concurrent process is less likely to find the jar being updated
>> missing.
>> (Alan: is there a better way to do the common task of replacing a file
>> with its transformed output?)
>>
>> */
>> void dumpIndex(String rootjar, JarIndex index) throws IOException {
>> File jarFile = new File(rootjar);
>> - File tmpFile = createTempFileInSameDirectoryAs(jarFile);
>> + Path jarPath = jarFile.toPath();
>> + Path tmpPath = createTempFileInSameDirectoryAs(jarFile).toPath();
>> try {
>> - boolean updateOk = update(new FileInputStream(jarFile),
>> - new FileOutputStream(tmpFile),
>> - null, index);
>> - if (updateOk) {
>> - jarFile.delete();
>> - if (!tmpFile.renameTo(jarFile)) {
>> - throw new IOException(getMsg("error.write.file"));
>> + if (update(jarPath.newInputStream(),
>> + tmpPath.newOutputStream(),
>> + null, index)) {
>> + try {
>> + tmpPath.moveTo(jarPath, REPLACE_EXISTING);
>> + } catch (IOException e) {
>> + throw new IOException(getMsg("error.write.file"), e);
>> }
>> }
>> } finally {
>> - tmpFile.delete();
>> + tmpPath.delete(false);
>> }
>> }
>>
>> webrev updated.
>> Martin
>>
>>
>>
>>
>> sherman
>>
>> btw, while you are here:-) do you have time to make the update()
>> NOT to put jarIndex the
>> first one when there is a manifest present? The JarInputStream
>> assumes the manifest is always
>> the first entry (or the second if the manifest dir is the first),
>> which causes problem...I'm not saying
>> to mix with this one:-) just in case you have time and interested
>> while you are here:-)
>>
>>
>> Martin Buchholz wrote:
>>
>> I did some benchmarking,
>> and found that my changes "only" make jar 10-20% faster.
>> Disappointing - we expect an order of magnitude for every commit!
>>
>> While benchmarking, I discovered to my horror that the simple
>>
>> jar cf /tmp/t1 ...
>> jar i /tmp/t1
>>
>> fails, because it tries to create the replacement jar in "."
>> and then
>> rename() it into place. Oops... Better refactor out the code that
>> puts the replacement temp file in the same directory.
>> Better write some tests for that, too.
>>
>> /**
>> * A variant of File.getParentFile that always returns a valid
>> * directory (i.e. returns new File(".") where
>> File.getParentFile
>> * would return null).
>> */
>> private static File directoryOf(File file) {
>> File dir = file.getParentFile();
>> return (dir != null) ? dir : new File(".");
>> }
>>
>> /**
>> * Creates a new empty temporary file in the same directory
>> as the
>> * specified file. A variant of File.createTempFile.
>> */
>> private static File createTempFileInSameDirectoryAs(File
>> file) throws IOException {
>> return File.createTempFile("jartmp", null,
>> directoryOf(file));
>> }
>>
>> ---
>>
>> While we're here, let's remove the double buffering on file
>> copy operations.
>> And the repeated allocations of big buffers.
>>
>> /**
>> * A buffer for use only by copy(InputStream, OutputStream).
>> * Not as clean as allocating a new buffer as needed by copy,
>> * but significantly more efficient.
>> */
>> private byte[] copyBuf = new byte[8192];
>>
>> /**
>> * Copies all bytes from the input stream to the output stream.
>> * Does not close or flush either stream.
>> *
>> * @param from the input stream to read from
>> * @param to the output stream to write to
>> * @throws IOException if an I/O error occurs
>> */
>> private void copy(InputStream from, OutputStream to) throws
>> IOException {
>> int n;
>> while ((n = from.read(copyBuf)) != -1)
>> to.write(copyBuf, 0, n);
>> }
>>
>> /**
>> * Copies all bytes from the input file to the output stream.
>> * Does not close or flush the output stream.
>> *
>> * @param from the input file to read from
>> * @param to the output stream to write to
>> * @throws IOException if an I/O error occurs
>> */
>> private void copy(File from, OutputStream to) throws
>> IOException {
>> InputStream in = new FileInputStream(from);
>> try {
>> copy(in, to);
>> } finally {
>> in.close();
>> }
>> }
>>
>> /**
>> * Copies all bytes from the input stream to the output file.
>> * Does not close the input stream.
>> *
>> * @param from the input stream to read from
>> * @param to the output file to write to
>> * @throws IOException if an I/O error occurs
>> */
>> private void copy(InputStream from, File to) throws
>> IOException {
>> OutputStream out = new FileOutputStream(to);
>> try {
>> copy(from, out);
>> } finally {
>> out.close();
>> }
>> }
>>
>> ----
>>
>> On the other hand, allocating a CRC32 is very cheap, so let's
>> make that
>> private to CRC32OutputStream.
>> + private static class CRC32OutputStream extends
>> java.io.OutputStream {
>> + final CRC32 crc = new CRC32();
>>
>> ----
>>
>> We should add a try { finally } to delete the tempfile for jar i
>> + try {
>> boolean updateOk = update(new FileInputStream(jarFile),
>> - new
>> FileOutputStream(scratchFile),
>>
>> + new
>> FileOutputStream(tmpFile),
>> null, index);
>> + if (updateOk) {
>> jarFile.delete();
>>
>> - if (!scratchFile.renameTo(jarFile)) {
>> - scratchFile.delete();
>> + if (!tmpFile.renameTo(jarFile)) {
>>
>> throw new IOException(getMsg("error.write.file"));
>> }
>> - scratchFile.delete();
>> + }
>> + } finally {
>>
>> + tmpFile.delete();
>> + }
>> }
>> ----
>>
>> Webrev updated.
>> http://cr.openjdk.java.net/~martin/jar-misc/<http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>>
>>
>> There are now many small changes combined in this fix. Sorry
>> about that.
>> I'd be more inclined to separate them if creating new bugs was
>> easier.
>>
>> I'm not planning on making any more changes. Really.
>>
>> Martin
>>
>> On Thu, Jun 25, 2009 at 12:00, Martin Buchholz
>> <martinrb at google.com <mailto:martinrb at google.com>
>> <mailto:martinrb at google.com <mailto:martinrb at google.com>>> wrote:
>>
>> I have an updated version of this fix, with these changes:
>>
>> - Documented the turkish i problem
>>
>> /**
>> * Compares two strings for equality, ignoring case.
>> The second
>> * argument must contain only upper-case ASCII characters.
>> * We don't want case comparison to be locale-dependent
>> (else we
>> * have the notorious "turkish i bug").
>> */
>> private boolean equalsIgnoreCase(String s, String upper) {
>>
>> - Refactored code so that updateEntry now also sets the
>> method to
>> STORED.
>>
>> /**
>> * Updates a ZipEntry which describes the data read
>> by this
>> * output stream, in STORED mode.
>> */
>> public void updateEntry(ZipEntry e) {
>> e.setMethod(ZipEntry.STORED);
>> e.setSize(n);
>> e.setCrc(crc.getValue());
>> }
>>
>> - addIndex was never updating the size in the ZipEntry (as
>> required),
>> which was not previously noticed because closeEntry was never
>> called.
>>
>> private void addIndex(JarIndex index, ZipOutputStream zos)
>> throws IOException
>> {
>> ZipEntry e = new ZipEntry(INDEX_NAME);
>> e.setTime(System.currentTimeMillis());
>> if (flag0) {
>> CRC32OutputStream os = new
>> CRC32OutputStream(crc32);
>> index.write(os);
>> os.updateEntry(e);
>> }
>> zos.putNextEntry(e);
>> index.write(zos);
>> zos.closeEntry();
>>
>> }
>>
>> http://cr.openjdk.java.net/~martin/jar-misc/<http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>>
>> Previous webrev:
>> http://cr.openjdk.java.net/~martin/jar-misc.0/<http://cr.openjdk.java.net/%7Emartin/jar-misc.0/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc.0/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc.0/>
>>
>>
>> Martin
>>
>>
>>
>> On Wed, Jun 24, 2009 at 19:34, Martin Buchholz
>> <martinrb at google.com <mailto:martinrb at google.com>
>> <mailto:martinrb at google.com <mailto:martinrb at google.com>>> wrote:
>>
>> Hi jar team,
>>
>> I have a bunch of minor improvements to
>> src/share/classes/sun/tools/jar/Main.java
>>
>> Toby and Xueming, please review.
>>
>> Warning: the index code has not been maintained for
>> many years.
>>
>> Xueming, please file a bug.
>>
>> Synopsis: Miscellaneous improvements to "jar".
>> Description:
>> - Use standard jdk coding style for javadoc
>> - Don't create a temp file for jar index in STORED mode.
>> - Don't use synchronized collections.
>> - Fix javac warnings.
>> - Don't define new names for things like INDEX_NAME;
>> use static import instead.
>> - more efficiently compare special file names in update
>> mode.
>> Update mode should be measurably faster.
>> - make CRC32OutputStream a nested class.
>> refactor crc32.reset and updating entry into
>> CRC32OutputStream.
>> - Fix apparently benign bug updating n in
>> CRC32OutputStream.write(byte[], int, int)
>>
>> Evaluation: Yep.
>>
>> http://cr.openjdk.java.net/~martin/jar-misc/<http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>> <http://cr.openjdk.java.net/%7Emartin/jar-misc/>
>>
>> Thanks,
>>
>> Martin
>>
>>
>>
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/core-libs-dev/attachments/20090629/6ff253e3/attachment.html>
More information about the core-libs-dev
mailing list