diff --git a/pom.xml b/pom.xml index d56dc94..4050877 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ org.janelia.saalfeldlab n5-hdf5 - 2.3.0-alpha-4-SNAPSHOT + 2.3.0-alpha-4-fix N5 HDF5 Bindings Best effort N5 implementation on HDF5 files. @@ -139,7 +139,7 @@ sign,deploy-to-scijava - 4.0.0-alpha-4 + 4.0.0-alpha-6 diff --git a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java index 35a085d..d0b3838 100644 --- a/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java +++ b/src/main/java/org/janelia/saalfeldlab/n5/hdf5/N5HDF5Writer.java @@ -552,6 +552,138 @@ public void writeBlock( } } + @Override + public void writeRegion( + final String datasetPath, + final DatasetAttributes datasetAttributes, + final long[] min, + final long[] size, + final DataBlockSupplier dataBlocks, + final boolean writeFully) throws N5Exception { + + // For HDF5 (no sharding support), iterate through blocks in the region + // and write each one using writeBlock + final int n = min.length; + final int[] blockSize = datasetAttributes.getBlockSize(); + + // Compute min and max block grid positions + final long[] minBlock = new long[n]; + final long[] maxBlock = new long[n]; + for (int d = 0; d < n; ++d) { + minBlock[d] = min[d] / blockSize[d]; + maxBlock[d] = (min[d] + size[d] - 1) / blockSize[d]; + } + + // Iterate through all blocks in the region + final long[] gridPosition = minBlock.clone(); + while (true) { + // Check if we need to read existing data for this block + final DataBlock existingBlock; + if (writeFully) { + existingBlock = null; + } else { + // Check if block is fully contained in the region + boolean fullyContained = true; + for (int d = 0; d < n; ++d) { + final long blockStart = gridPosition[d] * blockSize[d]; + final long blockEnd = blockStart + blockSize[d]; + if (blockStart < min[d] || blockEnd > min[d] + size[d]) { + fullyContained = false; + break; + } + } + @SuppressWarnings("unchecked") + final DataBlock readBlockUnchecked = (DataBlock) readBlock(datasetPath, datasetAttributes, gridPosition); + existingBlock = fullyContained ? null : readBlockUnchecked; + } + + // Get the new block from the supplier + final DataBlock dataBlock = dataBlocks.get(gridPosition, existingBlock); + if (dataBlock != null) { + writeBlock(datasetPath, datasetAttributes, dataBlock); + } + + // Increment grid position + int d = 0; + for (; d < n; ++d) { + if (gridPosition[d] < maxBlock[d]) { + gridPosition[d]++; + break; + } + gridPosition[d] = minBlock[d]; + } + if (d == n) break; // Done iterating + } + } + + @Override + public void writeRegion( + final String datasetPath, + final DatasetAttributes datasetAttributes, + final long[] min, + final long[] size, + final DataBlockSupplier dataBlocks, + final boolean writeFully, + final java.util.concurrent.ExecutorService executor) throws N5Exception { + + // For HDF5 (no sharding support), iterate through blocks in the region + // and write each one using writeBlock, parallelized with executor + final int n = min.length; + final int[] blockSize = datasetAttributes.getBlockSize(); + + // Compute min and max block grid positions + final long[] minBlock = new long[n]; + final long[] maxBlock = new long[n]; + for (int d = 0; d < n; ++d) { + minBlock[d] = min[d] / blockSize[d]; + maxBlock[d] = (min[d] + size[d] - 1) / blockSize[d]; + } + + // Iterate through all blocks in the region and submit tasks to executor + final long[] gridPosition = minBlock.clone(); + while (true) { + final long[] currentGridPosition = gridPosition.clone(); + executor.submit(() -> { + // Check if we need to read existing data for this block + final DataBlock existingBlock; + if (writeFully) { + existingBlock = null; + } else { + // Check if block is fully contained in the region + boolean fullyContained = true; + for (int d = 0; d < n; ++d) { + final long blockStart = currentGridPosition[d] * blockSize[d]; + final long blockEnd = blockStart + blockSize[d]; + if (blockStart < min[d] || blockEnd > min[d] + size[d]) { + fullyContained = false; + break; + } + } + @SuppressWarnings("unchecked") + final DataBlock readBlockUnchecked = (DataBlock) readBlock(datasetPath, datasetAttributes, currentGridPosition); + existingBlock = fullyContained ? null : readBlockUnchecked; + } + + // Get the new block from the supplier (must be thread-safe) + final DataBlock dataBlock = dataBlocks.get(currentGridPosition, existingBlock); + if (dataBlock != null) { + writeBlock(datasetPath, datasetAttributes, dataBlock); + } + }); + + // Increment grid position + int d = 0; + for (; d < n; ++d) { + if (gridPosition[d] < maxBlock[d]) { + gridPosition[d]++; + break; + } + gridPosition[d] = minBlock[d]; + } + if (d == n) break; // Done iterating + } + } + @Override public boolean deleteBlock(String pathName, final long... gridPosition) throws N5Exception {