Skip to content

Commit 3ab8795

Browse files
committed
fix: handle the smb over mac edge case about closing file channels failing after a successful write.
1 parent e8883af commit 3ab8795

2 files changed

Lines changed: 38 additions & 11 deletions

File tree

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

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,44 @@ static FileChannel openFileChannel(final Path path, final boolean forWriting) th
5252
}
5353
}
5454

55+
56+
/**
57+
* This method is necessary to handle the situtation where writing is successful, but `close` fails on the file channel.
58+
* This has been observed to happen fairly consistently on MacOS when writing to a file mounted over SMB.
59+
*
60+
* @param readData to write to the {@code Path}
61+
* @param path to write to
62+
* @throws IOException if writing failed.
63+
*/
64+
private static void writeToPathIgnoreCloseException(ReadData readData, Path path) throws IOException {
65+
66+
FileChannel channel = openFileChannel(path, true);
67+
OutputStream os = Channels.newOutputStream(channel);
68+
69+
try {
70+
readData.writeTo(os);
71+
os.flush();
72+
channel.force(true);
73+
} catch (Throwable e) {
74+
os.close();
75+
channel.close();
76+
throw e;
77+
}
78+
79+
/* if we get here, the write succeeded, and the os/channel may not be closed yet */
80+
try {
81+
os.close();
82+
channel.close();
83+
} catch (IOException | UncheckedIOException ignore) {
84+
/* Ignore; we know the data was written already. */
85+
}
86+
}
87+
5588
public static class Unsafe implements IoPolicy {
5689
@Override
5790
public void write(String key, ReadData readData) throws IOException {
5891
final Path path = Paths.get(key);
59-
try (
60-
FileChannel channel = openFileChannel(path, true);
61-
OutputStream os = Channels.newOutputStream(channel);
62-
) {
63-
readData.writeTo(os);
64-
}
92+
writeToPathIgnoreCloseException(readData, path);
6593
}
6694

6795
@Override

src/test/java/org/janelia/saalfeldlab/n5/shard/ShardTest.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,14 +632,13 @@ public void testPartialReadAggregationBehavior() {
632632
writer.resetNumMaterializeCalls();
633633
writer.readBlocks(dataset, datasetAttributes, ptList);
634634

635-
// TODO change this if and when we implement aggregation of read calls
636-
// one for the index, one for each of the four blocks
637-
assertEquals(5, writer.getNumMaterializeCalls());
635+
// one for the index, one for the four blocks (aggregated)
636+
assertEquals(2, writer.getNumMaterializeCalls());
638637

639638
writer.resetNumMaterializeCalls();
640639
writer.readShard(dataset, datasetAttributes, new long[] {0,0});
641-
// one for the index, one for each of the four blocks
642-
assertEquals(5, writer.getNumMaterializeCalls());
640+
// one for the index, one for the four blocks (aggregated)
641+
assertEquals(2, writer.getNumMaterializeCalls());
643642

644643

645644
/**

0 commit comments

Comments
 (0)