long getIndexEntry ( SubFileParameter subFileParameter , long blockNumber ) throws IOException { // check if the block number is out of bounds if ( blockNumber >= subFileParameter . numberOfBlocks ) { throw new IOException ( "invalid block number: " + blockNumber ) ; } // calculate the index block number long indexBlockNumber = blockNumber / INDEX_ENTRIES_PER_BLOCK ; // create the cache entry key for this request IndexCacheEntryKey indexCacheEntryKey = new IndexCacheEntryKey ( subFileParameter , indexBlockNumber ) ; // check for cached index block byte [ ] indexBlock = this . map . get ( indexCacheEntryKey ) ; if ( indexBlock == null ) { // cache miss, seek to the correct index block in the file and read it long indexBlockPosition = subFileParameter . indexStartAddress + indexBlockNumber * SIZE_OF_INDEX_BLOCK ; int remainingIndexSize = ( int ) ( subFileParameter . indexEndAddress - indexBlockPosition ) ; int indexBlockSize = Math . min ( SIZE_OF_INDEX_BLOCK , remainingIndexSize ) ; indexBlock = new byte [ indexBlockSize ] ; ByteBuffer indexBlockWrapper = ByteBuffer . wrap ( indexBlock , 0 , indexBlockSize ) ; synchronized ( this . fileChannel ) { this . fileChannel . position ( indexBlockPosition ) ; if ( this . fileChannel . read ( indexBlockWrapper ) != indexBlockSize ) { throw new IOException ( "could not read index block with size: " + indexBlockSize ) ; } } // put the index block in the map this . map . put ( indexCacheEntryKey , indexBlock ) ; } // calculate the address of the index entry inside the index block long indexEntryInBlock = blockNumber % INDEX_ENTRIES_PER_BLOCK ; int addressInIndexBlock = ( int ) ( indexEntryInBlock * SubFileParameter . BYTES_PER_INDEX_ENTRY ) ; // return the real index entry return Deserializer . getFiveBytesLong ( indexBlock , addressInIndexBlock ) ; }
Returns the index entry of a block in the given map file . If the required index entry is not cached it will be read from the map file index and put in the cache .