@@ -334,100 +334,142 @@ private static Block readDirectBlock(SeekableByteChannel channel, FractalHeapHea
334334 return db ;
335335 }
336336
337- private static Block readIndirectBlock (SeekableByteChannel channel , FractalHeapHeader header , FixedPointDatatype sizeOfOffset , FixedPointDatatype sizeOfLength , HdfFixedPoint address , long expectedBlockOffset , long iblockSize , int passedNrows ) throws IOException , InvocationTargetException , InstantiationException , IllegalAccessException {
338- if (address .isUndefined ()) {
339- throw new IOException ("Invalid indirect block address" );
337+ //<editor-fold desc="Refactored readIndirectBlock Helper Methods">
338+ private static int calculateNrows (FractalHeapHeader header , long iblockSize , int passedNrows ) throws InvocationTargetException , InstantiationException , IllegalAccessException , IOException {
339+ if (iblockSize <= 0 ) {
340+ return passedNrows ;
340341 }
341- channel .position (address .getInstance (Long .class ));
342- IndirectBlock ib = new IndirectBlock ();
343- int nrows ;
342+
344343 long startingBlockSize = header .startingBlockSize .getInstance (Long .class );
345- if (iblockSize > 0 ) {
346- long covered = 0 ;
347- long current = startingBlockSize ;
348- int nr = 0 ;
349- while (covered < iblockSize ) {
350- covered += (long ) header .tableWidth * current ;
351- current *= 2 ;
352- nr ++;
353- }
354- nrows = (short ) nr ;
355- } else {
356- nrows = passedNrows ;
357- }
358- int plusSize = 0 ;
359- ib .nrows = nrows ;
344+ long covered = 0 ;
345+ long current = startingBlockSize ;
346+ int nr = 0 ;
347+ while (covered < iblockSize ) {
348+ covered += (long ) header .tableWidth * current ;
349+ current *= 2 ;
350+ nr ++;
351+ }
352+ return nr ;
353+ }
354+
355+ private static int calculateChildrenEntriesSize (FractalHeapHeader header , int nrows , FixedPointDatatype sizeOfOffset , FixedPointDatatype sizeOfLength ) {
356+ int entriesSize = 0 ;
360357 for (short r = 0 ; r < nrows ; r ++) {
361358 for (int c = 0 ; c < header .tableWidth ; c ++) {
362- plusSize += sizeOfOffset .getSize ();
359+ entriesSize += sizeOfOffset .getSize ();
363360 boolean isDirect = r < header .maxDblockRows ;
364361 if (header .hasFilters && isDirect ) {
365- plusSize += sizeOfLength .getSize ();
366- plusSize += 4 ;
362+ entriesSize += sizeOfLength .getSize ();
363+ entriesSize += 4 ; // filter mask
367364 }
368365 }
369366 }
370- plusSize += 4 ; // checksum
371-
372- int headerSize = 4 + 1 + sizeOfOffset .getSize () + header .offsetBytes .getSize () + plusSize ;
373- ByteBuffer headerBuffer = ByteBuffer .allocate (headerSize ).order (ByteOrder .LITTLE_ENDIAN );
374- int bytesRead = channel .read (headerBuffer );
375- if ( headerSize != bytesRead )
376- throw new IllegalStateException ("Incorrect bytesRead: " + bytesRead + ": expected " + headerSize );
377- headerBuffer .flip ();
367+ return entriesSize ;
368+ }
378369
379- String sig = new String (Arrays .copyOfRange (headerBuffer .array (), 0 , 4 ), StandardCharsets .US_ASCII );
380- if (!Objects .equals (sig , "FHIB" )) {
381- throw new IOException ("Invalid indirect block signature" );
370+ private static void readAndVerifyIndirectBlockHeader (ByteBuffer blockBuffer , long expectedBlockOffset , FixedPointDatatype sizeOfOffset , FixedPointDatatype offsetBytes ) throws IOException , InvocationTargetException , InstantiationException , IllegalAccessException {
371+ byte [] signatureBytes = new byte [4 ];
372+ blockBuffer .get (signatureBytes );
373+ String sig = new String (signatureBytes , StandardCharsets .US_ASCII );
374+ if (!"FHIB" .equals (sig )) {
375+ throw new IOException ("Invalid indirect block signature: " + sig );
382376 }
383- headerBuffer . position ( 4 );
384- byte version = headerBuffer .get ();
377+
378+ byte version = blockBuffer .get ();
385379 if (version != 0 ) {
386- throw new IOException ("Unsupported version" );
380+ throw new IOException ("Unsupported version: " + version );
387381 }
388- HdfFixedPoint heapHeader = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfOffset , headerBuffer );
382+
383+ HdfFixedPoint heapHeader = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfOffset , blockBuffer );
389384 if (heapHeader .isUndefined ()) {
390385 throw new IOException ("Invalid heap header address in indirect block" );
391386 }
392- HdfFixedPoint blockOffset = HdfReadUtils .readHdfFixedPointFromBuffer (header .offsetBytes , headerBuffer );
387+
388+ HdfFixedPoint blockOffset = HdfReadUtils .readHdfFixedPointFromBuffer (offsetBytes , blockBuffer );
393389 if (blockOffset .getInstance (Long .class ) != expectedBlockOffset ) {
394390 throw new IOException ("Block offset mismatch" );
395391 }
396- headerBuffer . position ( 4 + 1 + sizeOfOffset . getSize () + header . offsetBytes . getSize ());
397- ib . blockOffset = blockOffset . getInstance ( Long . class );
398- ib . children = new ArrayList <>();
392+ }
393+
394+ private static List < ChildInfo > parseChildInfos ( ByteBuffer blockBuffer , FractalHeapHeader header , int nrows , long startOffset , FixedPointDatatype sizeOfOffset , FixedPointDatatype sizeOfLength ) throws InvocationTargetException , InstantiationException , IllegalAccessException , IOException {
399395 List <ChildInfo > childInfos = new ArrayList <>();
400- long currentOffset = expectedBlockOffset ; // expectedBlockOffset;
396+ long currentOffset = startOffset ;
397+ long startingBlockSize = header .startingBlockSize .getInstance (Long .class );
398+
401399 for (short r = 0 ; r < nrows ; r ++) {
402400 long rowBlockSize = startingBlockSize * (1L << r );
403401 for (int c = 0 ; c < header .tableWidth ; c ++) {
404- HdfFixedPoint childAddress = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfOffset , headerBuffer );
402+ HdfFixedPoint childAddress = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfOffset , blockBuffer );
405403 HdfFixedPoint childFilteredSize = sizeOfOffset .undefined ();
406404 long childFilterMask = 0 ;
405+
407406 boolean isDirect = r < header .maxDblockRows ;
408407 if (header .hasFilters && isDirect ) {
409- childFilteredSize = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfLength , headerBuffer );
410- childFilterMask = headerBuffer . getInt ();
408+ childFilteredSize = HdfReadUtils .readHdfFixedPointFromBuffer (sizeOfLength , blockBuffer );
409+ childFilterMask = Integer . toUnsignedLong ( blockBuffer . getInt () );
411410 }
411+
412412 if (!childAddress .isUndefined ()) {
413- ChildInfo info = new ChildInfo (childAddress , currentOffset , isDirect , childFilteredSize , childFilterMask , rowBlockSize );
414- childInfos .add (info );
413+ childInfos .add (new ChildInfo (childAddress , currentOffset , isDirect , childFilteredSize , childFilterMask , rowBlockSize ));
415414 }
416415 currentOffset += rowBlockSize ;
417416 }
418417 }
419- ib .checksum = Integer .toUnsignedLong (headerBuffer .getInt ());
418+ return childInfos ;
419+ }
420+
421+ private static List <Block > readChildren (SeekableByteChannel channel , FractalHeapHeader header , List <ChildInfo > childInfos , FixedPointDatatype sizeOfOffset , FixedPointDatatype sizeOfLength ) throws IOException , InvocationTargetException , InstantiationException , IllegalAccessException {
422+ List <Block > children = new ArrayList <>();
420423 for (ChildInfo info : childInfos ) {
421- if (!info .address .isUndefined ()) {
422- Block child ;
423- if (info .isDirect ) {
424- child = readDirectBlock (channel , header , info .address , sizeOfOffset , info .blockOffset , info .filteredSize , info .filterMask );
425- } else {
426- child = readIndirectBlock (channel , header , sizeOfOffset , sizeOfLength , info .address , info .blockOffset , info .blockSize , (short ) 0 );
427- }
428- ib .children .add (child );
424+ Block child ;
425+ if (info .isDirect ) {
426+ child = readDirectBlock (channel , header , info .address , sizeOfOffset , info .blockOffset , info .filteredSize , info .filterMask );
427+ } else {
428+ child = readIndirectBlock (channel , header , sizeOfOffset , sizeOfLength , info .address , info .blockOffset , info .blockSize , 0 );
429429 }
430+ children .add (child );
431+ }
432+ return children ;
433+ }
434+ //</editor-fold>
435+
436+ private static Block readIndirectBlock (SeekableByteChannel channel , FractalHeapHeader header , FixedPointDatatype sizeOfOffset , FixedPointDatatype sizeOfLength , HdfFixedPoint address , long expectedBlockOffset , long iblockSize , int passedNrows ) throws IOException , InvocationTargetException , InstantiationException , IllegalAccessException {
437+ if (address .isUndefined ()) {
438+ throw new IOException ("Invalid indirect block address" );
439+ }
440+ channel .position (address .getInstance (Long .class ));
441+
442+ // 1. Determine the number of rows in this indirect block.
443+ int nrows = calculateNrows (header , iblockSize , passedNrows );
444+
445+ // 2. Calculate the total size of the child entries section.
446+ int childrenEntriesSize = calculateChildrenEntriesSize (header , nrows , sizeOfOffset , sizeOfLength );
447+
448+ // 3. Read the entire block's header, entries, and checksum into a buffer.
449+ int headerPortionSize = 4 + 1 + sizeOfOffset .getSize () + header .offsetBytes .getSize (); // sig+ver+heapAddr+blockOffset
450+ int totalSizeToRead = headerPortionSize + childrenEntriesSize + 4 ; // 4 for checksum
451+ ByteBuffer blockBuffer = ByteBuffer .allocate (totalSizeToRead ).order (ByteOrder .LITTLE_ENDIAN );
452+ int bytesRead = channel .read (blockBuffer );
453+ if (totalSizeToRead != bytesRead ) {
454+ throw new IllegalStateException ("Incorrect bytesRead: " + bytesRead + ": expected " + totalSizeToRead );
430455 }
456+ blockBuffer .flip ();
457+
458+ // 4. Verify the block's header fields. The buffer position is advanced past the header.
459+ readAndVerifyIndirectBlockHeader (blockBuffer , expectedBlockOffset , sizeOfOffset , header .offsetBytes );
460+
461+ // 5. Parse child information from the buffer. The buffer position is advanced past the entries.
462+ List <ChildInfo > childInfos = parseChildInfos (blockBuffer , header , nrows , expectedBlockOffset , sizeOfOffset , sizeOfLength );
463+
464+ // 6. Create the block object and read the checksum from the end of the buffer.
465+ IndirectBlock ib = new IndirectBlock ();
466+ ib .nrows = nrows ;
467+ ib .blockOffset = expectedBlockOffset ;
468+ ib .checksum = Integer .toUnsignedLong (blockBuffer .getInt ());
469+
470+ // 7. Recursively read all children based on the parsed info.
471+ ib .children = readChildren (channel , header , childInfos , sizeOfOffset , sizeOfLength );
472+
431473 return ib ;
432474 }
433475
0 commit comments