Пример #1
0
        // for later: H5EA__lookup_elmt

        private void ReadExtensibleArray(Span <byte> buffer, ulong chunkSize)
        {
            var chunkSizeLength = this.ComputeChunkSizeLength(chunkSize);
            var header          = new ExtensibleArrayHeader(this.Context.Reader, this.Context.Superblock, chunkSizeLength);
            var indexBlock      = header.IndexBlock;
            var elementIndex    = 0U;

            var elements = new List <DataBlockElement>()
                           .AsEnumerable();

            // elements
            elements = elements.Concat(indexBlock.Elements);

            // data blocks
            ReadDataBlocks(indexBlock.DataBlockAddresses);

            // secondary blocks
#warning Is there any precalculated way to avoid checking all addresses?
            var addresses = indexBlock
                            .SecondaryBlockAddresses
                            .Where(address => !this.Context.Superblock.IsUndefinedAddress(address));

            foreach (var secondaryBlockAddress in addresses)
            {
                this.Context.Reader.Seek((long)secondaryBlockAddress, SeekOrigin.Begin);
                var secondaryBlockIndex = header.ComputeSecondaryBlockIndex(elementIndex + header.IndexBlockElementsCount);
                var secondaryBlock      = new ExtensibleArraySecondaryBlock(this.Context.Reader, this.Context.Superblock, header, secondaryBlockIndex);
                ReadDataBlocks(secondaryBlock.DataBlockAddresses);
            }

            var offset = 0UL;

            foreach (var element in elements)
            {
                // if page/element is initialized (see also datablock.PageBitmap)
#warning Is there any precalculated way to avoid checking all addresses?
                if (element.Address > 0 && !this.Context.Superblock.IsUndefinedAddress(element.Address))
                {
                    this.SeekSliceAndReadChunk(offset, chunkSize, element.ChunkSize, element.Address, buffer);
                }

                offset += chunkSize;
            }

            void ReadDataBlocks(ulong[] dataBlockAddresses)
            {
#warning Is there any precalculated way to avoid checking all addresses?
                dataBlockAddresses = dataBlockAddresses
                                     .Where(address => !this.Context.Superblock.IsUndefinedAddress(address))
                                     .ToArray();

                foreach (var dataBlockAddress in dataBlockAddresses)
                {
                    this.Context.Reader.Seek((long)dataBlockAddress, SeekOrigin.Begin);
                    var newElements = this.ReadExtensibleArrayDataBlock(header, chunkSizeLength, elementIndex);
                    elements      = elements.Concat(newElements);
                    elementIndex += (uint)newElements.Length;
                }
            }
        }
        private T?LookupElement <T>(ulong index, Func <H5BinaryReader, T> decode) where T : DataBlockElement
        {
            // H5EA.c (H5EA__lookup_elmt)
            var chunkSizeLength = H5Utils.ComputeChunkSizeLength(this.ChunkByteSize);

            /* Check if we should create the index block */
            if (this.Dataset.Context.Superblock.IsUndefinedAddress(_header.IndexBlockAddress))
            {
                return(null);
            }

            /* Protect index block */
            if (_indexBlock is null)
            {
                this.Dataset.Context.Reader.Seek((long)_header.IndexBlockAddress, SeekOrigin.Begin);

                _indexBlock = new ExtensibleArrayIndexBlock <T>(
                    this.Dataset.Context.Reader,
                    this.Dataset.Context.Superblock,
                    _header,
                    decode);
            }

            var indexBlock = (ExtensibleArrayIndexBlock <T>)_indexBlock;

            /* Check if element is in index block */
            if (index < _header.IndexBlockElementsCount)
            {
                return(indexBlock.Elements[index]);
            }
            else
            {
                /* Get super block index where element is located */
                var secondaryBlockIndex = _header.ComputeSecondaryBlockIndex(index);

                /* Adjust index to offset in super block */
                var elementIndex = index - (_header.IndexBlockElementsCount + _header.SecondaryBlockInfos[secondaryBlockIndex].ElementStartIndex);

                /* Check for data block containing element address in the index block */
                if (secondaryBlockIndex < indexBlock.SecondaryBlockDataBlockAddressCount)
                {
                    /* Compute the data block index in index block */
                    var dataBlockIndex =
                        _header.SecondaryBlockInfos[secondaryBlockIndex].DataBlockStartIndex +
                        elementIndex / _header.SecondaryBlockInfos[secondaryBlockIndex].ElementsCount;

                    /* Check if the data block has been allocated on disk yet */
                    if (this.Dataset.Context.Superblock.IsUndefinedAddress(indexBlock.DataBlockAddresses[dataBlockIndex]))
                    {
                        return(null);
                    }

                    /* Protect data block */
                    this.Dataset.Context.Reader.Seek((long)indexBlock.DataBlockAddresses[dataBlockIndex], SeekOrigin.Begin);
                    var elementsCount = _header.SecondaryBlockInfos[secondaryBlockIndex].ElementsCount;

                    var dataBlock = new ExtensibleArrayDataBlock <T>(
                        this.Dataset.Context.Reader,
                        this.Dataset.Context.Superblock,
                        _header,
                        elementsCount,
                        decode);

                    /* Adjust index to offset in data block */
                    elementIndex %= _header.SecondaryBlockInfos[secondaryBlockIndex].ElementsCount;

                    /* Set 'thing' info to refer to the data block */
                    return(dataBlock.Elements[elementIndex]);
                }
                else
                {
                    /* Calculate offset of super block in index block's array */
                    var secondaryBlockOffset = secondaryBlockIndex - indexBlock.SecondaryBlockDataBlockAddressCount;

                    /* Check if the super block has been allocated on disk yet */
                    if (this.Dataset.Context.Superblock.IsUndefinedAddress(indexBlock.SecondaryBlockAddresses[secondaryBlockOffset]))
                    {
                        return(null);
                    }

                    /* Protect super block */
                    this.Dataset.Context.Reader.Seek((long)indexBlock.SecondaryBlockAddresses[secondaryBlockOffset], SeekOrigin.Begin);

                    var secondaryBlock = new ExtensibleArraySecondaryBlock(
                        this.Dataset.Context.Reader,
                        this.Dataset.Context.Superblock,
                        _header,
                        secondaryBlockIndex);

                    /* Compute the data block index in super block */
                    var dataBlockIndex = elementIndex / secondaryBlock.ElementCount;

                    /* Check if the data block has been allocated on disk yet */
                    if (this.Dataset.Context.Superblock.IsUndefinedAddress(secondaryBlock.DataBlockAddresses[dataBlockIndex]))
                    {
                        return(null);
                    }

                    /* Adjust index to offset in data block */
                    elementIndex %= secondaryBlock.ElementCount;

                    /* Check if the data block is paged */
                    if (secondaryBlock.DataBlockPageCount > 0)
                    {
                        /* Compute page index */
                        var pageIndex = elementIndex / _header.DataBlockPageElementsCount;

                        /* Compute 'page init' index */
                        var pageInitIndex = dataBlockIndex * secondaryBlock.DataBlockPageCount + pageIndex;

                        /* Adjust index to offset in data block page */
                        elementIndex %= _header.DataBlockPageElementsCount;

                        /* Compute data block page address */
                        var dataBlockPrefixSize =
                            // H5EA_METADATA_PREFIX_SIZE
                            4UL + 1UL + 1UL + 4UL +
                            // H5EA_DBLOCK_PREFIX_SIZE
                            this.Dataset.Context.Superblock.OffsetsSize + _header.ArrayOffsetsSize +
                            // H5EA_DBLOCK_SIZE
                            secondaryBlock.ElementCount * _header.ElementSize +    /* Elements in data block */
                            secondaryBlock.DataBlockPageCount * 4;                 /* Checksum for each page */

                        var dataBlockPageAddress = secondaryBlock.DataBlockAddresses[dataBlockIndex] + dataBlockPrefixSize +
                                                   (pageIndex * secondaryBlock.DataBlockPageSize);

                        /* Check if page has been initialized yet */
                        var pageBitmapEntry = secondaryBlock.PageBitmap[pageIndex / 8];
                        var bitMaskIndex    = (int)pageIndex % 8;

                        if ((pageBitmapEntry & H5Utils.SequentialBitMask[bitMaskIndex]) == 0)
                        {
                            return(null);
                        }

                        /* Protect data block page */
                        this.Dataset.Context.Reader.Seek((long)dataBlockPageAddress, SeekOrigin.Begin);

                        var dataBlockPage = new DataBlockPage <T>(
                            this.Dataset.Context.Reader,
                            _header.DataBlockPageElementsCount,
                            decode);

                        /* Set 'thing' info to refer to the data block page */
                        return(dataBlockPage.Elements[elementIndex]);
                    }
                    else
                    {
                        /* Protect data block */
                        this.Dataset.Context.Reader.Seek((long)secondaryBlock.DataBlockAddresses[dataBlockIndex], SeekOrigin.Begin);

                        var dataBlock = new ExtensibleArrayDataBlock <T>(
                            this.Dataset.Context.Reader,
                            this.Dataset.Context.Superblock,
                            _header,
                            secondaryBlock.ElementCount,
                            decode);

                        /* Set 'thing' info to refer to the data block */
                        return(dataBlock.Elements[elementIndex]);
                    }
                }
            }
        }