Skip to content

Commit

Permalink
Tweak the store loader config warning stuff a bit to make the tests n…
Browse files Browse the repository at this point in the history
…ot actually do the sleeps. Also allow bypassing the sleep via env var. Standardize some of the buffered logger stuff too.
  • Loading branch information
SpicyLemon committed Jan 12, 2024
1 parent aa179d2 commit 21ea2c9
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 217 deletions.
3 changes: 1 addition & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ func New(
}

// Currently in an upgrade hold for this block.
var storeLoader baseapp.StoreLoader
storeLoader := baseapp.DefaultStoreLoader
if upgradeInfo.Name != "" && upgradeInfo.Height == app.LastBlockHeight()+1 {
if app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
app.Logger().Info("Skipping upgrade based on height",
Expand All @@ -1075,7 +1075,6 @@ func New(
storeLoader = GetUpgradeStoreLoader(app, upgradeInfo)
}
}
// --

// Verify configuration settings
storeLoader = ValidateWrapper(app.Logger(), appOpts, storeLoader)
Expand Down
111 changes: 66 additions & 45 deletions app/store_loader.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package app

import (
"errors"
"fmt"
"os"
"strconv"
"strings"
"time"

"github.com/spf13/cast"
Expand All @@ -16,60 +18,79 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

// StoreLoaderWrapper is a wrapper function that is called before the StoreLoader.
type StoreLoaderWrapper func(sdk.CommitMultiStore, baseapp.StoreLoader) error
// ValidateWrapperSleeper is the sleeper that the ValidateWrapper will use.
// It primarily exists so it can be changed for unit tests on ValidateWrapper so they don't take so long.
var ValidateWrapperSleeper Sleeper = &DefaultSleeper{}

// WrapStoreLoader creates a new StoreLoader by wrapping an existing one.
func WrapStoreLoader(wrapper StoreLoaderWrapper, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
// ValidateWrapper creates a new StoreLoader that first checks the config settings before calling the provided StoreLoader.
func ValidateWrapper(logger log.Logger, appOpts servertypes.AppOptions, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
return func(ms sdk.CommitMultiStore) error {
if storeLoader == nil {
storeLoader = baseapp.DefaultStoreLoader
}
IssueConfigWarnings(logger, appOpts, ValidateWrapperSleeper)
return storeLoader(ms)
}
}

if wrapper == nil {
return errors.New("wrapper must not be nil")
}
// Sleeper is an interface for something with a Sleep function.
type Sleeper interface {
Sleep(d time.Duration)
}

return wrapper(ms, storeLoader)
}
// DefaultSleeper uses the time.Sleep function for sleeping.
type DefaultSleeper struct{}

// Sleep is a wrapper for time.Sleep(d).
func (s DefaultSleeper) Sleep(d time.Duration) {
time.Sleep(d)
}

// ValidateWrapper creates a new StoreLoader that first checks the config settings before calling the provided StoreLoader.
func ValidateWrapper(logger log.Logger, appOpts servertypes.AppOptions, storeLoader baseapp.StoreLoader) baseapp.StoreLoader {
return WrapStoreLoader(func(ms sdk.CommitMultiStore, sl baseapp.StoreLoader) error {
const MaxPruningInterval = 999
const SleepSeconds = 30
backend := server.GetAppDBBackend(appOpts)
interval := cast.ToUint64(appOpts.Get("pruning-interval"))
txIndexer := cast.ToStringMap(appOpts.Get("tx_index"))
indexer := cast.ToString(txIndexer["indexer"])
fastNode := cast.ToBool(appOpts.Get("iavl-disable-fastnode"))
var errs []string

if interval > MaxPruningInterval {
errs = append(errs, fmt.Sprintf("pruning-interval %d EXCEEDS %d AND IS NOT RECOMMENDED, AS IT CAN LEAD TO MISSED BLOCKS ON VALIDATORS", interval, MaxPruningInterval))
}
// IssueConfigWarnings checks a few values in the configs and issues warnings and sleeps if appropriate.
func IssueConfigWarnings(logger log.Logger, appOpts servertypes.AppOptions, sleeper Sleeper) {
const MaxPruningInterval = 999
const SleepSeconds = 30
interval := cast.ToUint64(appOpts.Get("pruning-interval"))
txIndexer := cast.ToStringMap(appOpts.Get("tx_index"))
indexer := cast.ToString(txIndexer["indexer"])
fastNode := cast.ToBool(appOpts.Get(server.FlagDisableIAVLFastNode))
backend := server.GetAppDBBackend(appOpts)
var errs []string

if indexer != "" && indexer != "null" {
errs = append(errs, fmt.Sprintf("indexer \"%s\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%s\"", indexer, "null"))
}
if interval > MaxPruningInterval {
errs = append(errs, fmt.Sprintf("pruning-interval %d EXCEEDS %d AND IS NOT RECOMMENDED, AS IT CAN LEAD TO MISSED BLOCKS ON VALIDATORS.", interval, MaxPruningInterval))
}

if fastNode {
errs = append(errs, fmt.Sprintf("iavl-disable-fastnode \"%v\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%v\"", fastNode, !fastNode))
}
if indexer != "" && indexer != "null" {
errs = append(errs, fmt.Sprintf("indexer \"%s\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%s\".", indexer, "null"))
}

if backend != dbm.GoLevelDBBackend {
errs = append(errs, fmt.Sprintf("%s IS NO LONGER SUPPORTED. MIGRATE TO %s", backend, dbm.GoLevelDBBackend))
}
if fastNode {
errs = append(errs, fmt.Sprintf("%s \"%v\" IS NOT RECOMMENDED, AND IT IS RECOMMENDED TO USE \"%v\".", server.FlagDisableIAVLFastNode, fastNode, !fastNode))
}

if backend != dbm.GoLevelDBBackend {
errs = append(errs, fmt.Sprintf("%s IS NO LONGER SUPPORTED. MIGRATE TO %s.", backend, dbm.GoLevelDBBackend))
}

if len(errs) > 0 {
logger.Error(fmt.Sprintf("NODE WILL CONTINUE AFTER %d SECONDS", SleepSeconds))
for _, err := range errs {
logger.Error(err)
}
time.Sleep(SleepSeconds * time.Second)
if len(errs) > 0 {
for _, err := range errs {
logger.Error(err)
}
if !HaveAckWarn() {
logger.Error(fmt.Sprintf("NODE WILL CONTINUE AFTER %d SECONDS.", SleepSeconds))
logger.Error("This wait can be bypassed by fixing the above warnings or setting the PIO_ACKWARN environment variable to \"1\".")
sleeper.Sleep(SleepSeconds * time.Second)
}
}
}

// HaveAckWarn returns true if the PIO_ACKWARN env var is set and isn't a false value (e.g. "0", "f" or "false").
func HaveAckWarn() bool {
ackWarn := strings.TrimSpace(os.Getenv("PIO_ACKWARN"))
if len(ackWarn) == 0 {
return false
}

return sl(ms)
}, storeLoader)
rv, err := strconv.ParseBool(ackWarn)
// We return false only if it parsed successfully to a false value.
// If parsing failed or it parsed to a true value, we return true.
return err != nil || rv
}
Loading

0 comments on commit 21ea2c9

Please sign in to comment.