< prev index next >

src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java

Print this page
rev 54588 : 8222532: (zipfs) Performance regression when writing ZipFileSystem entries in parallel
Reviewed-by: TBD
rev 54589 : imported patch def2

*** 33,46 **** import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; - import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; - import java.nio.channels.NonWritableChannelException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.channels.WritableByteChannel; import java.nio.file.*; import java.nio.file.attribute.FileAttribute; --- 33,44 ----
*** 622,639 **** e.flag |= FLAG_USE_UTF8; } @Override public void close() throws IOException { ! OutputStream os = getOutputStream(e); os.write(toByteArray()); ! os.close(); // will update the entry super.close(); } } ! private int getCompressMethod(FileAttribute<?>... attrs) { return defaultMethod; } // Returns a Writable/ReadByteChannel for now. Might consider to use // newFileChannel() instead, which dump the entry data into a regular --- 620,638 ---- e.flag |= FLAG_USE_UTF8; } @Override public void close() throws IOException { ! // will update the entry ! try (OutputStream os = getOutputStream(e)) { os.write(toByteArray()); ! } super.close(); } } ! private int getCompressMethod() { return defaultMethod; } // Returns a Writable/ReadByteChannel for now. Might consider to use // newFileChannel() instead, which dump the entry data into a regular
*** 673,683 **** } if (!options.contains(CREATE) && !options.contains(CREATE_NEW)) throw new NoSuchFileException(getString(path)); checkParents(path); return new EntryOutputChannel( ! new Entry(path, Entry.NEW, false, getCompressMethod(attrs))); } finally { endRead(); } } else { beginRead(); --- 672,682 ---- } if (!options.contains(CREATE) && !options.contains(CREATE_NEW)) throw new NoSuchFileException(getString(path)); checkParents(path); return new EntryOutputChannel( ! new Entry(path, Entry.NEW, false, getCompressMethod())); } finally { endRead(); } } else { beginRead();
*** 740,750 **** .provider() .newFileChannel(tmpfile, options, attrs); final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); if (forWrite) { u.flag = FLAG_DATADESCR; ! u.method = getCompressMethod(attrs); } // is there a better way to hook into the FileChannel's close method? return new FileChannel() { public int write(ByteBuffer src) throws IOException { return fch.write(src); --- 739,749 ---- .provider() .newFileChannel(tmpfile, options, attrs); final Entry u = isFCH ? e : new Entry(path, tmpfile, Entry.FILECH); if (forWrite) { u.flag = FLAG_DATADESCR; ! u.method = getCompressMethod(); } // is there a better way to hook into the FileChannel's close method? return new FileChannel() { public int write(ByteBuffer src) throws IOException { return fch.write(src);
*** 845,855 **** private Set<InputStream> streams = Collections.synchronizedSet(new HashSet<>()); // the ex-channel and ex-path that need to close when their outstanding // input streams are all closed by the obtainers. ! private Set<ExChannelCloser> exChClosers = new HashSet<>(); private Set<Path> tmppaths = Collections.synchronizedSet(new HashSet<Path>()); private Path getTempPathForEntry(byte[] path) throws IOException { Path tmpPath = createTempFileInSameDirectoryAs(zfpath); if (path != null) { --- 844,854 ---- private Set<InputStream> streams = Collections.synchronizedSet(new HashSet<>()); // the ex-channel and ex-path that need to close when their outstanding // input streams are all closed by the obtainers. ! private Set<ExistingChannelCloser> exChClosers = new HashSet<>(); private Set<Path> tmppaths = Collections.synchronizedSet(new HashSet<Path>()); private Path getTempPathForEntry(byte[] path) throws IOException { Path tmpPath = createTempFileInSameDirectoryAs(zfpath); if (path != null) {
*** 1244,1257 **** // sync the zip file system, if there is any udpate private void sync() throws IOException { // check ex-closer if (!exChClosers.isEmpty()) { ! for (ExChannelCloser ecc : exChClosers) { ! if (ecc.streams.isEmpty()) { ! ecc.ch.close(); ! Files.delete(ecc.path); exChClosers.remove(ecc); } } } if (!hasUpdate) --- 1243,1254 ---- // sync the zip file system, if there is any udpate private void sync() throws IOException { // check ex-closer if (!exChClosers.isEmpty()) { ! for (ExistingChannelCloser ecc : exChClosers) { ! if (ecc.closeAndDeleteIfDone()) { exChClosers.remove(ecc); } } } if (!hasUpdate)
*** 1318,1334 **** if (!streams.isEmpty()) { // // There are outstanding input streams open on existing "ch", // so, don't close the "cha" and delete the "file for now, let // the "ex-channel-closer" to handle them ! ExChannelCloser ecc = new ExChannelCloser( ! createTempFileInSameDirectoryAs(zfpath), ch, streams); ! Files.move(zfpath, ecc.path, REPLACE_EXISTING); exChClosers.add(ecc); ! streams = Collections.synchronizedSet(new HashSet<InputStream>()); } else { ch.close(); Files.delete(zfpath); } --- 1315,1331 ---- if (!streams.isEmpty()) { // // There are outstanding input streams open on existing "ch", // so, don't close the "cha" and delete the "file for now, let // the "ex-channel-closer" to handle them ! Path path = createTempFileInSameDirectoryAs(zfpath); ! ExistingChannelCloser ecc = new ExistingChannelCloser(path, ch, streams); ! Files.move(zfpath, path, REPLACE_EXISTING); exChClosers.add(ecc); ! streams = Collections.synchronizedSet(new HashSet<>()); } else { ch.close(); Files.delete(zfpath); }
*** 2505,2526 **** fm.close(); return sb.toString(); } } ! private static class ExChannelCloser { ! Path path; ! SeekableByteChannel ch; ! Set<InputStream> streams; ! ExChannelCloser(Path path, SeekableByteChannel ch, ! Set<InputStream> streams) ! { this.path = path; this.ch = ch; this.streams = streams; } } // ZIP directory has two issues: // (1) ZIP spec does not require the ZIP file to include // directory entry --- 2502,2539 ---- fm.close(); return sb.toString(); } } ! private static class ExistingChannelCloser { ! private final Path path; ! private final SeekableByteChannel ch; ! private final Set<InputStream> streams; ! ExistingChannelCloser(Path path, SeekableByteChannel ch, ! Set<InputStream> streams) { this.path = path; this.ch = ch; this.streams = streams; } + + /** + * If there are no more outstanding streams, close the channel and + * delete the backing file + * + * @return true if we're done and closed the backing file, + * otherwise false + * @throws IOException + */ + public boolean closeAndDeleteIfDone() throws IOException { + if (streams.isEmpty()) { + ch.close(); + Files.delete(path); + return true; + } + return false; + } } // ZIP directory has two issues: // (1) ZIP spec does not require the ZIP file to include // directory entry
< prev index next >