force disk flush when caught up to current

This commit is contained in:
Brannon King 2021-07-27 15:10:17 -04:00 committed by Roy Lee
parent 0a01170422
commit 82d4b6657b
18 changed files with 109 additions and 18 deletions

View file

@ -574,15 +574,9 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
"spent transaction out information") "spent transaction out information")
} }
// Handle LBRY Claim Scripts
if b.claimTrie != nil {
if err := b.ParseClaimScripts(block, node, view, false); err != nil {
return ruleError(ErrBadClaimTrie, err.Error())
}
}
// No warnings about unknown rules until the chain is current. // No warnings about unknown rules until the chain is current.
if b.isCurrent() { current := b.isCurrent()
if current {
// Warn if any unknown new rules are either about to activate or // Warn if any unknown new rules are either about to activate or
// have already been activated. // have already been activated.
if err := b.warnUnknownRuleActivations(node); err != nil { if err := b.warnUnknownRuleActivations(node); err != nil {
@ -590,6 +584,13 @@ func (b *BlockChain) connectBlock(node *blockNode, block *btcutil.Block,
} }
} }
// Handle LBRY Claim Scripts
if b.claimTrie != nil {
if err := b.ParseClaimScripts(block, node, view, false, current); err != nil {
return ruleError(ErrBadClaimTrie, err.Error())
}
}
// Write any block status changes to DB before updating best state. // Write any block status changes to DB before updating best state.
err := b.index.flushToDB() err := b.index.flushToDB()
if err != nil { if err != nil {
@ -1223,7 +1224,7 @@ func (b *BlockChain) connectBestChain(node *blockNode, block *btcutil.Block, fla
// factors are used to guess, but the key factors that allow the chain to // factors are used to guess, but the key factors that allow the chain to
// believe it is current are: // believe it is current are:
// - Latest block height is after the latest checkpoint (if enabled) // - Latest block height is after the latest checkpoint (if enabled)
// - Latest block has a timestamp newer than 24 hours ago // - Latest block has a timestamp newer than ~6 hours ago (as LBRY block time is one fourth of bitcoin)
// //
// This function MUST be called with the chain state lock held (for reads). // This function MUST be called with the chain state lock held (for reads).
func (b *BlockChain) isCurrent() bool { func (b *BlockChain) isCurrent() bool {
@ -1234,13 +1235,13 @@ func (b *BlockChain) isCurrent() bool {
return false return false
} }
// Not current if the latest best block has a timestamp before 24 hours // Not current if the latest best block has a timestamp before 7 hours
// ago. // ago.
// //
// The chain appears to be current if none of the checks reported // The chain appears to be current if none of the checks reported
// otherwise. // otherwise.
minus24Hours := b.timeSource.AdjustedTime().Add(-24 * time.Hour).Unix() hours := b.timeSource.AdjustedTime().Add(-7 * time.Hour).Unix()
return b.bestChain.Tip().timestamp >= minus24Hours return b.bestChain.Tip().timestamp >= hours
} }
// IsCurrent returns whether or not the chain believes it is current. Several // IsCurrent returns whether or not the chain believes it is current. Several
@ -1879,7 +1880,7 @@ func rebuildMissingClaimTrieData(b *BlockChain, done <-chan struct{}) error {
} }
if h >= b.claimTrie.Height() { if h >= b.claimTrie.Height() {
err = b.ParseClaimScripts(block, n, view, true) err = b.ParseClaimScripts(block, n, view, true, false)
if err != nil { if err != nil {
return err return err
} }

View file

@ -15,7 +15,8 @@ import (
"github.com/btcsuite/btcd/claimtrie/node" "github.com/btcsuite/btcd/claimtrie/node"
) )
func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view *UtxoViewpoint, failOnHashMiss bool) error { func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view *UtxoViewpoint,
failOnHashMiss bool, shouldFlush bool) error {
ht := block.Height() ht := block.Height()
for _, tx := range block.Transactions() { for _, tx := range block.Transactions() {
@ -40,6 +41,10 @@ func (b *BlockChain) ParseClaimScripts(block *btcutil.Block, bn *blockNode, view
} }
hash := b.claimTrie.MerkleHash() hash := b.claimTrie.MerkleHash()
if shouldFlush {
b.claimTrie.FlushToDisk()
}
if bn.claimTrie != *hash { if bn.claimTrie != *hash {
if failOnHashMiss { if failOnHashMiss {
return errors.Errorf("height: %d, ct.MerkleHash: %s != node.ClaimTrie: %s", ht, *hash, bn.claimTrie) return errors.Errorf("height: %d, ct.MerkleHash: %s != node.ClaimTrie: %s", ht, *hash, bn.claimTrie)

View file

@ -69,3 +69,8 @@ func (repo *Pebble) Close() error {
err = repo.db.Close() err = repo.db.Close()
return errors.Wrap(err, "on close") return errors.Wrap(err, "on close")
} }
func (repo *Pebble) Flush() error {
_, err := repo.db.AsyncFlush()
return err
}

View file

@ -10,4 +10,5 @@ type Repo interface {
Set(height int32, hash *chainhash.Hash) error Set(height int32, hash *chainhash.Hash) error
Get(height int32) (*chainhash.Hash, error) Get(height int32) (*chainhash.Hash, error)
Close() error Close() error
Flush() error
} }

View file

@ -69,3 +69,8 @@ func (repo *Pebble) Close() error {
err = repo.db.Close() err = repo.db.Close()
return errors.Wrap(err, "on close") return errors.Wrap(err, "on close")
} }
func (repo *Pebble) Flush() error {
_, err := repo.db.AsyncFlush()
return err
}

View file

@ -6,4 +6,5 @@ type Repo interface {
Save(height int32, changes []change.Change) error Save(height int32, changes []change.Change) error
Load(height int32) ([]change.Change, error) Load(height int32) ([]change.Change, error)
Close() error Close() error
Flush() error
} }

View file

@ -410,3 +410,29 @@ func (ct *ClaimTrie) forwardNodeChange(chg change.Change) error {
func (ct *ClaimTrie) Node(name []byte) (*node.Node, error) { func (ct *ClaimTrie) Node(name []byte) (*node.Node, error) {
return ct.nodeManager.Node(name) return ct.nodeManager.Node(name)
} }
func (ct *ClaimTrie) FlushToDisk() {
// maybe the user can fix the file lock shown in the warning before they shut down
if err := ct.nodeManager.Flush(); err != nil {
node.Warn("During nodeManager flush: " + err.Error())
}
if err := ct.temporalRepo.Flush(); err != nil {
node.Warn("During temporalRepo flush: " + err.Error())
}
if err := ct.merkleTrie.Flush(); err != nil {
node.Warn("During merkleTrie flush: " + err.Error())
}
if err := ct.blockRepo.Flush(); err != nil {
node.Warn("During blockRepo flush: " + err.Error())
}
if ct.reportedBlockRepo != nil {
if err := ct.reportedBlockRepo.Flush(); err != nil {
node.Warn("During reportedBlockRepo flush: " + err.Error())
}
}
if ct.chainRepo != nil {
if err := ct.chainRepo.Flush(); err != nil {
node.Warn("During chainRepo flush: " + err.Error())
}
}
}

View file

@ -272,3 +272,7 @@ func (t *PersistentTrie) Dump(s string) {
fmt.Printf(" Child %s hash: %s\n", string(key), value.merkleHash.String()) fmt.Printf(" Child %s hash: %s\n", string(key), value.merkleHash.String())
} }
} }
func (t *PersistentTrie) Flush() error {
return t.repo.Flush()
}

View file

@ -59,3 +59,8 @@ func (repo *Pebble) Close() error {
err = repo.db.Close() err = repo.db.Close()
return errors.Wrap(err, "on close") return errors.Wrap(err, "on close")
} }
func (repo *Pebble) Flush() error {
_, err := repo.db.AsyncFlush()
return err
}

View file

@ -2,10 +2,12 @@ package merkletrie
import ( import (
"bytes" "bytes"
"runtime"
"strconv"
"sync"
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/claimtrie/node" "github.com/btcsuite/btcd/claimtrie/node"
"runtime"
"sync"
) )
type MerkleTrie interface { type MerkleTrie interface {
@ -13,6 +15,7 @@ type MerkleTrie interface {
Update(name []byte, restoreChildren bool) Update(name []byte, restoreChildren bool)
MerkleHash() *chainhash.Hash MerkleHash() *chainhash.Hash
MerkleHashAllClaims() *chainhash.Hash MerkleHashAllClaims() *chainhash.Hash
Flush() error
} }
type RamTrie struct { type RamTrie struct {
@ -50,10 +53,14 @@ func (rt *RamTrie) SetRoot(h *chainhash.Hash, names [][]byte) {
runtime.GC() runtime.GC()
} }
c := 0
rt.store.IterateNames(func(name []byte) bool { rt.store.IterateNames(func(name []byte) bool {
rt.Update(name, false) rt.Update(name, false)
c++
return true return true
}) })
node.LogOnce("Completed claim trie construction. Name count: " + strconv.Itoa(c))
} else { } else {
for _, name := range names { for _, name := range names {
rt.Update(name, false) rt.Update(name, false)
@ -147,3 +154,7 @@ func (rt *RamTrie) merkleHashAllClaims(v *collapsedVertex) *chainhash.Hash {
v.merkleHash = node.HashMerkleBranches(childHash, claimHash) v.merkleHash = node.HashMerkleBranches(childHash, claimHash)
return v.merkleHash return v.merkleHash
} }
func (rt *RamTrie) Flush() error {
return nil
}

View file

@ -9,4 +9,5 @@ type Repo interface {
Get(key []byte) ([]byte, io.Closer, error) Get(key []byte) ([]byte, io.Closer, error)
Set(key, value []byte) error Set(key, value []byte) error
Close() error Close() error
Flush() error
} }

View file

@ -35,3 +35,7 @@ func LogOnce(s string) {
loggedStrings[s] = true loggedStrings[s] = true
log.Info(s) log.Info(s)
} }
func Warn(s string) {
log.Warn(s)
}

View file

@ -25,6 +25,7 @@ type Manager interface {
NextUpdateHeightOfNode(name []byte) ([]byte, int32) NextUpdateHeightOfNode(name []byte) ([]byte, int32)
IterateNames(predicate func(name []byte) bool) IterateNames(predicate func(name []byte) bool)
Hash(name []byte) *chainhash.Hash Hash(name []byte) *chainhash.Hash
Flush() error
} }
type nodeCacheLeaf struct { type nodeCacheLeaf struct {
@ -448,3 +449,7 @@ func calculateNodeHash(op wire.OutPoint, takeover int32) *chainhash.Hash {
return &hh return &hh
} }
func (nm *BaseManager) Flush() error {
return nm.repo.Flush()
}

View file

@ -79,7 +79,7 @@ func init() {
func NewPebble(path string) (*Pebble, error) { func NewPebble(path string) (*Pebble, error) {
db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(256 << 20), BytesPerSync: 16 << 20}) db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(32 << 20), BytesPerSync: 4 << 20})
repo := &Pebble{db: db} repo := &Pebble{db: db}
return repo, errors.Wrapf(err, "unable to open %s", path) return repo, errors.Wrapf(err, "unable to open %s", path)
@ -218,3 +218,8 @@ func (repo *Pebble) Close() error {
err = repo.db.Close() err = repo.db.Close()
return errors.Wrap(err, "on close") return errors.Wrap(err, "on close")
} }
func (repo *Pebble) Flush() error {
_, err := repo.db.AsyncFlush()
return err
}

