Skip to content

Commit

Permalink
headerfs: add new readHeaderRange method to BlockHeaderStore
Browse files Browse the repository at this point in the history
In this commit, we add a new method readHeaderRange, which allows
callers to batch request a set of headers in a contiguous height range.
Before this commit, in order to fetch a range of headers, we required
the caller to execute a system call for *each* header. During IDB, when
we're writing thousands of headers, this quickly becomes very costly.

In order to provide an alternative, we add a new method which allows the
caller to fetch an series of headers with a *single* system call.
  • Loading branch information
Roasbeef committed Aug 8, 2018
1 parent c6d289e commit 00c45f6
Showing 1 changed file with 54 additions and 0 deletions.
54 changes: 54 additions & 0 deletions headerfs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,60 @@ func (h *headerStore) readRaw(seekDist uint64) ([]byte, error) {

return rawHeader[:], nil
}

// readHeaderRange will attempt to fetch a series of headers within the target
// height range. This method batches a set of reads into a single system call
// thereby increasing performance when reading a set of contiguous headers.
//
// NOTE: The end height is _inclusive_ so we'll fetch all headers from the
// startHeight up to the end height, including the final header.
func (h *BlockHeaderStore) readHeaderRange(startHeight uint32,
endHeight uint32) ([]wire.BlockHeader, error) {

// Each header is 80 bytes, so using this information, we'll seek a
// distance to cover that height based on the size of block headers.
seekDistance := uint64(startHeight) * 80

// Based on the defined header type, we'll determine the number of
// bytes that we need to read past the sync point.
var headerSize uint32
switch h.indexType {
case Block:
headerSize = 80

case RegularFilter:
headerSize = 32

default:
return nil, fmt.Errorf("unknown index type: %v", h.indexType)
}

// Based on the number of headers in the range, we'll allocate a single
// slice that's able to hold the entire range of headers.
numHeaders := endHeight - startHeight + 1
rawHeaderBytes := make([]byte, headerSize*numHeaders)

// Now that we have our slice allocated, we'll read out the entire
// range of headers with a single system call.
_, err := h.file.ReadAt(rawHeaderBytes, int64(seekDistance))
if err != nil {
return nil, err
}

// We'll now incrementally parse out the set of individual headers from
// our set of serialized contiguous raw headers.
headerReader := bytes.NewReader(rawHeaderBytes)
headers := make([]wire.BlockHeader, 0, numHeaders)
for headerReader.Len() != 0 {
var nextHeader wire.BlockHeader
if err := nextHeader.Deserialize(headerReader); err != nil {
return nil, err
}

headers = append(headers, nextHeader)
}

return headers, nil
}

// readHeader reads a full block header from the flat-file. The header read is
Expand Down

0 comments on commit 00c45f6

Please sign in to comment.