Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import java.util.Map;

import com.google.gson.JsonSyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import org.janelia.saalfeldlab.n5.N5Exception.N5IOException;
import org.janelia.saalfeldlab.n5.shard.PositionValueAccess;

Expand Down Expand Up @@ -210,6 +212,41 @@ default boolean removeAttributes(final String pathName, final List<String> attri
return removed;
}

@Override
default <T> void writeRegion(
final String datasetPath,
final DatasetAttributes datasetAttributes,
final long[] min,
final long[] size,
final DataBlockSupplier<T> dataBlocks,
final boolean writeFully) throws N5Exception {
try {
final PositionValueAccess posKva = PositionValueAccess.fromKva(getKeyValueAccess(), getURI(), N5URI.normalizeGroupPath(datasetPath), datasetAttributes);
datasetAttributes.<T>getDatasetAccess().writeRegion(posKva, min, size, dataBlocks, datasetAttributes.getDimensions(), writeFully);
} catch (final UncheckedIOException e) {
throw new N5IOException(
"Failed to write blocks into dataset " + datasetPath, e);
}
}

@Override
default <T> void writeRegion(
final String datasetPath,
final DatasetAttributes datasetAttributes,
final long[] min,
final long[] size,
final DataBlockSupplier<T> dataBlocks,
final boolean writeFully,
final ExecutorService exec) throws N5Exception, InterruptedException, ExecutionException {
try {
final PositionValueAccess posKva = PositionValueAccess.fromKva(getKeyValueAccess(), getURI(), N5URI.normalizeGroupPath(datasetPath), datasetAttributes);
datasetAttributes.<T>getDatasetAccess().writeRegion(posKva, min, size, dataBlocks, datasetAttributes.getDimensions(), writeFully, exec);
} catch (final UncheckedIOException e) {
throw new N5IOException(
"Failed to write blocks into dataset " + datasetPath, e);
}
}

@Override
default <T> void writeBlocks(
final String datasetPath,
Expand Down Expand Up @@ -239,7 +276,6 @@ default <T> void writeBlock(
"Failed to write block " + Arrays.toString(dataBlock.getGridPosition()) + " into dataset " + path,
e);
}

}

@Override
Expand Down
73 changes: 70 additions & 3 deletions src/main/java/org/janelia/saalfeldlab/n5/N5Writer.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
*/
package org.janelia.saalfeldlab.n5;

import org.janelia.saalfeldlab.n5.codec.BlockCodecInfo;
import org.janelia.saalfeldlab.n5.codec.DataCodecInfo;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
Expand All @@ -39,6 +36,8 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

/**
* A simple structured container API for hierarchies of chunked
Expand Down Expand Up @@ -265,6 +264,56 @@ default <T> void writeBlocks(
writeBlock(datasetPath, datasetAttributes, block);
}

@FunctionalInterface
interface DataBlockSupplier<T> {

/**
*
* @param gridPos
* @param existingDataBlock
* existing data to be merged into the new data block (maybe {@code null})
*
* @return data block at the given gridPos
*/
DataBlock<T> get(long[] gridPos, final DataBlock<T> existingDataBlock);
}

/**
* @param datasetPath the dataset path
* @param datasetAttributes the dataset attributes
* @param min min pixel coordinate of region to write
* @param size size in pixels of region to write
* @param dataBlocks is asked to create blocks within the given region
* @param writeFully if false, merge existing data in shards/blocks that overlap the region boundary. if true, override everything.
* @throws N5Exception the exception
*/
<T> void writeRegion(
String datasetPath,
DatasetAttributes datasetAttributes,
long[] min,
long[] size,
DataBlockSupplier<T> dataBlocks,
boolean writeFully) throws N5Exception;

/**
* @param datasetPath the dataset path
* @param datasetAttributes the dataset attributes
* @param min min pixel coordinate of region to write
* @param size size in pixels of region to write
* @param dataBlocks is asked to create blocks within the given region
* @param writeFully if false, merge existing data in shards/blocks that overlap the region boundary. if true, override everything.
* @param exec used to parallelize over blocks and shards
* @throws N5Exception the exception
*/
<T> void writeRegion(
String datasetPath,
DatasetAttributes datasetAttributes,
long[] min,
long[] size,
DataBlockSupplier<T> dataBlocks,
boolean writeFully,
ExecutorService exec) throws N5Exception, InterruptedException, ExecutionException;

/**
* Deletes the block at {@code gridPosition}.
*
Expand All @@ -278,6 +327,24 @@ boolean deleteBlock(
final String datasetPath,
final long... gridPosition) throws N5Exception;

/**
* Deletes the blocks at the given {@code gridPositions}.
*
* @param datasetPath dataset path
* @param gridPositions a list of grid positions
* @return {@code true} if any of the specified blocks existed and was deleted
* @throws N5Exception if any of the block exists but could not be deleted
*/
default boolean deleteBlocks(
final String datasetPath,
final List<long[]> gridPositions) throws N5Exception {
boolean deleted = false;
for (long[] pos : gridPositions) {
deleted |= deleteBlock(datasetPath, pos);
}
return deleted;
}