View file

@ -26,4 +26,6 @@ type Repo interface {
// IterateAll iterates keys until the predicate function returns false // IterateAll iterates keys until the predicate function returns false
IterateAll(predicate func(name []byte) bool) IterateAll(predicate func(name []byte) bool)
Flush() error
} }

View file

@ -5,4 +5,5 @@ type Repo interface {
SetNodesAt(names [][]byte, heights []int32) error SetNodesAt(names [][]byte, heights []int32) error
NodesAt(height int32) ([][]byte, error) NodesAt(height int32) ([][]byte, error)
Close() error Close() error
Flush() error
} }

View file

@ -39,3 +39,7 @@ func (repo *Memory) NodesAt(height int32) ([][]byte, error) {
func (repo *Memory) Close() error { func (repo *Memory) Close() error {
return nil return nil
} }
func (repo *Memory) Flush() error {
return nil
}

View file

@ -14,7 +14,7 @@ type Pebble struct {
func NewPebble(path string) (*Pebble, error) { func NewPebble(path string) (*Pebble, error) {
db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(128 << 20)}) db, err := pebble.Open(path, &pebble.Options{Cache: pebble.NewCache(16 << 20)})
repo := &Pebble{db: db} repo := &Pebble{db: db}
return repo, errors.Wrapf(err, "unable to open %s", path) return repo, errors.Wrapf(err, "unable to open %s", path)
@ -79,3 +79,8 @@ func (repo *Pebble) Close() error {
err = repo.db.Close() err = repo.db.Close()
return errors.Wrap(err, "on close") return errors.Wrap(err, "on close")
} }
func (repo *Pebble) Flush() error {
_, err := repo.db.AsyncFlush()
return err
}