Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose versions field to support pruning #123

Closed
wants to merge 1 commit into from

Conversation

ackratos
Copy link

@ackratos ackratos commented Feb 2, 2019

@liamsi
Copy link
Contributor

liamsi commented Feb 6, 2019

Thanks a lot for looking into this @ackratos! Do you mind sharing your implementation of the PruningStrategy to better understand this requirement?

Also, shouldn't the interface in cosmos/cosmos-sdk#3480 rather be:

func (tree *MutableTree) Prune(ps PruningStrategy) {/* as in cosmos-sdk#3480 */}

and require changes here (and not in the sdk)?

@ackratos
Copy link
Author

@liamsi sorry for the delayed reply, I have had a whole week vacation.

Apart from cosmos/cosmos-sdk#3480, this is mainly mean to support state sync (tendermint/tendermint#828)

I haven't realise cosmos recently refactored the prune strategy part :( (cosmos/cosmos-sdk#2985). I already finished change on my earlier cosmos fork (will raise a PR to latest cosmos within this week):

// PruningStrategy specfies how old states will be deleted over time
type PruningStrategy interface {
	Prune(version, latestVersion int64) bool
}

// PruneSyncable means only those states not needed for state syncing will be deleted (keeps last 100 + every 10000th)
type PruneSyncable struct {
	// How many old versions we hold onto.
	// A value of 0 means keep no recent states.
	NumRecent int64

	// This is the distance between state-sync waypoint states to be stored.
	// See https://github.com/tendermint/tendermint/issues/828
	// A value of 1 means store every state.
	// A value of 0 means store no waypoints. (node cannot assist in state-sync)
	// By default this value should be set the same across all nodes,
	// so that nodes can know the waypoints their peers store.
	StoreEvery int64
}

func (strategy PruneSyncable) Prune(version, latestVersion int64) bool {
	return (latestVersion-version > strategy.NumRecent) && (version%strategy.StoreEvery != 0)
}

// PruneEverything means all saved states will be deleted, storing only the current state
type PruneEverything struct{}

func (strategy PruneEverything) Prune(version, latestVersion int64) bool {
	return true
}

// PruneNothing means all historic states will be saved, nothing will be deleted
type PruneNothing struct{}

func (strategy PruneNothing) Prune(version, latestVersion int64) bool {
	return false
}

// Implements Committer.
func (st *iavlStore) Commit() CommitID {
	// Save a new version.
	hash, version, err := st.tree.SaveVersion()
	if err != nil {
		// TODO: Do we want to extend Commit to allow returning errors?
		panic(err)
	}

	// Release an old version of history, if not a sync waypoint.
	for v, _ := range st.tree.GetVersions() {
		if st.pruningStrategy.Prune(v, version) {
			st.tree.DeleteVersion(v)
		}
	}

	return CommitID{
		Version: version,
		Hash:    hash,
	}
}

Our usage is a little more complicated than cosmos syncable way point. (which related to num of versions recent and fixed number of blocks). We introduced breathe block - the first block of each UTC day and snapshot tx/msg execution result in memory between two breathe block (to ease disk r/w pressure). We want keep all breathe block versions. Below is strategy implemented in our app level.

type KeepRecentAndBreatheBlock struct {
	breatheBlockInterval int64

 	// Keep recent number blocks in case of rollback
	numRecent int64

 	blockStore *blockchain.BlockStore

 	blockStoreInitializer sync.Once
}

func NewKeepRecentAndBreatheBlock(breatheBlockInterval, numRecent int64) *KeepRecentAndBreatheBlock {
	return &KeepRecentAndBreatheBlock{
		breatheBlockInterval: breatheBlockInterval,
		numRecent:            numRecent,
	}
}

func (strategy KeepRecentAndBreatheBlock) Prune(version, latestVersion int64) bool {

 	// only at this time block store is initialized!
	strategy.blockStoreInitializer.Do(func() {
		strategy.blockStore = cosmossrv.BlockStore
	})

 	if version == 1 {
		return true
	} else {
		lastBlock := strategy.blockStore.LoadBlock(version - 1)
		block := strategy.blockStore.LoadBlock(version)

 		if strategy.breatheBlockInterval > 0 {
			return version%strategy.breatheBlockInterval != 0
		} else {
			return utils.SameDayInUTC(lastBlock.Time, block.Time)
		}
	}
}

ackratos added a commit to bnb-chain/bnc-tendermint-iavl that referenced this pull request Feb 21, 2019
@tac0turtle
Copy link
Member

closing this PR as we introduced pruning into IAVL via #158

@tac0turtle tac0turtle closed this Jan 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants