Skip to content

Commit 38a1743

Browse files
authored
Merge pull request #198 from saalfeldlab/default-write-region
Add default implementation of N5writer.writeRegion
2 parents b191e30 + 5b179e0 commit 38a1743

5 files changed

Lines changed: 83 additions & 22 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
<groupId>org.janelia.saalfeldlab</groupId>
1313
<artifactId>n5</artifactId>
14-
<version>4.0.0-alpha-7-SNAPSHOT</version>
14+
<version>4.0.0-alpha-8-SNAPSHOT</version>
1515

1616
<name>N5</name>
1717
<description>Not HDF5</description>

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,21 +298,19 @@ default boolean remove(final String path) throws N5Exception {
298298
@Override
299299
default boolean deleteBlock(
300300
final String path,
301+
final DatasetAttributes datasetAttributes,
301302
final long... gridPosition) throws N5Exception {
302303

303-
final String normalPath = N5URI.normalizeGroupPath(path);
304-
final DatasetAttributes datasetAttributes = getDatasetAttributes(normalPath);
305304
final PositionValueAccess posKva = PositionValueAccess.fromKva(getKeyValueAccess(), getURI(), N5URI.normalizeGroupPath(path), datasetAttributes);
306305
return datasetAttributes.getDatasetAccess().deleteBlock(posKva, gridPosition);
307306
}
308307

309308
@Override
310309
default boolean deleteBlocks(
311310
final String path,
311+
final DatasetAttributes datasetAttributes,
312312
final List<long[]> gridPositions) throws N5Exception {
313313

314-
final String normalPath = N5URI.normalizeGroupPath(path);
315-
final DatasetAttributes datasetAttributes = getDatasetAttributes(normalPath);
316314
final PositionValueAccess posKva = PositionValueAccess.fromKva(getKeyValueAccess(), getURI(), N5URI.normalizeGroupPath(path), datasetAttributes);
317315
return datasetAttributes.getDatasetAccess().deleteBlocks(posKva, gridPositions);
318316
}

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

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
import java.util.Map;
4040
import java.util.concurrent.ExecutionException;
4141
import java.util.concurrent.ExecutorService;
42+
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedGrid;
43+
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedPosition;
44+
import org.janelia.saalfeldlab.n5.shard.Region;
4245

4346
/**
4447
* A simple structured container API for hierarchies of chunked
@@ -298,13 +301,33 @@ interface DataBlockSupplier<T> {
298301
* @param writeFully if false, merge existing data in shards/blocks that overlap the region boundary. if true, override everything.
299302
* @throws N5Exception the exception
300303
*/
301-
<T> void writeRegion(
304+
default <T> void writeRegion(
302305
String datasetPath,
303306
DatasetAttributes datasetAttributes,
304307
long[] min,
305308
long[] size,
306309
DataBlockSupplier<T> dataBlocks,
307-
boolean writeFully) throws N5Exception;
310+
boolean writeFully) throws N5Exception {
311+
312+
final NestedGrid grid = datasetAttributes.getNestedBlockGrid();
313+
final Region region = new Region(min, size, grid);
314+
for (long[] key : Region.gridPositions(region.minPos().key(), region.maxPos().key())) {
315+
final NestedPosition pos = grid.nestedPosition(key, grid.numLevels() - 1);
316+
final long[] gridPosition = pos.absolute(0);
317+
final DataBlock<T> existingDataBlock = writeFully || region.fullyContains(pos)
318+
? null
319+
: readBlock(datasetPath, datasetAttributes, gridPosition);
320+
final DataBlock<T> dataBlock = dataBlocks.get(gridPosition, existingDataBlock);
321+
// null blocks may be provided when they contain only the fill value
322+
// and only non-empty blocks should be written, for example
323+
if (dataBlock == null) {
324+
deleteBlock(datasetPath, datasetAttributes, gridPosition);
325+
} else {
326+
writeBlock(datasetPath, datasetAttributes, dataBlock);
327+
}
328+
}
329+
330+
}
308331

309332
/**
310333
* @param datasetPath the dataset path
@@ -316,14 +339,35 @@ <T> void writeRegion(
316339
* @param exec used to parallelize over blocks and shards
317340
* @throws N5Exception the exception
318341
*/
319-
<T> void writeRegion(
342+
default <T> void writeRegion(
320343
String datasetPath,
321344
DatasetAttributes datasetAttributes,
322345
long[] min,
323346
long[] size,
324347
DataBlockSupplier<T> dataBlocks,
325348
boolean writeFully,
326-
ExecutorService exec) throws N5Exception, InterruptedException, ExecutionException;
349+
ExecutorService exec) throws N5Exception, InterruptedException, ExecutionException {
350+
351+
final NestedGrid grid = datasetAttributes.getNestedBlockGrid();
352+
final Region region = new Region(min, size, grid);
353+
for (long[] key : Region.gridPositions(region.minPos().key(), region.maxPos().key())) {
354+
exec.submit(() -> {
355+
final NestedPosition pos = grid.nestedPosition(key, grid.numLevels() - 1);
356+
final long[] gridPosition = pos.absolute(0);
357+
final DataBlock<T> existingDataBlock = writeFully || region.fullyContains(pos)
358+
? null
359+
: readBlock(datasetPath, datasetAttributes, gridPosition);
360+
final DataBlock<T> dataBlock = dataBlocks.get(gridPosition, existingDataBlock);
361+
// null blocks may be provided when they contain only the fill value
362+
// and only non-empty blocks should be written, for example
363+
if (dataBlock == null) {
364+
deleteBlock(datasetPath, datasetAttributes, gridPosition);
365+
} else {
366+
writeBlock(datasetPath, datasetAttributes, dataBlock);
367+
}
368+
});
369+
}
370+
}
327371

328372
/**
329373
* Deletes the block at {@code gridPosition}.
@@ -334,9 +378,27 @@ <T> void writeRegion(
334378
*
335379
* @return {@code true} if the block at {@code gridPosition} existed and was deleted.
336380
*/
337-
boolean deleteBlock(
381+
default boolean deleteBlock(
338382
final String datasetPath,
339-
final long... gridPosition) throws N5Exception;
383+
final long... gridPosition) throws N5Exception {
384+
final DatasetAttributes datasetAttributes = getDatasetAttributes(datasetPath);
385+
return deleteBlock(datasetPath, datasetAttributes, gridPosition);
386+
}
387+
388+
/**
389+
* Deletes the block at {@code gridPosition}.
390+
*
391+
* @param datasetPath the dataset path
392+
* @param datasetAttributes the dataset attributes
393+
* @param gridPosition position of block to be deleted
394+
* @throws N5Exception if the block exists but could not be deleted
395+
*
396+
* @return {@code true} if the block at {@code gridPosition} existed and was deleted.
397+
*/
398+
boolean deleteBlock(
399+
String datasetPath,
400+
DatasetAttributes datasetAttributes,
401+
long... gridPosition) throws N5Exception;
340402

341403
/**
342404
* Deletes the blocks at the given {@code gridPositions}.
@@ -347,11 +409,12 @@ boolean deleteBlock(
347409
* @throws N5Exception if any of the block exists but could not be deleted
348410
*/
349411
default boolean deleteBlocks(
350-
final String datasetPath,
351-
final List<long[]> gridPositions) throws N5Exception {
412+
String datasetPath,
413+
DatasetAttributes datasetAttributes,
414+
List<long[]> gridPositions) throws N5Exception {
352415
boolean deleted = false;
353416
for (long[] pos : gridPositions) {
354-
deleted |= deleteBlock(datasetPath, pos);
417+
deleted |= deleteBlock(datasetPath, datasetAttributes, pos);
355418
}
356419
return deleted;
357420
}

src/main/java/org/janelia/saalfeldlab/n5/shard/Region.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* Provides methods to find which blocks and shards are contained in the
4040
* region, iterate sub-NestedPositions, etc.
4141
*/
42-
class Region {
42+
public class Region {
4343

4444
/**
4545
* The dimensions of the full dataset.
@@ -72,7 +72,7 @@ class Region {
7272
*/
7373
private final Nesting.NestedPosition maxPos;
7474

75-
Region(final long[] min, final long[] size, final NestedGrid grid) {
75+
public Region(final long[] min, final long[] size, final NestedGrid grid) {
7676
this.min = min;
7777
this.size = size;
7878
this.grid = grid;
@@ -93,14 +93,14 @@ class Region {
9393
/**
9494
* Get the {@code NestedPosition} of the minimum DataBlock touched by the region.
9595
*/
96-
Nesting.NestedPosition minPos() {
96+
public Nesting.NestedPosition minPos() {
9797
return minPos;
9898
}
9999

100100
/**
101101
* Get the {@code NestedPosition} of the maximum DataBlock touched by the region.
102102
*/
103-
Nesting.NestedPosition maxPos() {
103+
public Nesting.NestedPosition maxPos() {
104104
return maxPos;
105105
}
106106

@@ -116,7 +116,7 @@ Nesting.NestedPosition maxPos() {
116116
*
117117
* @return true, if the given position is fully contained in this region
118118
*/
119-
boolean fullyContains(final Nesting.NestedPosition position) {
119+
public boolean fullyContains(final Nesting.NestedPosition position) {
120120

121121
final long[] pmin = position.pixelPosition();
122122
for (int d = 0; d < pmin.length; d++) {
@@ -165,7 +165,7 @@ List<Nesting.NestedPosition> containedNestedPositions(final Nesting.NestedPositi
165165
}
166166

167167
// TODO: Revise to accept Consumer<long[]> for handling each position
168-
static List<long[]> gridPositions(final long[] min, final long[] max) {
168+
public static List<long[]> gridPositions(final long[] min, final long[] max) {
169169
final int n = min.length;
170170
final long[] pos = min.clone();
171171
int numElements = 1;

src/test/java/org/janelia/saalfeldlab/n5/http/HttpReaderFsWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ public <W extends GsonKeyValueN5Writer, R extends GsonKeyValueN5Reader> HttpRead
281281
return writer.deleteBlock(datasetPath, gridPosition);
282282
}
283283

284-
@Override public boolean deleteBlocks(String datasetPath, List<long[]> gridPositions) throws N5Exception {
284+
@Override public boolean deleteBlocks(String datasetPath, DatasetAttributes datasetAttributes, List<long[]> gridPositions) throws N5Exception {
285285

286-
return writer.deleteBlocks(datasetPath, gridPositions);
286+
return writer.deleteBlocks(datasetPath, datasetAttributes, gridPositions);
287287
}
288288

289289
@Override public void writeSerializedBlock(Serializable object, String datasetPath, DatasetAttributes datasetAttributes, long... gridPosition) throws N5Exception {

0 commit comments

Comments
 (0)