Skip to content

Commit d596477

Browse files
committed
perf: Don't use Files.copy for Unsafe. It's much slower than writing via FileChannel.
fix: ensure parent directories exist before writing file for Unsafe Signed-off-by: Caleb Hulbert <cmhulbert@gmail.com>
1 parent 99ed3c4 commit d596477

2 files changed

Lines changed: 30 additions & 25 deletions

File tree

src/main/java/org/janelia/saalfeldlab/n5/ChannelLock.java

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@
66
import java.nio.channels.FileChannel;
77
import java.nio.channels.FileLock;
88
import java.nio.channels.OverlappingFileLockException;
9-
import java.nio.file.Files;
109
import java.nio.file.Path;
11-
import java.nio.file.StandardOpenOption;
1210

1311
/**
1412
* Holds a channel and system-level file lock (shared for writing, non-shared
@@ -56,7 +54,7 @@ FileChannel getChannel() {
5654
*/
5755
static ChannelLock lock(final Path path, final boolean forWriting) throws IOException {
5856

59-
final FileChannel channel = openFileChannel(path, forWriting);
57+
final FileChannel channel = FsIoPolicy.openFileChannel(path, forWriting);
6058
try {
6159
while (true) {
6260
try {
@@ -94,7 +92,7 @@ static ChannelLock tryLock(final Path path, final boolean forWriting) throws IOE
9492

9593
FileChannel channel = null;
9694
try {
97-
channel = openFileChannel(path, forWriting);
95+
channel = FsIoPolicy.openFileChannel(path, forWriting);
9896
final FileLock lock = channel.tryLock(0, Long.MAX_VALUE, !forWriting);
9997
return lock == null ? null : new ChannelLock(channel, lock);
10098
} catch (Exception e) {
@@ -103,26 +101,6 @@ static ChannelLock tryLock(final Path path, final boolean forWriting) throws IOE
103101
}
104102
}
105103

106-
/**
107-
* Opens a file channel. If the channel is opened {@code forWriting},
108-
* then this may create the file and the parent directories as needed.
109-
*
110-
* @throws IOException
111-
* if the channel cannot be opened
112-
*/
113-
private static FileChannel openFileChannel(final Path path, final boolean forWriting) throws IOException {
114-
115-
if (forWriting) {
116-
final Path parent = path.getParent();
117-
if (parent != null) {
118-
Files.createDirectories(parent);
119-
}
120-
return FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
121-
} else {
122-
return FileChannel.open(path, StandardOpenOption.READ);
123-
}
124-
}
125-
126104
private static void closeQuietly(final FileChannel fileChannel) {
127105
if (fileChannel != null) {
128106
try {

src/main/java/org/janelia/saalfeldlab/n5/FsIoPolicy.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66

77
import java.io.Closeable;
88
import java.io.IOException;
9+
import java.io.OutputStream;
910
import java.io.UncheckedIOException;
1011
import java.nio.ByteBuffer;
12+
import java.nio.channels.Channels;
1113
import java.nio.channels.FileChannel;
1214
import java.nio.file.*;
1315

@@ -29,11 +31,36 @@ else if (length >= 0 && offset + length > channelSize)
2931
return true;
3032
}
3133

34+
/**
35+
* Opens a file channel. If the channel is opened {@code forWriting},
36+
* then this may create the file and the parent directories as needed.
37+
*
38+
* @throws IOException
39+
* if the channel cannot be opened
40+
*/
41+
static FileChannel openFileChannel(final Path path, final boolean forWriting) throws IOException {
42+
43+
if (forWriting) {
44+
final Path parent = path.getParent();
45+
if (parent != null) {
46+
Files.createDirectories(parent);
47+
}
48+
return FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
49+
} else {
50+
return FileChannel.open(path, StandardOpenOption.READ);
51+
}
52+
}
53+
3254
public static class Unsafe implements IoPolicy {
3355
@Override
3456
public void write(String key, ReadData readData) throws IOException {
3557
final Path path = Paths.get(key);
36-
Files.copy(readData.inputStream(), path, StandardCopyOption.REPLACE_EXISTING);
58+
try (
59+
FileChannel channel = openFileChannel(path, true);
60+
OutputStream os = Channels.newOutputStream(channel);
61+
) {
62+
readData.writeTo(os);
63+
}
3764
}
3865

3966
@Override

0 commit comments

Comments
 (0)