3939import org .janelia .saalfeldlab .n5 .N5FSTest ;
4040import org .janelia .saalfeldlab .n5 .N5KeyValueWriter ;
4141import org .janelia .saalfeldlab .n5 .N5Writer ;
42- import org .janelia .saalfeldlab .n5 .NameConfigAdapter ;
4342import org .janelia .saalfeldlab .n5 .RawCompression ;
4443import org .janelia .saalfeldlab .n5 .N5Exception .N5NoSuchKeyException ;
4544import org .janelia .saalfeldlab .n5 .GsonKeyValueN5Writer ;
46- import org .janelia .saalfeldlab .n5 .codec .CodecInfo ;
47- import org .janelia .saalfeldlab .n5 .codec .DataCodecInfo ;
48- import org .janelia .saalfeldlab .n5 .codec .N5BlockCodecInfo ;
49- import org .janelia .saalfeldlab .n5 .codec .RawBlockCodecInfo ;
45+ import org .janelia .saalfeldlab .n5 .codec .*;
5046import org .janelia .saalfeldlab .n5 .readdata .ReadData ;
5147import org .janelia .saalfeldlab .n5 .shard .ShardIndex .IndexLocation ;
5248import org .junit .After ;
5551import org .junit .runner .RunWith ;
5652import org .junit .runners .Parameterized ;
5753
58- import com .google .gson .Gson ;
5954import com .google .gson .GsonBuilder ;
6055
56+ import static org .junit .Assert .assertEquals ;
57+ import static org .junit .Assert .assertTrue ;
58+
6159import java .io .File ;
6260import java .io .IOException ;
6361import java .io .UncheckedIOException ;
7775import java .util .HashMap ;
7876import java .util .List ;
7977import java .util .Map ;
78+ import java .util .concurrent .atomic .AtomicInteger ;
79+ import java .util .function .Consumer ;
80+ import java .util .function .Function ;
81+ import java .util .function .Supplier ;
8082
8183@ RunWith (Parameterized .class )
8284public class ShardTest {
@@ -88,15 +90,15 @@ public class ShardTest {
8890 @ Override public N5Writer createTempN5Writer () {
8991
9092 if (LOCAL_DEBUG ) {
91- final N5Writer writer = new ShardedN5Writer ("src/test/resources/test.n5" );
93+ final N5Writer writer = new TrackingN5Writer ("src/test/resources/test.n5" );
9294 writer .remove ("" ); // Clear old when starting new test
9395 return writer ;
9496 }
9597
9698 final String basePath = new File (tempN5PathName ()).toURI ().normalize ().getPath ();
9799 try {
98100 String uri = new URI ("file" , null , basePath , null ).toString ();
99- return new ShardedN5Writer (uri );
101+ return new TrackingN5Writer (uri );
100102 } catch (URISyntaxException e ) {
101103 e .printStackTrace ();
102104 }
@@ -117,10 +119,6 @@ private String tempN5PathName() {
117119 }
118120 };
119121
120- public static GsonBuilder gsonBuilder () {
121- return new GsonBuilder ();
122- }
123-
124122 @ Parameterized .Parameters (name = "IndexLocation({0}), Index ByteOrder({1})" )
125123 public static Collection <Object []> data () {
126124
@@ -313,15 +311,17 @@ public void writeShardDataSizeTest() {
313311
314312 int numBlocksPerShard = 16 ;
315313 final int n5HeaderSizeBytes = 12 ; // 2 + 2 + 4*2
316- final DatasetAttributes datasetAttributes = getTestAttributes (
314+ final DatasetAttributes attrs = getTestAttributes (
317315 new long []{24 , 24 },
318316 new int []{8 , 8 },
319317 new int []{2 , 2 }
320318 );
321319
322320 final String dataset = "writeBlocksShardSize" ;
323321 writer .remove (dataset );
324- writer .createDataset (dataset , datasetAttributes );
322+ final DatasetAttributes datasetAttributes = writer .createDataset (dataset , attrs );
323+ assertTrue (datasetAttributes .isSharded ());
324+
325325 final KeyValueAccess kva = ((N5KeyValueWriter )writer ).getKeyValueAccess ();
326326
327327 final int [] blockSize = datasetAttributes .getBlockSize ();
@@ -438,7 +438,7 @@ public void writeReadBlockTest() {
438438 */
439439 public void numReadsTest () {
440440
441- final ShardedN5Writer writer = (ShardedN5Writer )tempN5Factory .createTempN5Writer ();
441+ final TrackingN5Writer writer = (TrackingN5Writer )tempN5Factory .createTempN5Writer ();
442442
443443 final DatasetAttributes datasetAttributes = getTestAttributes (
444444 new long []{24 , 24 },
@@ -491,54 +491,122 @@ public void numReadsTest() {
491491 System .out .println ("" );
492492 }
493493
494- /**
495- * An N5Writer that serializing the sharding codecs, enabling testing of
496- * shard functionality, despite the fact that the N5 format does not support
497- * sharding.
498- */
499- public static class ShardedN5Writer extends N5KeyValueWriter {
494+ @ Test
495+ public void shardExistsTest () {
500496
501- Gson gson ;
497+ final N5Writer writer = tempN5Factory . createTempN5Writer () ;
502498
503- public ShardedN5Writer (String basePath ) {
499+ final DatasetAttributes datasetAttributes = getTestAttributes (
500+ new long []{24 , 24 },
501+ new int []{8 , 8 },
502+ new int []{2 , 2 }
503+ );
504+
505+ final String dataset = "shardExists" ;
506+ writer .remove (dataset );
507+ writer .createDataset (dataset , datasetAttributes );
508+
509+ final int [] blockSize = datasetAttributes .getBlockSize ();
510+ final int numElements = blockSize [0 ] * blockSize [1 ];
504511
505- super ( new TrackingFileSystemKeyValueAccess (FileSystems .getDefault ()),
506- basePath , new GsonBuilder (), false );
512+ final byte [] data = new byte [numElements ];
513+ for (int i = 0 ; i < data .length ; i ++) {
514+ data [i ] = (byte )(i );
507515 }
508516
509- public ShardedN5Writer (String basePath , GsonBuilder gsonBuilder ) {
517+ /* write blocks to shards (0,0), (1,0), and (2,2) */
518+ writer .writeBlocks (
519+ dataset ,
520+ datasetAttributes ,
521+ new ByteArrayDataBlock (blockSize , new long []{0 , 0 }, data ), /* shard (0, 0) */
522+ new ByteArrayDataBlock (blockSize , new long []{4 , 0 }, data ), /* shard (1, 0) */
523+ new ByteArrayDataBlock (blockSize , new long []{11 , 11 }, data ) /* shard (2, 2) */
524+ );
525+
526+ TrackingN5Writer trackingWriter = ((TrackingN5Writer ) writer );
527+
528+ Function <long [], Boolean > assertShardExistsTracking = (gridPosition ) -> {
529+ trackingWriter .resetAllTracking ();
530+ final Boolean exists = writer .shardExists (dataset , datasetAttributes , gridPosition );
531+ assertEquals ("isFileCheck incremented" , 1 , trackingWriter .getNumIsFileCalls ());
532+ assertEquals ("No Bytes Read" , 0 , trackingWriter .getTotalBytesRead ());
533+ return exists ;
534+ };
535+
536+
537+ trackingWriter .resetAllTracking ();
538+ /* shards that should exist should only check file */
539+ Assert .assertTrue ("Shard (0,0) should exist" , assertShardExistsTracking .apply (new long []{0 , 0 }));
540+ Assert .assertTrue ("Shard (1,0) should exist" , assertShardExistsTracking .apply (new long []{1 , 0 }));
541+ Assert .assertTrue ("Shard (2,2) should exist" , assertShardExistsTracking .apply (new long []{2 , 2 }));
542+
543+ /* shards that should NOT exist */
544+ Assert .assertFalse ("Shard (0,1) should not exist" , assertShardExistsTracking .apply (new long []{0 , 1 }));
545+ Assert .assertFalse ("Shard (1,1) should not exist" , assertShardExistsTracking .apply (new long []{1 , 1 }));
546+ Assert .assertFalse ("Shard (2,0) should not exist" , assertShardExistsTracking .apply (new long []{2 , 0 }));
547+ Assert .assertFalse ("Shard (0,2) should not exist" , assertShardExistsTracking .apply (new long []{0 , 2 }));
548+ }
549+
550+ /**
551+ * An N5Writer that tracks the number of materialize calls performed by
552+ * its underlying key value access.
553+ */
554+ public static class TrackingN5Writer extends N5KeyValueWriter {
555+
556+ final TrackingFileSystemKeyValueAccess tkva ;
557+ public TrackingN5Writer (String basePath ) {
510558
511- this (basePath );
512- gsonBuilder .registerTypeAdapter (DataType .class , new DataType .JsonAdapter ());
513- gsonBuilder .registerTypeHierarchyAdapter (CodecInfo .class , NameConfigAdapter .getJsonAdapter (CodecInfo .class ));
514- gsonBuilder .registerTypeHierarchyAdapter (ByteOrder .class , RawBlockCodecInfo .byteOrderAdapter );
515- gsonBuilder .disableHtmlEscaping ();
516- gson = gsonBuilder .create ();
559+ super ( new TrackingFileSystemKeyValueAccess (FileSystems .getDefault ()), basePath , new GsonBuilder (), false );
560+ tkva = (TrackingFileSystemKeyValueAccess )getKeyValueAccess ();
517561 }
518562
519563 public void resetNumMaterializeCalls () {
520- (( TrackingFileSystemKeyValueAccess ) super . getKeyValueAccess ()) .numMaterializeCalls = 0 ;
564+ tkva .numMaterializeCalls = 0 ;
521565 }
522566
523567 public int getNumMaterializeCalls () {
524- return (( TrackingFileSystemKeyValueAccess ) super . getKeyValueAccess ()) .numMaterializeCalls ;
568+ return tkva .numMaterializeCalls ;
525569 }
526570
527- @ Override
528- public Gson getGson () {
529- // the super constructor needs the gson instance, unfortunately
530- return gson == null ? super .gson : gson ;
571+ public void resetNumIsFileCalls () {
572+ tkva .numIsFileCalls = 0 ;
573+ }
574+
575+ public int getNumIsFileCalls () {
576+ return tkva .numIsFileCalls ;
577+ }
578+
579+ public void resetTotalBytesRead () {
580+ tkva .totalBytesRead = 0 ;
581+ }
582+
583+ public long getTotalBytesRead () {
584+ return tkva .totalBytesRead ;
585+ }
586+
587+ public void resetAllTracking () {
588+ tkva .numMaterializeCalls = 0 ;
589+ tkva .numIsFileCalls = 0 ;
590+ tkva .totalBytesRead = 0 ;
531591 }
532592 }
533593
534594 private static class TrackingFileSystemKeyValueAccess extends FileSystemKeyValueAccess {
535595
536596 private int numMaterializeCalls = 0 ;
597+ private int numIsFileCalls = 0 ;
598+ private long totalBytesRead = 0 ;
537599
538600 protected TrackingFileSystemKeyValueAccess (FileSystem fileSystem ) {
539601 super (fileSystem );
540602 }
541603
604+ @ Override
605+ public boolean isFile (String normalPath ) {
606+ numIsFileCalls ++;
607+ return super .isFile (normalPath );
608+ }
609+
542610 @ Override
543611 public ReadData createReadData (final String normalPath ) {
544612 return new KeyValueAccessReadData (new TrackingFileLazyRead (normalPath ));
@@ -574,6 +642,7 @@ public ReadData materialize(final long offset, final long length) {
574642 throw new IndexOutOfBoundsException ();
575643
576644 final int sz = (int )(length < 0 ? channelSize : length );
645+ totalBytesRead += sz ;
577646 final byte [] data = new byte [sz ];
578647 final ByteBuffer buf = ByteBuffer .wrap (data );
579648 channel .read (buf );
0 commit comments