database: Stop writing block header data to LevelDB.

Now that all headers are stored in the in-memory index, the database
bucket managed by blockchain, and in the flat files, it makes sense to
drop the redundant data from the block index bucket in ffldb.

To avoid modifying the database interface, this reimplements
FetchBlockHeader(s) to use header data stored in flat files. This can
be trivially implemented by delegating to FetchBlockRegion.
This commit is contained in:
Jim Posen 2017-09-05 19:08:09 -07:00 committed by Dave Collins
parent 74fb6e56da
commit ad00e7ff82

View file

@ -1255,27 +1255,11 @@ func (tx *transaction) fetchBlockRow(hash *chainhash.Hash) ([]byte, error) {
//
// This function is part of the database.Tx interface implementation.
func (tx *transaction) FetchBlockHeader(hash *chainhash.Hash) ([]byte, error) {
// Ensure transaction state is valid.
if err := tx.checkClosed(); err != nil {
return nil, err
}
// When the block is pending to be written on commit return the bytes
// from there.
if idx, exists := tx.pendingBlocks[*hash]; exists {
blockBytes := tx.pendingBlockData[idx].bytes
return blockBytes[0:blockHdrSize:blockHdrSize], nil
}
// Fetch the block index row and slice off the header. Notice the use
// of the cap on the subslice to prevent the caller from accidentally
// appending into the db data.
blockRow, err := tx.fetchBlockRow(hash)
if err != nil {
return nil, err
}
endOffset := blockLocSize + blockHdrSize
return blockRow[blockLocSize:endOffset:endOffset], nil
return tx.FetchBlockRegion(&database.BlockRegion{
Hash: hash,
Offset: 0,
Len: blockHdrSize,
})
}
// FetchBlockHeaders returns the raw serialized bytes for the block headers
@ -1294,41 +1278,13 @@ func (tx *transaction) FetchBlockHeader(hash *chainhash.Hash) ([]byte, error) {
//
// This function is part of the database.Tx interface implementation.
func (tx *transaction) FetchBlockHeaders(hashes []chainhash.Hash) ([][]byte, error) {
// Ensure transaction state is valid.
if err := tx.checkClosed(); err != nil {
return nil, err
}
// NOTE: This could check for the existence of all blocks before loading
// any of the headers which would be faster in the failure case, however
// callers will not typically be calling this function with invalid
// values, so optimize for the common case.
// Load the headers.
headers := make([][]byte, len(hashes))
regions := make([]database.BlockRegion, len(hashes))
for i := range hashes {
hash := &hashes[i]
// When the block is pending to be written on commit return the
// bytes from there.
if idx, exists := tx.pendingBlocks[*hash]; exists {
blkBytes := tx.pendingBlockData[idx].bytes
headers[i] = blkBytes[0:blockHdrSize:blockHdrSize]
continue
}
// Fetch the block index row and slice off the header. Notice
// the use of the cap on the subslice to prevent the caller
// from accidentally appending into the db data.
blockRow, err := tx.fetchBlockRow(hash)
if err != nil {
return nil, err
}
endOffset := blockLocSize + blockHdrSize
headers[i] = blockRow[blockLocSize:endOffset:endOffset]
regions[i].Hash = &hashes[i]
regions[i].Offset = 0
regions[i].Len = blockHdrSize
}
return headers, nil
return tx.FetchBlockRegions(regions)
}
// FetchBlock returns the raw serialized bytes for the block identified by the
@ -1656,19 +1612,6 @@ func (tx *transaction) close() {
}
}
// serializeBlockRow serializes a block row into a format suitable for storage
// into the block index.
func serializeBlockRow(blockLoc blockLocation, blockHdr []byte) []byte {
// The serialized block index row format is:
//
// [0:blockLocSize] Block location
// [blockLocSize:blockLocSize+blockHdrSize] Block header
serializedRow := make([]byte, blockLocSize+blockHdrSize)
copy(serializedRow, serializeBlockLoc(blockLoc))
copy(serializedRow[blockHdrOffset:], blockHdr)
return serializedRow
}
// writePendingAndCommit writes pending block data to the flat block files,
// updates the metadata with their locations as well as the new current write
// location, and commits the metadata to the memory database cache. It also
@ -1706,8 +1649,7 @@ func (tx *transaction) writePendingAndCommit() error {
// includes the location information needed to locate the block
// on the filesystem as well as the block header since they are
// so commonly needed.
blockHdr := blockData.bytes[0:blockHdrSize]
blockRow := serializeBlockRow(location, blockHdr)
blockRow := serializeBlockLoc(location)
err = tx.blockIdxBucket.Put(blockData.hash[:], blockRow)
if err != nil {
rollback()