github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/index/bloom_read.go (about)

     1  package index
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"unsafe"
     9  
    10  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/base"
    11  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/config"
    12  	"github.com/TrueBlocks/trueblocks-core/src/apps/chifra/pkg/file"
    13  )
    14  
    15  // Read reads the entire contents of the bloom filter
    16  func (bl *Bloom) Read(fileName string) (err error) {
    17  	bl.Range, err = base.RangeFromFilenameE(fileName)
    18  	if err != nil {
    19  		return err
    20  	}
    21  
    22  	bl.File, err = os.OpenFile(fileName, os.O_RDONLY, 0644)
    23  	if err != nil {
    24  		return err
    25  	}
    26  	defer func() {
    27  		bl.File.Close()
    28  		bl.File = nil
    29  	}()
    30  
    31  	_, _ = bl.File.Seek(0, io.SeekStart)                   // already true, but can't hurt
    32  	if err = bl.readHeader(true /* check */); err != nil { // Note that it may not find a header, but it leaves the file pointer pointing to the count
    33  		return err
    34  	}
    35  
    36  	if err = binary.Read(bl.File, binary.LittleEndian, &bl.Count); err != nil {
    37  		return err
    38  	}
    39  
    40  	bl.Blooms = make([]bloomBytes, bl.Count)
    41  	for i := uint32(0); i < bl.Count; i++ {
    42  		if err = binary.Read(bl.File, binary.LittleEndian, &bl.Blooms[i].NInserted); err != nil {
    43  			return err
    44  		}
    45  
    46  		bl.Blooms[i].Bytes = make([]byte, BLOOM_WIDTH_IN_BYTES)
    47  		if err = binary.Read(bl.File, binary.LittleEndian, &bl.Blooms[i].Bytes); err != nil {
    48  			return err
    49  		}
    50  	}
    51  
    52  	return nil
    53  }
    54  
    55  // readHeader reads a bloom file header into Bloom.
    56  func (bl *Bloom) readHeader(check bool) error {
    57  
    58  	// Set HeaderSize to 0.
    59  	bl.HeaderSize = 0
    60  
    61  	// Read header from file.
    62  	err := binary.Read(bl.File, binary.LittleEndian, &bl.Header)
    63  	if err != nil {
    64  		bl.Header = bloomHeader{}
    65  		_, _ = bl.File.Seek(0, io.SeekStart)
    66  		return err
    67  	}
    68  
    69  	// Check for unversioned bloom filter.
    70  	if bl.Header.Magic != file.SmallMagicNumber {
    71  		bl.Header = bloomHeader{}
    72  		_, _ = bl.File.Seek(0, io.SeekStart)
    73  		return fmt.Errorf("Bloom.readHeader: %w %x %x", ErrIncorrectMagic, bl.Header.Magic, file.SmallMagicNumber)
    74  	}
    75  
    76  	// Set HeaderSize.
    77  	bl.HeaderSize = int64(unsafe.Sizeof(bl.Header))
    78  
    79  	// Validate hash against provided tag.
    80  	if check {
    81  		if bl.Header.Hash != base.BytesToHash(config.HeaderHash(config.ExpectedVersion())) {
    82  			return fmt.Errorf("Bloom.readHeader: %w %x %x", ErrIncorrectHash, bl.Header.Hash, base.BytesToHash(config.HeaderHash(config.ExpectedVersion())))
    83  		}
    84  	}
    85  
    86  	return nil
    87  }