< 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,14 +33,12 @@
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;
@@ -622,18 +620,19 @@
e.flag |= FLAG_USE_UTF8;
}
@Override
public void close() throws IOException {
- OutputStream os = getOutputStream(e);
+ // will update the entry
+ try (OutputStream os = getOutputStream(e)) {
os.write(toByteArray());
- os.close(); // will update the entry
+ }
super.close();
}
}
- private int getCompressMethod(FileAttribute<?>... attrs) {
+ 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,11 +672,11 @@
}
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)));
+ new Entry(path, Entry.NEW, false, getCompressMethod()));
} finally {
endRead();
}
} else {
beginRead();
@@ -740,11 +739,11 @@
.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);
+ 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,11 +844,11 @@
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<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,14 +1243,12 @@
// 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);
+ for (ExistingChannelCloser ecc : exChClosers) {
+ if (ecc.closeAndDeleteIfDone()) {
exChClosers.remove(ecc);
}
}
}
if (!hasUpdate)
@@ -1318,17 +1315,17 @@
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),
+ Path path = createTempFileInSameDirectoryAs(zfpath);
+ ExistingChannelCloser ecc = new ExistingChannelCloser(path,
ch,
streams);
- Files.move(zfpath, ecc.path, REPLACE_EXISTING);
+ Files.move(zfpath, path, REPLACE_EXISTING);
exChClosers.add(ecc);
- streams = Collections.synchronizedSet(new HashSet<InputStream>());
+ streams = Collections.synchronizedSet(new HashSet<>());
} else {
ch.close();
Files.delete(zfpath);
}
@@ -2505,22 +2502,38 @@
fm.close();
return sb.toString();
}
}
- private static class ExChannelCloser {
- Path path;
- SeekableByteChannel ch;
- Set<InputStream> streams;
- ExChannelCloser(Path path,
+ 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)
- {
+ 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 >