Skip to content

Commit 98c25d5

Browse files
authored
Merge pull request #2 from scalableminds/test-zarrita-compatibility
Tests for zarrita compatibility
2 parents 850de50 + 39ffce5 commit 98c25d5

34 files changed

+1103
-431
lines changed

.github/workflows/ci.yml

+19-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: CI
22

33
on:
4+
workflow_dispatch:
45
push:
56
branches: [ "main" ]
67
pull_request:
@@ -10,29 +11,41 @@ jobs:
1011
build:
1112
strategy:
1213
matrix:
13-
os: [ ubuntu, windows, macos ]
14-
runs-on: ${{ matrix.os }}-latest
14+
os: [ ubuntu-latest, windows-latest, macos-latest ]
15+
fail-fast: false
16+
runs-on: ${{ matrix.os }}
1517
defaults:
1618
run:
1719
shell: bash
1820

1921
steps:
2022
- uses: actions/checkout@v3
23+
2124
- name: Set up JDK
2225
uses: actions/setup-java@v3
2326
with:
24-
java-version: '8'
27+
java-version: '22'
2528
distribution: 'temurin'
2629
cache: maven
2730

31+
- name: Set up Python
32+
uses: actions/setup-python@v4
33+
with:
34+
python-version: '3.11'
35+
36+
- name: Install zarrita
37+
run: |
38+
python -m venv venv_zarrita
39+
if [ "${{ runner.os }}" = "Windows" ]; then venv_zarrita/Scripts/pip install zarrita; else venv_zarrita/bin/pip install zarrita; fi
40+
2841
- name: Download blosc jar
2942
run: |
3043
mkdir -p ../blosc-java/target
3144
curl https://static.webknossos.org/misc/blosc-java-0.1-1.21.4-SNAPSHOT.jar -o ../blosc-java/target/blosc-java-0.1-1.21.4-SNAPSHOT.jar
3245
3346
- name: Download testdata
3447
run: |
35-
mkdir testdata testoutput
48+
mkdir testoutput
3649
curl https://static.webknossos.org/data/zarr_v3/l4_sample.zip -o testdata/l4_sample.zip
3750
cd testdata
3851
unzip l4_sample.zip
@@ -43,12 +56,12 @@ jobs:
4356
- name: Test
4457
env:
4558
MAVEN_OPTS: "-Xmx6g"
46-
run: mvn test -DargLine="-Xmx6g"
59+
run: mvn --no-transfer-progress test -DargLine="-Xmx6g"
4760

4861
- name: Assemble JAR
4962
run: mvn package -DskipTests
5063

