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

go/oasis-node: Add the debug dumpdb command #2921

Merged
merged 4 commits into from
May 21, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
go/consensus/tendermint/abci: Move storage init into a helper
The dump tool was duplicating a considerable amount of this, so refactor
it out into a helper to minimize code duplication.
Yawning committed May 21, 2020
commit e5d5402474473c6b95c553b67e94f6c41de648f9
3 changes: 3 additions & 0 deletions go/consensus/tendermint/abci/mux.go
Original file line number Diff line number Diff line change
@@ -72,6 +72,9 @@ type ApplicationConfig struct {

// MemoryOnlyStorage forces in-memory storage to be used for the state storage.
MemoryOnlyStorage bool

// ReadOnlyStorage forces read-only access for the state storage.
ReadOnlyStorage bool
}

// TransactionAuthHandler is the interface for ABCI applications that handle
58 changes: 43 additions & 15 deletions go/consensus/tendermint/abci/state.go
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"time"
@@ -359,16 +360,31 @@ func (s *applicationState) pruneWorker() {
}
}

func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicationState, error) {
// InitStateStorage initializes the internal ABCI state storage.
func InitStateStorage(ctx context.Context, cfg *ApplicationConfig) (storage.LocalBackend, storage.NodeDB, *storage.Root, error) {
baseDir := filepath.Join(cfg.DataDir, appStateDir)
if err := common.Mkdir(baseDir); err != nil {
return nil, fmt.Errorf("failed to create application state directory: %w", err)
switch cfg.ReadOnlyStorage {
case true:
// Note: I'm not sure what badger does when given a path that
// doesn't actually contain a database, when it's set to
// read-only. Hopefully it's something sensible.
fi, err := os.Lstat(baseDir)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to stat application state directory: %w", err)
}
if !fi.Mode().IsDir() {
return nil, nil, nil, fmt.Errorf("application state path is not a directory: %v", fi.Mode())
}
default:
if err := common.Mkdir(baseDir); err != nil {
return nil, nil, nil, fmt.Errorf("failed to create application state directory: %w", err)
}
}

switch cfg.StorageBackend {
case storageDB.BackendNameBadgerDB:
default:
return nil, fmt.Errorf("unsupported storage backend: %s", cfg.StorageBackend)
return nil, nil, nil, fmt.Errorf("unsupported storage backend: %s", cfg.StorageBackend)
}

db, err := storageDB.New(&storage.Config{
@@ -378,9 +394,10 @@ func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicat
DiscardWriteLogs: true,
NoFsync: true, // This is safe as Tendermint will replay on crash.
MemoryOnly: cfg.MemoryOnlyStorage,
ReadOnly: cfg.ReadOnlyStorage,
})
if err != nil {
return nil, err
return nil, nil, nil, err
}
ldb := db.(storage.LocalBackend)
ndb := ldb.NodeDB()
@@ -396,33 +413,46 @@ func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicat
// Figure out the latest version/hash if any, and use that as the block height/hash.
latestVersion, err := ndb.GetLatestVersion(ctx)
if err != nil {
return nil, err
return nil, nil, nil, err
}
roots, err := ndb.GetRootsForVersion(ctx, latestVersion)
if err != nil {
return nil, err
return nil, nil, nil, err
}
stateRoot := storage.Root{
stateRoot := &storage.Root{
Version: latestVersion,
}
switch len(roots) {
case 0:
// No roots -- empty database.
if latestVersion != 0 {
return nil, fmt.Errorf("state: no roots at non-zero height, corrupted database?")
return nil, nil, nil, fmt.Errorf("state: no roots at non-zero height, corrupted database?")
}
stateRoot.Hash.Empty()
case 1:
// Exactly one root -- the usual case.
stateRoot.Hash = roots[0]
default:
// More roots -- should not happen for our use case.
return nil, fmt.Errorf("state: more than one root, corrupted database?")
return nil, nil, nil, fmt.Errorf("state: more than one root, corrupted database?")
}

ok = true

return ldb, ndb, stateRoot, nil
}

func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicationState, error) {
// Initialize the state storage.
ldb, ndb, stateRoot, err := InitStateStorage(ctx, cfg)
if err != nil {
return nil, err
}
latestVersion := stateRoot.Version

// Use the node database directly to avoid going through the syncer interface.
deliverTxTree := mkvs.NewWithRoot(nil, ndb, stateRoot, mkvs.WithoutWriteLog())
checkTxTree := mkvs.NewWithRoot(nil, ndb, stateRoot, mkvs.WithoutWriteLog())
deliverTxTree := mkvs.NewWithRoot(nil, ndb, *stateRoot, mkvs.WithoutWriteLog())
checkTxTree := mkvs.NewWithRoot(nil, ndb, *stateRoot, mkvs.WithoutWriteLog())

// Initialize the state pruner.
statePruner, err := newStatePruner(&cfg.Pruning, ndb, latestVersion)
@@ -443,7 +473,7 @@ func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicat
cancelCtx: cancelCtx,
deliverTxTree: deliverTxTree,
checkTxTree: checkTxTree,
stateRoot: stateRoot,
stateRoot: *stateRoot,
storage: ldb,
statePruner: statePruner,
prunerClosedCh: make(chan struct{}),
@@ -462,8 +492,6 @@ func newApplicationState(ctx context.Context, cfg *ApplicationConfig) (*applicat
}
}

ok = true

go s.metricsWorker()
go s.pruneWorker()