diff --git a/store/rootmulti/store.go b/store/rootmulti/store.go index 9192d1cab186..af5f4486c489 100644 --- a/store/rootmulti/store.go +++ b/store/rootmulti/store.go @@ -54,9 +54,9 @@ type Store struct { traceContext types.TraceContext traceContextMutex sync.Mutex - cleanHouseHeight int64 // CVCH: -1 Unstarted; 0 Finished; +# Current Height we are pruning down from - cleanHouseAmount int64 // CVCH: Positive Integer of blocks to prune @ Each pruning-interval - cleanHouseFinished bool // CVCH: true at false, then turn off when cleanHouse is complete + histPruneHeight int64 // CVCH: -1 Unstarted; 0 Finished; +# Current Height we are pruning down from + histPruneAmount int64 // CVCH: Positive Integer of blocks to prune @ Each pruning-interval + histPruneFinished bool // CVCH: true at start, then falsewhen histPrune is complete interBlockCache types.MultiStorePersistentCache @@ -84,9 +84,9 @@ func NewStore(db dbm.DB) *Store { listeners: make(map[types.StoreKey][]types.WriteListener), removalMap: make(map[types.StoreKey]bool), - cleanHouseHeight: -1, // CVCH - cleanHouseAmount: 10, // CVCH - cleanHouseFinished: false, // CVCH + histPruneHeight: -1, // CVCH + histPruneAmount: 10, // CVCH + histPruneFinished: false, // CVCH } } @@ -396,50 +396,62 @@ func (rs *Store) LastCommitID() types.CommitID { // Example 1: KeepRecent = 100 is changed to KeepRecent = 50, leaving the oldest 50 blocks unpruned after restart. // Example 2: KeepEvery = 100 is changed to KeepRecent = 50, leaving the old "Every" heights in the DB. func (rs *Store) addPruneHistorical(previousHeight int64) { + debuginfo := false // show debug info + // Clean Historical is already finished - if rs.cleanHouseFinished { + if rs.histPruneFinished { return } - // Avoid cleaning historical too early in the blockchain lifecycle + // Avoid historical pruning too early in the blockchain lifecycle // Only consider cleaning historical heights if current height > KeepRecent) if previousHeight < int64(rs.pruningOpts.KeepRecent) { - fmt.Printf("**CVCH Too Early: %d !> %d\n", previousHeight, rs.pruningOpts.KeepRecent) - fmt.Printf("**CVCH Early Finished!!\n") - rs.cleanHouseFinished = true // Since we have started below the KeepRecent height, cleanHouse is unnecessary + if debuginfo { + fmt.Printf("**CVCH Too Early: %d !> %d\n", previousHeight, rs.pruningOpts.KeepRecent) + fmt.Printf("**CVCH Early Finished!!\n") + } + rs.histPruneFinished = true // Since we have started below the KeepRecent height, histPrune is unnecessary return } // Debug - fmt.Printf("**CVCH Run : %d > %d\n", previousHeight, rs.pruningOpts.KeepRecent) - fmt.Printf("**CVCH cHH : %d\n", rs.cleanHouseHeight) + if debuginfo { + fmt.Printf("**CVCH Run : %d > %d\n", previousHeight, rs.pruningOpts.KeepRecent) + fmt.Printf("**CVCH cHH : %d\n", rs.histPruneHeight) + } // Start from current height, then move towards 0 since more recent blocks are more likely to be present) // Remove all previous blocks older than KeepRecent // NOTE: SNAPSHOTS MUST be within KeepRecent (Must KeepRecent > snapshot-keep-recent * snapshot-interval (a multiple of pruning-keep-every in older cosmos-sdk versions, or within keep-recent for newer cosmos-sdk versions) // Clean Historical hasn't been set up yet - if rs.cleanHouseHeight == -1 { - rs.cleanHouseHeight = previousHeight - int64(rs.pruningOpts.KeepRecent) // We are not concerned about duplicate height removals - fmt.Printf("**CVCH Init cleanHouseHeight = %d\n", rs.cleanHouseHeight) - } - - fmt.Printf("**PH CVCH Starting: cleanHouseHeight %d\n", rs.cleanHouseHeight) - // Determine starting and ending heights to clean - var cleanOffset int64 - for cleanOffset = 0; cleanOffset < rs.cleanHouseAmount; cleanOffset++ { - fmt.Printf("**PH CVCH Add %d\n", rs.cleanHouseHeight) - rs.pruneHeights = append(rs.pruneHeights, rs.cleanHouseHeight) - - rs.cleanHouseHeight-- // Reduce cleanHouseHeight for next time through the loop - if rs.cleanHouseHeight < 1 { - fmt.Printf("\t\t**PH CVCH **COMPLETE** cHH:%d\n", rs.cleanHouseHeight) - fmt.Printf("**CVCH Finished!!\n") - rs.cleanHouseFinished = true + if rs.histPruneHeight == -1 { + rs.histPruneHeight = previousHeight - int64(rs.pruningOpts.KeepRecent) // We are not concerned about duplicate height removals + if debuginfo { + fmt.Printf("**CVCH Init histPruneHeight = %d\n", rs.histPruneHeight) + } + } + + if debuginfo { + fmt.Printf("**PH CVCH Starting: histPruneHeight %d\n", rs.histPruneHeight) + } + // Determine starting and ending heights to prune + var histCtr int64 + for histCtr = 0; histCtr < rs.histPruneAmount; histCtr++ { + if debuginfo { + fmt.Printf("**PH CVCH Add %d\n", rs.histPruneHeight) + } + rs.pruneHeights = append(rs.pruneHeights, rs.histPruneHeight) + + rs.histPruneHeight-- // Reduce histPruneHeight for next time through the loop + if rs.histPruneHeight < 1 { + if debuginfo { + fmt.Printf("**CVCH Finished!!\n") + } + rs.histPruneFinished = true break // do not remove heights below 1 } } - fmt.Printf("**PH CVCH Resulting: cleanHouseHeight %d\n", rs.cleanHouseHeight) } // Commit implements Committer/CommitStore. @@ -478,14 +490,14 @@ func (rs *Store) Commit() types.CommitID { // be pruned, where pruneHeight = (commitHeight - 1) - KeepRecent. if rs.pruningOpts.Interval > 0 && int64(rs.pruningOpts.KeepRecent) < previousHeight { pruneHeight := previousHeight - int64(rs.pruningOpts.KeepRecent) - fmt.Printf("**CVCH PH.Future Add pruneHeight %d (previousHeight %d)\n", pruneHeight, previousHeight) + //fmt.Printf("**CVCH PH.Future Add pruneHeight %d (previousHeight %d)\n", pruneHeight, previousHeight) rs.pruneHeights = append(rs.pruneHeights, pruneHeight) } // If the next version will be a pruning interval, pre-append any historical prunes. // This early addtion makes testing in the existing framework easy if rs.pruningOpts.Interval > 0 && (version+1)%int64(rs.pruningOpts.Interval) == 0 { - rs.addPruneHistorical(previousHeight) // CVCH: Add additional block heights for clean house pruning + rs.addPruneHistorical(previousHeight) // CVCH: Add additional block heights for historical pruning } // Execute batch prune if the current height is a pruning interval height @@ -504,6 +516,7 @@ func (rs *Store) Commit() types.CommitID { // pruneStores will batch delete a list of heights from each mounted sub-store. // Afterwards, pruneHeights is reset. func (rs *Store) pruneStores() { + debuginfo := false // show debug info - Helpful to see which heights are pruned if len(rs.pruneHeights) == 0 { return } @@ -514,7 +527,9 @@ func (rs *Store) pruneStores() { // it to get the underlying IAVL store. store = rs.GetCommitKVStore(key) - fmt.Printf("**PH DV %s => %v\n", key, rs.pruneHeights) + if debuginfo { + fmt.Printf("**pruneStores Key: %s Heights: %v\n", key, rs.pruneHeights) + } if err := store.(*iavl.Store).DeleteVersions(rs.pruneHeights...); err != nil { if errCause := errors.Cause(err); errCause != nil && errCause != iavltree.ErrVersionDoesNotExist { panic(err) diff --git a/store/rootmulti/store_test.go b/store/rootmulti/store_test.go index fcbd73a81b5e..e282fe690c83 100644 --- a/store/rootmulti/store_test.go +++ b/store/rootmulti/store_test.go @@ -555,15 +555,15 @@ func TestMultiStore_PruningHistoricalEarlyFinish(t *testing.T) { } // Should already be flagged complete since we started at zero height - require.Equal(t, ms.cleanHouseFinished, true) + require.Equal(t, ms.histPruneFinished, true) } -// Confirm that historical pruning starts and completes -func TestMultiStore_PruningHistorical(t *testing.T) { +// Confirm that decreasing the KeepRecent setting from 100->10 prunes the new offset +func TestMultiStore_PruningHistoricalDecrease(t *testing.T) { debuginfo := false // Show debug logs? if debuginfo { - fmt.Println("TestMultiStore_PruningHistorical") + fmt.Println("TestMultiStore_PruningHistoricalReduce") } // Create DB @@ -581,7 +581,7 @@ func TestMultiStore_PruningHistorical(t *testing.T) { // Next pruneHeight 60, historicalPrune queue height = 59, previousHeight = 58, previousHeight(58) - keepRecent(10) = 48 historicMarker := int64(48) - // "restart" + CHANGE PruningOptions (to a lower KeepRecent), Check for historical prune + // Simulate Reconfig + "Restart" + CHANGE PruningOptions (to a lower KeepRecent), Check for historical prune if debuginfo { fmt.Printf("Restart with new PruneingOptions\n") } @@ -600,7 +600,7 @@ func TestMultiStore_PruningHistorical(t *testing.T) { if debuginfo { fmt.Printf("Historic Prune Loop %d\n", i) } - require.Equal(t, false, ms.cleanHouseFinished) // Should not be done pruning at the beginning of this loop + require.Equal(t, false, ms.histPruneFinished) // Should not be done pruning at the beginning of this loop // This commit should queue a lot of historical prunes ms.Commit() @@ -619,7 +619,7 @@ func TestMultiStore_PruningHistorical(t *testing.T) { } // Historic Prune - Should be complete - require.Equal(t, true, ms.cleanHouseFinished) + require.Equal(t, true, ms.histPruneFinished) // Run some extra commits to see if the program dies for i := int64(0); i < 10; i++ { @@ -632,6 +632,83 @@ func TestMultiStore_PruningHistorical(t *testing.T) { require.Equal(t, targetHeights, ms.pruneHeights) } +// Confirm that increasing the KeepRecent setting from 10->30 prunes the new offset +func TestMultiStore_PruningHistoricalIncrease(t *testing.T) { + debuginfo := false // Show debug logs? + + if debuginfo { + fmt.Println("TestMultiStore_PruningHistoricalIncrease") + } + + // Create DB + db := dbm.NewMemDB() + ms := newMultiStoreWithMounts(db, types.PruningOptions{KeepRecent: 10, Interval: 5}) + require.NoError(t, ms.LoadLatestVersion()) + + // Add enough heights to start pruning after increase + targetHeights := []int64{45, 46} + for i := int64(0); i < 57; i++ { + ms.Commit() + } + require.Equal(t, true, ms.histPruneFinished) // Should not be done pruning at the beginning of this loop + ph, err := getPruningHeights(ms.db) + require.Equal(t, targetHeights, ph) // Should have some pruneHeights due to low KeepRecent + + // Next pruneHeight 60, historicalPrune queue height = 59, previousHeight = 58, previousHeight(58) - keepRecent(30) = 28 + historicMarker := int64(28) + + // Simulate Reconfig + "Restart" + CHANGE PruningOptions (to a lower KeepRecent), Check for historical prune + if debuginfo { + fmt.Printf("Restart with new PruneingOptions\n") + } + ms = newMultiStoreWithMounts(db, types.PruningOptions{KeepRecent: 30, Interval: 10}) + err = ms.LoadLatestVersion() + require.NoError(t, err) + ph, err = getPruningHeights(ms.db) + require.Equal(t, targetHeights, ph) // Should have some pruneHeights due to low KeepRecent + ms.Commit() // Boring commit + + // commit until all historic heights have been pruned + // Loop 0: Prune Heights: 19-28 + // Loop 1: Prune Heights: 9-18 + // Loop 2: Prune Heights: 1- 8 + for i := 0; i < 3; i++ { + if debuginfo { + fmt.Printf("Historic Prune Loop %d\n", i) + } + require.Equal(t, false, ms.histPruneFinished) // Should not be done pruning at the beginning of this loop + + // This commit should queue a lot of historical prunes + ms.Commit() + for h := historicMarker; h > historicMarker-10 && h > 0; h-- { + require.Contains(t, ms.pruneHeights, h) // Expect each historicalHeight to be queued for prune + } + historicMarker -= 10 + + // Run another series of dummy commits until the next historical height queue + for dummy := int64(0); dummy < 9; dummy++ { + if debuginfo { + fmt.Printf("\tBoring Commit Height %d\n", ms.lastCommitInfo.GetVersion()+1) + } + ms.Commit() + } + } + + // Historic Prune - Should be complete + require.Equal(t, true, ms.histPruneFinished) + + // Run some extra commits to see if the program dies + for i := int64(0); i < 10; i++ { + if debuginfo { + fmt.Printf("\tExtra Commit Height %d\n", ms.lastCommitInfo.GetVersion()+1) + } + ms.Commit() + } + + targetHeights = []int64{60, 61, 62, 63, 64, 65, 66, 67} + require.Equal(t, targetHeights, ms.pruneHeights) +} + func TestSetInitialVersion(t *testing.T) { db := dbm.NewMemDB() multi := newMultiStoreWithMounts(db, types.PruneNothing)