5164
- uses: actions/upload-artifact@v3
5265
with:
5366
name: jar
54-
path: target/*.jar
67+
path: target/*.jar

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@ build/
3636

3737

3838
### Custom ###
39-
/testdata
39+
/testdata/l4_sample
4040
/testoutput
41+
/venv_zarrita

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,19 @@ array.write(
3838
ucar.ma2.Array.factory(ucar.ma2.DataType.UINT, new int[]{1, 1024, 1024, 1024})
3939
);
4040
```
41+
## Development Start-Guide
42+
43+
### Run Tests Locally
44+
To be able to run the tests locally, make sure to have `python3.11` installed.
45+
Also, you need to set up a venv for zarrita at the root of the project:
46+
`python3.11 -m venv venv_zarrita`.
47+
48+
Then install zarrita there with `venv_zarrita/Scripts/pip install zarrita`
49+
for Windows and `venv_zarrita/bin/pip install zarrita` for Linux.
50+
51+
Furthermore, you will need the `l4_sample` test data:
52+
53+
`curl https://static.webknossos.org/data/zarr_v3/l4_sample.zip -o testdata/l4_sample.zip
54+
&& cd testdata
55+
&& unzip l4_sample.zip
56+
`

pom.xml

+36-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,31 @@
1616
<aws.version>1.12.477</aws.version>
1717
<netcdfJavaVersion>5.5.3</netcdfJavaVersion>
1818
<zstdVersion>1.5.5-5</zstdVersion>
19+
<junit-jupiter-version>5.10.2</junit-jupiter-version>
1920
</properties>
2021

2122
<dependencies>
23+
<!-- JUnit 5 dependencies -->
24+
<dependency>
25+
<groupId>org.junit.jupiter</groupId>
26+
<artifactId>junit-jupiter-api</artifactId>
27+
<version>${junit-jupiter-version}</version>
28+
<scope>test</scope>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.junit.jupiter</groupId>
32+
<artifactId>junit-jupiter-engine</artifactId>
33+
<version>${junit-jupiter-version}</version>
34+
<scope>test</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.junit.jupiter</groupId>
38+
<artifactId>junit-jupiter-params</artifactId>
39+
<version>${junit-jupiter-version}</version>
40+
<scope>test</scope>
41+
</dependency>
42+
43+
<!-- Other dependencies -->
2244
<dependency>
2345
<groupId>com.fasterxml.jackson.core</groupId>
2446
<artifactId>jackson-databind</artifactId>
@@ -54,6 +76,7 @@
5476
<artifactId>okhttp</artifactId>
5577
<version>2.7.5</version>
5678
</dependency>
79+
<!-- JUnit 4 dependency for backward compatibility if needed -->
5780
<dependency>
5881
<groupId>junit</groupId>
5982
<artifactId>junit</artifactId>
@@ -70,4 +93,16 @@
7093
</repository>
7194
</repositories>
7295

73-
</project>
96+
<build>
97+
<plugins>
98+
<plugin>
99+
<groupId>org.apache.maven.plugins</groupId>
100+
<artifactId>maven-surefire-plugin</artifactId>
101+
<version>3.2.5</version>
102+
<configuration>
103+
<useSystemClassLoader>false</useSystemClassLoader>
104+
</configuration>
105+
</plugin>
106+
</plugins>
107+
</build>
108+
</project>

src/main/java/dev/zarr/zarrjava/utils/Utils.java

+20
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,24 @@ public static <T> T[] concatArrays(T[] array1, T[]... arrays) {
7777
}
7878
return result;
7979
}
80+
81+
public static boolean isPermutation(int[] array) {
82+
if (array.length==0){
83+
return false;
84+
}
85+
int[] arange = new int[array.length];
86+
Arrays.setAll(arange, i -> i);
87+
int[] orderSorted = array.clone();
88+
Arrays.sort(orderSorted);
89+
return Arrays.equals(orderSorted, arange);
90+
}
91+
92+
public static int[] inversePermutation(int[] origin){
93+
assert isPermutation(origin);
94+
int[] inverse = new int[origin.length];
95+
for (int i = 0; i < origin.length; i++) {
96+
inverse[origin[i]] = i;
97+
}
98+
return inverse;
99+
}
80100
}

src/main/java/dev/zarr/zarrjava/v3/Array.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected Array(StoreHandle storeHandle, ArrayMetadata arrayMetadata)
2727
throws IOException, ZarrException {
2828
super(storeHandle);
2929
this.metadata = arrayMetadata;
30-
this.codecPipeline = new CodecPipeline(arrayMetadata.codecs);
30+
this.codecPipeline = new CodecPipeline(arrayMetadata.codecs, arrayMetadata.coreArrayMetadata);
3131
}
3232

3333
/**
@@ -171,8 +171,7 @@ public ucar.ma2.Array read(final long[] offset, final int[] shape) throws ZarrEx
171171

172172
if (codecPipeline.supportsPartialDecode()) {
173173
final ucar.ma2.Array chunkArray = codecPipeline.decodePartial(chunkHandle,
174-
Utils.toLongArray(chunkProjection.chunkOffset), chunkProjection.shape,
175-
metadata.coreArrayMetadata);
174+
Utils.toLongArray(chunkProjection.chunkOffset), chunkProjection.shape);
176175
MultiArrayUtils.copyRegion(chunkArray, new int[metadata.ndim()], outputArray,
177176
chunkProjection.outOffset, chunkProjection.shape
178177
);
@@ -223,7 +222,7 @@ public ucar.ma2.Array readChunk(long[] chunkCoords)
223222
return metadata.allocateFillValueChunk();
224223
}
225224

226-
return codecPipeline.decode(chunkBytes, metadata.coreArrayMetadata);
225+
return codecPipeline.decode(chunkBytes);
227226
}
228227

229228
/**
@@ -299,7 +298,7 @@ public void writeChunk(long[] chunkCoords, ucar.ma2.Array chunkArray) throws Zar
299298
if (MultiArrayUtils.allValuesEqual(chunkArray, metadata.parsedFillValue)) {
300299
chunkHandle.delete();
301300
} else {
302-
ByteBuffer chunkBytes = codecPipeline.encode(chunkArray, metadata.coreArrayMetadata);
301+
ByteBuffer chunkBytes = codecPipeline.encode(chunkArray);
303302
chunkHandle.set(chunkBytes);
304303
}
305304
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package dev.zarr.zarrjava.v3.codec;
22

33
import dev.zarr.zarrjava.ZarrException;
4-
import dev.zarr.zarrjava.v3.ArrayMetadata.CoreArrayMetadata;
54
import ucar.ma2.Array;
65

7-
public interface ArrayArrayCodec extends Codec {
6+
public abstract class ArrayArrayCodec extends Codec {
87

9-
Array encode(Array chunkArray, CoreArrayMetadata arrayMetadata)
8+
protected abstract Array encode(Array chunkArray)
109
throws ZarrException;
1110

12-
Array decode(Array chunkArray, CoreArrayMetadata arrayMetadata)
11+
protected abstract Array decode(Array chunkArray)
1312
throws ZarrException;
1413

1514
}

src/main/java/dev/zarr/zarrjava/v3/codec/ArrayBytesCodec.java

+9-8
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22

33
import dev.zarr.zarrjava.ZarrException;
44
import dev.zarr.zarrjava.store.StoreHandle;
5-
import dev.zarr.zarrjava.v3.ArrayMetadata.CoreArrayMetadata;
65
import java.nio.ByteBuffer;
76
import ucar.ma2.Array;
87

9-
public interface ArrayBytesCodec extends Codec {
8+
public abstract class ArrayBytesCodec extends Codec {
109

11-
ByteBuffer encode(Array chunkArray, CoreArrayMetadata arrayMetadata)
10+
protected abstract ByteBuffer encode(Array chunkArray)
1211
throws ZarrException;
1312

14-
Array decode(ByteBuffer chunkBytes, CoreArrayMetadata arrayMetadata)
13+
protected abstract Array decode(ByteBuffer chunkBytes)
1514
throws ZarrException;
1615

17-
interface WithPartialDecode extends ArrayBytesCodec {
16+
public abstract static class WithPartialDecode extends ArrayBytesCodec {
1817

19-
Array decodePartial(
20-
StoreHandle handle, long[] offset, int[] shape,
21-
CoreArrayMetadata arrayMetadata
18+
public abstract Array decode(ByteBuffer shardBytes) throws ZarrException;
19+
public abstract ByteBuffer encode(Array shardArray) throws ZarrException;
20+
21+
protected abstract Array decodePartial(
22+
StoreHandle handle, long[] offset, int[] shape
2223
) throws ZarrException;
2324
}
2425
}
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package dev.zarr.zarrjava.v3.codec;
22

33
import dev.zarr.zarrjava.ZarrException;
4-
import dev.zarr.zarrjava.v3.ArrayMetadata.CoreArrayMetadata;
4+
55
import java.nio.ByteBuffer;
66

7-
public interface BytesBytesCodec extends Codec {
7+
public abstract class BytesBytesCodec extends Codec {
88

9-
ByteBuffer encode(ByteBuffer chunkBytes, CoreArrayMetadata arrayMetadata)
10-
throws ZarrException;
9+
protected abstract ByteBuffer encode(ByteBuffer chunkBytes) throws ZarrException;
1110

12-
ByteBuffer decode(ByteBuffer chunkBytes, CoreArrayMetadata arrayMetadata)
13-
throws ZarrException;
11+
public abstract ByteBuffer decode(ByteBuffer chunkBytes) throws ZarrException;
1412

1513
}

src/main/java/dev/zarr/zarrjava/v3/codec/Codec.java

+16-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,22 @@
55
import dev.zarr.zarrjava.v3.ArrayMetadata;
66

77
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "name")
8-
public interface Codec {
8+
public abstract class Codec {
99

10-
long computeEncodedSize(long inputByteLength, ArrayMetadata.CoreArrayMetadata arrayMetadata)
11-
throws ZarrException;
10+
protected ArrayMetadata.CoreArrayMetadata arrayMetadata;
11+
12+
protected ArrayMetadata.CoreArrayMetadata resolveArrayMetadata() throws ZarrException {
13+
if (arrayMetadata == null) {
14+
throw new ZarrException("arrayMetadata needs to get set in for every codec");
15+
}
16+
return this.arrayMetadata;
17+
}
18+
19+
protected abstract long computeEncodedSize(long inputByteLength, ArrayMetadata.CoreArrayMetadata arrayMetadata)
20+
throws ZarrException;
21+
22+
public void setCoreArrayMetadata(ArrayMetadata.CoreArrayMetadata arrayMetadata) throws ZarrException{
23+
this.arrayMetadata = arrayMetadata;
24+
}
1225
}
1326

src/main/java/dev/zarr/zarrjava/v3/codec/CodecBuilder.java

+23-13
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ public CodecBuilder withBlosc(
4141
}
4242

4343
public CodecBuilder withBlosc(String cname, String shuffle, int clevel, int blockSize) {
44+
if (shuffle.equals("shuffle")){
45+
shuffle = "byteshuffle";
46+
}
4447
return withBlosc(Blosc.Compressor.fromString(cname), Blosc.Shuffle.fromString(shuffle), clevel,
4548
dataType.getByteCount(), blockSize
4649
);
@@ -62,13 +65,9 @@ public CodecBuilder withBlosc() {
6265
return withBlosc("zstd");
6366
}
6467

65-
public CodecBuilder withTranspose(String order) {
66-
try {
68+
public CodecBuilder withTranspose(int[] order) {
6769
codecs.add(new TransposeCodec(new TransposeCodec.Configuration(order)));
68-
} catch (ZarrException e) {
69-
throw new RuntimeException(e);
70-
}
71-
return this;
70+
return this;
7271
}
7372

7473
public CodecBuilder withBytes(Endian endian) {
@@ -113,29 +112,40 @@ public CodecBuilder withZstd(int clevel) {
113112
public CodecBuilder withSharding(int[] chunkShape) {
114113
try {
115114
codecs.add(
116-
new ShardingIndexedCodec(new ShardingIndexedCodec.Configuration(chunkShape,
117-
new Codec[]{new BytesCodec(new Configuration(Endian.LITTLE))},
118-
new Codec[]{new BytesCodec(new Configuration(Endian.LITTLE)), new Crc32cCodec()})));
115+
new ShardingIndexedCodec(new ShardingIndexedCodec.Configuration(chunkShape,
116+
new Codec[]{new BytesCodec(new Configuration(Endian.LITTLE))},
117+
new Codec[]{new BytesCodec(new Configuration(Endian.LITTLE)), new Crc32cCodec()},
118+
"end")));
119119
} catch (ZarrException e) {
120120
throw new RuntimeException(e);
121121
}
122122
return this;
123123
}
124124

125125
public CodecBuilder withSharding(int[] chunkShape,
126-
Function<CodecBuilder, CodecBuilder> codecBuilder) {
126+
Function<CodecBuilder, CodecBuilder> codecBuilder) {
127+
return withSharding(chunkShape, codecBuilder, "end");
128+
}
129+
130+
public CodecBuilder withSharding(int[] chunkShape,
131+
Function<CodecBuilder, CodecBuilder> codecBuilder, String indexLocation) {
127132
CodecBuilder nestedBuilder = new CodecBuilder(dataType);
128133
try {
129134
codecs.add(new ShardingIndexedCodec(
130-
new ShardingIndexedCodec.Configuration(chunkShape,
131-
codecBuilder.apply(nestedBuilder).build(),
132-
new Codec[]{new BytesCodec(Endian.LITTLE), new Crc32cCodec()})));
135+
new ShardingIndexedCodec.Configuration(chunkShape,
136+
codecBuilder.apply(nestedBuilder).build(),
137+
new Codec[]{new BytesCodec(Endian.LITTLE), new Crc32cCodec()},
138+
indexLocation)));
133139
} catch (ZarrException e) {
134140
throw new RuntimeException(e);
135141
}
136142
return this;
137143
}
138144

145+
public CodecBuilder withCrc32c() {
146+
codecs.add(new Crc32cCodec());
147+
return this;
148+
}
139149
private void autoInsertBytesCodec() {
140150
if (codecs.stream().noneMatch(c -> c instanceof ArrayBytesCodec)) {
141151
Codec[] arrayArrayCodecs = codecs.stream().filter(c -> c instanceof ArrayArrayCodec)

0 commit comments

Comments
 (0)