Skip to content

Commit fe31236

Browse files
committed
feat: skip compact while syncing
1 parent 38c61cf commit fe31236

2 files changed

Lines changed: 50 additions & 0 deletions

File tree

controller/consensus.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/canopy-network/canopy/lib"
1111
"github.com/canopy-network/canopy/lib/crypto"
1212
"github.com/canopy-network/canopy/p2p"
13+
"github.com/canopy-network/canopy/store"
1314
)
1415

1516
const (
@@ -74,6 +75,10 @@ func (c *Controller) Sync() {
7475
c.log.Infof("Sync started 🔄 for committee %d", c.Config.ChainId)
7576
// set the Controller as 'syncing'
7677
c.isSyncing.Store(true)
78+
// notify the store to defer compaction during sync
79+
if st, ok := c.FSM.Store().(*store.Store); ok {
80+
st.SetSyncing(true)
81+
}
7782
// check if node is alone in the validator set
7883
singleNode, err := c.singleNodeNetwork()
7984
if err != nil {
@@ -756,6 +761,12 @@ func (c *Controller) finishSyncing() {
756761
c.Consensus.ResetBFT <- bft.ResetBFT{StartTime: c.LoadLastCommitTime(c.FSM.Height())}
757762
// set syncing to false
758763
c.isSyncing.Store(false)
764+
// notify the store to resume compaction and trigger a full compaction of all prefixes
765+
// (including SMT/indexer which are never compacted during normal operation)
766+
if st, ok := c.FSM.Store().(*store.Store); ok {
767+
st.SetSyncing(false)
768+
go st.CompactAll()
769+
}
759770
// enable listening for a block
760771
go c.ListenForBlock()
761772
}

store/store.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ type Store struct {
7373
sc *SMT // reference to the state commitment store
7474
*Indexer // reference to the indexer store
7575
metrics *lib.Metrics // telemetry
76+
syncing atomic.Bool // when true, skip compaction to avoid write stalls during sync
7677
log lib.LoggerI // logger
7778
config lib.Config // config
7879
mu *sync.Mutex // mutex for concurrent commits
@@ -472,6 +473,39 @@ func (s *Store) IncreaseVersion() { func() { s.version++; s.sc = nil }() }
472473
// number of the state. This is used to track the versioning of the state data.
473474
func (s *Store) Version() uint64 { return s.version }
474475

476+
// SetSyncing tells the store whether the node is currently syncing, allowing it to
477+
// defer expensive maintenance operations (compaction) that cause write stalls at scale.
478+
func (s *Store) SetSyncing(v bool) { s.syncing.Store(v) }
479+
480+
// CompactAll runs compaction across all store prefixes including SMT commitment nodes
481+
// and indexer entries that are not covered by the regular MaybeCompact cycle.
482+
// Should be called after sync completes to consolidate the accumulated versions.
483+
func (s *Store) CompactAll() {
484+
if s.compaction.Load() {
485+
return
486+
}
487+
s.compaction.Store(true)
488+
defer s.compaction.Store(false)
489+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
490+
defer cancel()
491+
version := s.Version()
492+
s.log.Infof("full compaction started at height %d (post-sync)", version)
493+
now := time.Now()
494+
for _, prefix := range [][]byte{
495+
latestStatePrefix,
496+
historicStatePrefix,
497+
stateCommitmentPrefix,
498+
stateCommitIDPrefix,
499+
indexerPrefix,
500+
} {
501+
if err := s.db.Compact(ctx, prefix, prefixEnd(prefix), false); err != nil {
502+
s.log.Errorf("full compaction failed for prefix: %s", err)
503+
return
504+
}
505+
}
506+
s.log.Infof("full compaction finished at height %d in %s", version, time.Since(now))
507+
}
508+
475509
// NewTxn() creates and returns a new transaction for the Store, allowing atomic operations
476510
// on the StateStore, StateCommitStore, Indexer, and CommitIDStore.
477511
func (s *Store) NewTxn() lib.StoreI {
@@ -612,6 +646,11 @@ func getLatestCommitID(db *pebble.DB, log lib.LoggerI) (id *lib.CommitID) {
612646

613647
// MaybeCompact() checks if it is time to compact the LSS and HSS respectively
614648
func (s *Store) MaybeCompact() {
649+
// skip compaction during syncing: at scale (~1.5M+ blocks) HSS range compaction causes
650+
// PebbleDB write stalls that throttle the sync loop's db.Apply calls
651+
if s.syncing.Load() {
652+
return
653+
}
615654
// check if the current version is a multiple of the cleanup block interval
616655
compactionInterval := s.config.StoreConfig.LSSCompactionInterval
617656
version := s.Version()

0 commit comments

Comments
 (0)