/**
* Save a {@link Serializable} as an N5 {@link DataBlock} at a given offset.
* The
Expand Down
84 changes: 73 additions & 11 deletions src/main/java/org/janelia/saalfeldlab/n5/shard/DatasetAccess.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package org.janelia.saalfeldlab.n5.shard;

import org.janelia.saalfeldlab.n5.DataBlock;
import org.janelia.saalfeldlab.n5.N5Exception.N5IOException;
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedGrid;
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedPosition;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import org.janelia.saalfeldlab.n5.DataBlock;
import org.janelia.saalfeldlab.n5.N5Exception;
import org.janelia.saalfeldlab.n5.N5Exception.N5IOException;
import org.janelia.saalfeldlab.n5.N5Writer.DataBlockSupplier;
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedGrid;
import org.janelia.saalfeldlab.n5.shard.Nesting.NestedPosition;

/**
* Wrap an instantiated DataBlock/shard codec hierarchy to implement (single and
Expand All @@ -20,15 +23,73 @@
*/
public interface DatasetAccess<T> {

DataBlock<T> readBlock(PositionValueAccess kva, long[] gridPosition) throws N5IOException;
DataBlock<T> readBlock(PositionValueAccess pva, long[] gridPosition) throws N5IOException;

void writeBlock(PositionValueAccess pva, DataBlock<T> dataBlock) throws N5IOException;

boolean deleteBlock(PositionValueAccess pva, long[] gridPosition) throws N5IOException;

void writeBlock(PositionValueAccess kva, DataBlock<T> dataBlock) throws N5IOException;

boolean deleteBlock(PositionValueAccess kva, long[] gridPosition) throws N5IOException;
List<DataBlock<T>> readBlocks(PositionValueAccess pva, List<long[]> positions) throws N5IOException;

List<DataBlock<T>> readBlocks(PositionValueAccess kva, List<long[]> positions);
void writeBlocks(PositionValueAccess pva, List<DataBlock<T>> blocks) throws N5IOException;

void writeBlocks(PositionValueAccess kva, List<DataBlock<T>> blocks);
// TODO:
// boolean deleteBlocks(PositionValueAccess pva, List<long[]> positions) throws N5IOException;


/**
*
* @param pva
* @param min
* min pixel coordinate of region to write
* @param size
* size in pixels of region to write
* @param blocks
* is asked to create blocks within the given region
* @param datasetDimensions
* @param writeFully
* if false, merge existing data in shards/blocks that overlap the region boundary. if true, override everything.
*
* @throws N5IOException
*/
void writeRegion(
PositionValueAccess pva,
long[] min,
long[] size,
DataBlockSupplier<T> blocks,
long[] datasetDimensions,
boolean writeFully
) throws N5IOException;

/**
*
* @param pva
* @param min
* min pixel coordinate of region to write
* @param size
* size in pixels of region to write
* @param blocks
* is asked to create blocks within the given region. must be thread-safe.
* @param datasetDimensions
* @param writeFully
* if false, merge existing data in shards/blocks that overlap the region boundary. if true, override everything.
* @param exec
* used to parallelize over blocks and shards
*
* @throws N5Exception
* @throws InterruptedException
* @throws ExecutionException
*/
void writeRegion(
PositionValueAccess pva,
long[] min,
long[] size,
DataBlockSupplier<T> blocks,
long[] datasetDimensions,
boolean writeFully,
ExecutorService exec
) throws N5Exception, InterruptedException, ExecutionException;

NestedGrid getGrid();

Expand All @@ -42,6 +103,7 @@ public interface DatasetAccess<T> {
* @param outerLevel of the outerLevel shard position to group by. must be in range {@code [1, NestedGrid.numLevels() - 1]}
* @return map of outerLevel shard positions to inner level block positions
*/
// TODO: move to Nesting
static <T extends NestedPosition> Collection<List<T>> groupInnerPositions(final NestedGrid grid, final List<T> innerPositions, final int outerLevel) {

if (outerLevel < 1 || outerLevel >= grid.numLevels())
Expand All @@ -56,7 +118,7 @@ static <T extends NestedPosition> Collection<List<T>> groupInnerPositions(final
if (nestedPosition.level() == outerLevel)
outerNestedPosition = nestedPosition;
else
outerNestedPosition = new NestedPosition(grid, nestedPosition.absolute(0), outerLevel);
outerNestedPosition = grid.nestedPosition(nestedPosition.absolute(outerLevel), outerLevel);


final List<T> blocks = blocksPerShard.computeIfAbsent(outerNestedPosition, it -> new ArrayList<>());
Expand Down
Loading