Skip to content

Commit c895ec9

Browse files
authored
Merge pull request #6949 from onflow/leo/pebble-storage-db
[Storage Refactor] Init pebble DB in scaffold.
2 parents f00769a + 8299048 commit c895ec9

File tree

8 files changed

+216
-42
lines changed

8 files changed

+216
-42
lines changed

cmd/node_builder.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"time"
66

7+
"github.com/cockroachdb/pebble"
78
"github.com/dgraph-io/badger/v2"
89
madns "github.com/multiformats/go-multiaddr-dns"
910
"github.com/onflow/crypto"
@@ -151,6 +152,9 @@ type BaseConfig struct {
151152
DynamicStartupEpoch string
152153
DynamicStartupSleepInterval time.Duration
153154
datadir string
155+
pebbleDir string
156+
badgerDB *badger.DB
157+
pebbleDB *pebble.DB
154158
secretsdir string
155159
secretsDBEnabled bool
156160
InsecureSecretsDB bool
@@ -164,7 +168,6 @@ type BaseConfig struct {
164168
MetricsEnabled bool
165169
guaranteesCacheSize uint
166170
receiptsCacheSize uint
167-
db *badger.DB
168171
HeroCacheMetricsEnable bool
169172
SyncCoreConfig chainsync.Config
170173
CodecFactory func() network.Codec
@@ -198,6 +201,7 @@ type NodeConfig struct {
198201
MetricsRegisterer prometheus.Registerer
199202
Metrics Metrics
200203
DB *badger.DB
204+
PebbleDB *pebble.DB
201205
SecretsDB *badger.DB
202206
Storage Storage
203207
ProtocolEvents *events.Distributor
@@ -253,6 +257,7 @@ type StateExcerptAtBoot struct {
253257

254258
func DefaultBaseConfig() *BaseConfig {
255259
datadir := "/data/protocol"
260+
pebbleDir := "/data/protocol-pebble"
256261

257262
// NOTE: if the codec used in the network component is ever changed any code relying on
258263
// the message format specific to the codec must be updated. i.e: the AuthorizedSenderValidator.
@@ -269,6 +274,9 @@ func DefaultBaseConfig() *BaseConfig {
269274
ObserverMode: false,
270275
BootstrapDir: "bootstrap",
271276
datadir: datadir,
277+
pebbleDir: pebbleDir,
278+
badgerDB: nil,
279+
pebbleDB: nil,
272280
secretsdir: NotSet,
273281
secretsDBEnabled: true,
274282
level: "info",

cmd/scaffold.go

Lines changed: 88 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"time"
1313

1414
gcemd "cloud.google.com/go/compute/metadata"
15+
"github.com/cockroachdb/pebble"
1516
"github.com/dgraph-io/badger/v2"
1617
"github.com/hashicorp/go-multierror"
1718
dht "github.com/libp2p/go-libp2p-kad-dht"
@@ -20,6 +21,7 @@ import (
2021
"github.com/libp2p/go-libp2p/core/routing"
2122
"github.com/prometheus/client_golang/prometheus"
2223
"github.com/rs/zerolog"
24+
"github.com/rs/zerolog/log"
2325
"github.com/spf13/pflag"
2426
"golang.org/x/time/rate"
2527
"google.golang.org/api/option"
@@ -31,6 +33,7 @@ import (
3133
"github.com/onflow/flow-go/admin/commands/common"
3234
storageCommands "github.com/onflow/flow-go/admin/commands/storage"
3335
"github.com/onflow/flow-go/cmd/build"
36+
"github.com/onflow/flow-go/cmd/scaffold"
3437
"github.com/onflow/flow-go/config"
3538
"github.com/onflow/flow-go/consensus/hotstuff/persister"
3639
"github.com/onflow/flow-go/fvm/initialize"
@@ -164,6 +167,7 @@ func (fnb *FlowNodeBuilder) BaseFlags() {
164167
fnb.flags.StringVar(&fnb.BaseConfig.BindAddr, "bind", defaultConfig.BindAddr, "address to bind on")
165168
fnb.flags.StringVarP(&fnb.BaseConfig.BootstrapDir, "bootstrapdir", "b", defaultConfig.BootstrapDir, "path to the bootstrap directory")
166169
fnb.flags.StringVarP(&fnb.BaseConfig.datadir, "datadir", "d", defaultConfig.datadir, "directory to store the public database (protocol state)")
170+
fnb.flags.StringVar(&fnb.BaseConfig.pebbleDir, "pebble-dir", defaultConfig.pebbleDir, "directory to store the public pebble database (protocol state)")
167171
fnb.flags.StringVar(&fnb.BaseConfig.secretsdir, "secretsdir", defaultConfig.secretsdir, "directory to store private database (secrets)")
168172
fnb.flags.StringVarP(&fnb.BaseConfig.level, "loglevel", "l", defaultConfig.level, "level for logging output")
169173
fnb.flags.Uint32Var(&fnb.BaseConfig.debugLogLimit, "debug-log-limit", defaultConfig.debugLogLimit, "max number of debug/trace log events per second")
@@ -1057,14 +1061,22 @@ func (fnb *FlowNodeBuilder) initProfiler() error {
10571061
return nil
10581062
}
10591063

1060-
func (fnb *FlowNodeBuilder) initDB() error {
1061-
1062-
// if a db has been passed in, use that instead of creating one
1063-
if fnb.BaseConfig.db != nil {
1064-
fnb.DB = fnb.BaseConfig.db
1064+
func (fnb *FlowNodeBuilder) initBadgerDB() error {
1065+
// if the badger DB is already set, use it.
1066+
// the badger DB might be set by the follower engine
1067+
if fnb.BaseConfig.badgerDB != nil {
1068+
fnb.DB = fnb.BaseConfig.badgerDB
10651069
return nil
10661070
}
10671071

1072+
// if the badger DB is not set, then the datadir must be provided to initialize
1073+
// the badger DB
1074+
// since we've set an default directory for the badger DB, this check
1075+
// is not necessary, but rather a sanity check
1076+
if fnb.BaseConfig.datadir == NotSet {
1077+
return fmt.Errorf("missing required flag '--datadir'")
1078+
}
1079+
10681080
// Pre-create DB path (Badger creates only one-level dirs)
10691081
err := os.MkdirAll(fnb.BaseConfig.datadir, 0700)
10701082
if err != nil {
@@ -1111,6 +1123,24 @@ func (fnb *FlowNodeBuilder) initDB() error {
11111123
return nil
11121124
}
11131125

1126+
func (fnb *FlowNodeBuilder) initPebbleDB() error {
1127+
// if the pebble DB is already set, use it
1128+
// the pebble DB might be set by the follower engine
1129+
if fnb.BaseConfig.pebbleDB != nil {
1130+
fnb.PebbleDB = fnb.BaseConfig.pebbleDB
1131+
return nil
1132+
}
1133+
1134+
db, closer, err := scaffold.InitPebbleDB(fnb.BaseConfig.pebbleDir)
1135+
if err != nil {
1136+
return err
1137+
}
1138+
1139+
fnb.PebbleDB = db
1140+
fnb.ShutdownFunc(closer.Close)
1141+
return nil
1142+
}
1143+
11141144
func (fnb *FlowNodeBuilder) initSecretsDB() error {
11151145

11161146
// if the secrets DB is disabled (only applicable for Consensus Follower,
@@ -1888,11 +1918,55 @@ func WithBindAddress(bindAddress string) Option {
18881918
}
18891919
}
18901920

1921+
// WithDataDir set the data directory for the badger database
1922+
// It will be ignored if WithBadgerDB is used
18911923
func WithDataDir(dataDir string) Option {
18921924
return func(config *BaseConfig) {
1893-
if config.db == nil {
1894-
config.datadir = dataDir
1925+
if config.badgerDB != nil {
1926+
log.Warn().Msgf("ignoring data directory %s as badger database is already set", dataDir)
1927+
return
1928+
}
1929+
1930+
config.datadir = dataDir
1931+
}
1932+
}
1933+
1934+
// WithBadgerDB sets the badger database instance
1935+
// If used, then WithDataDir method will be ignored
1936+
func WithBadgerDB(db *badger.DB) Option {
1937+
return func(config *BaseConfig) {
1938+
if config.datadir != "" && config.datadir != NotSet {
1939+
log.Warn().Msgf("ignoring data directory is already set for badger %v", config.datadir)
1940+
config.datadir = ""
18951941
}
1942+
1943+
config.badgerDB = db
1944+
}
1945+
}
1946+
1947+
// WithPebbleDir set the data directory for the pebble database
1948+
// It will be ignored if WithPebbleDB is used
1949+
func WithPebbleDir(dataDir string) Option {
1950+
return func(config *BaseConfig) {
1951+
if config.pebbleDB != nil {
1952+
log.Warn().Msgf("ignoring data directory %s as pebble database is already set", dataDir)
1953+
return
1954+
}
1955+
1956+
config.pebbleDir = dataDir
1957+
}
1958+
}
1959+
1960+
// WithPebbleDB sets the pebble database instance
1961+
// If used, then WithPebbleDir method will be ignored
1962+
func WithPebbleDB(db *pebble.DB) Option {
1963+
return func(config *BaseConfig) {
1964+
if config.pebbleDir != "" && config.pebbleDir != NotSet {
1965+
log.Warn().Msgf("ignoring data directory is already set for pebble %v", config.pebbleDir)
1966+
config.pebbleDir = ""
1967+
}
1968+
1969+
config.pebbleDB = db
18961970
}
18971971
}
18981972

@@ -1926,14 +2000,6 @@ func WithLogLevel(level string) Option {
19262000
}
19272001
}
19282002

1929-
// WithDB takes precedence over WithDataDir and datadir will be set to empty if DB is set using this option
1930-
func WithDB(db *badger.DB) Option {
1931-
return func(config *BaseConfig) {
1932-
config.db = db
1933-
config.datadir = ""
1934-
}
1935-
}
1936-
19372003
// FlowNode creates a new Flow node builder with the given name.
19382004
func FlowNode(role string, opts ...Option) *FlowNodeBuilder {
19392005
config := DefaultBaseConfig()
@@ -2039,7 +2105,13 @@ func (fnb *FlowNodeBuilder) onStart() error {
20392105
return err
20402106
}
20412107

2042-
if err := fnb.initDB(); err != nil {
2108+
// we always initialize both badger and pebble databases
2109+
// even if we only use one of them, this simplify the code and checks
2110+
if err := fnb.initBadgerDB(); err != nil {
2111+
return err
2112+
}
2113+
2114+
if err := fnb.initPebbleDB(); err != nil {
20432115
return err
20442116
}
20452117

cmd/scaffold/pebble_db.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package scaffold
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
8+
"github.com/cockroachdb/pebble"
9+
10+
pebblestorage "github.com/onflow/flow-go/storage/pebble"
11+
)
12+
13+
func InitPebbleDB(dir string) (*pebble.DB, io.Closer, error) {
14+
// if the pebble DB is not set, we skip initialization
15+
// the pebble DB must be provided to initialize
16+
// since we've set an default directory for the pebble DB, this check
17+
// is not necessary, but rather a sanity check
18+
if dir == "not set" {
19+
return nil, nil, fmt.Errorf("missing required flag '--pebble-dir'")
20+
}
21+
22+
// Pre-create DB path
23+
err := os.MkdirAll(dir, 0700)
24+
if err != nil {
25+
return nil, nil, fmt.Errorf("could not create pebble db (path: %s): %w", dir, err)
26+
}
27+
28+
db, err := pebblestorage.OpenDefaultPebbleDB(dir)
29+
if err != nil {
30+
return nil, nil, fmt.Errorf("could not open newly created pebble db (path: %s): %w", dir, err)
31+
}
32+
33+
return db, db, nil
34+
}

cmd/scaffold/pebble_db_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package scaffold_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/onflow/flow-go/cmd"
9+
"github.com/onflow/flow-go/cmd/scaffold"
10+
"github.com/onflow/flow-go/utils/unittest"
11+
)
12+
13+
func TestInitPebbleDB(t *testing.T) {
14+
unittest.RunWithTempDir(t, func(dir string) {
15+
_, closer, err := scaffold.InitPebbleDB(dir)
16+
require.NoError(t, err)
17+
require.NoError(t, closer.Close())
18+
})
19+
}
20+
21+
func TestInitPebbleDBDirNotSet(t *testing.T) {
22+
_, _, err := scaffold.InitPebbleDB(cmd.NotSet)
23+
require.Error(t, err)
24+
require.Contains(t, err.Error(), "missing required flag")
25+
}

follower/consensus_follower.go

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"sync"
77

8+
"github.com/cockroachdb/pebble"
89
"github.com/dgraph-io/badger/v2"
910
"github.com/onflow/crypto"
1011
"github.com/rs/zerolog"
@@ -36,8 +37,8 @@ type Config struct {
3637
networkPrivKey crypto.PrivateKey // the network private key of this node
3738
bootstrapNodes []BootstrapNodeInfo // the bootstrap nodes to use
3839
bindAddr string // address to bind on
39-
db *badger.DB // the badger DB storage to use for the protocol state
40-
dataDir string // directory to store the protocol state (if the badger storage is not provided)
40+
badgerDB *badger.DB // badger instance
41+
pebbleDB *pebble.DB // pebble instance
4142
bootstrapDir string // path to the bootstrap directory
4243
logLevel string // log level
4344
exposeMetrics bool // whether to expose metrics
@@ -47,34 +48,28 @@ type Config struct {
4748

4849
type Option func(c *Config)
4950

50-
// WithDataDir sets the underlying directory to be used to store the database
51-
// If a database is supplied, then data directory will be set to empty string
52-
func WithDataDir(dataDir string) Option {
51+
// currently used by rosetta
52+
func WithDB(db *badger.DB) Option {
5353
return func(cf *Config) {
54-
if cf.db == nil {
55-
cf.dataDir = dataDir
56-
}
54+
cf.badgerDB = db
5755
}
5856
}
5957

60-
func WithBootstrapDir(bootstrapDir string) Option {
58+
func WithPebbleDB(db *pebble.DB) Option {
6159
return func(cf *Config) {
62-
cf.bootstrapDir = bootstrapDir
60+
cf.pebbleDB = db
6361
}
6462
}
6563

66-
func WithLogLevel(level string) Option {
64+
func WithBootstrapDir(bootstrapDir string) Option {
6765
return func(cf *Config) {
68-
cf.logLevel = level
66+
cf.bootstrapDir = bootstrapDir
6967
}
7068
}
7169

72-
// WithDB sets the underlying database that will be used to store the chain state
73-
// WithDB takes precedence over WithDataDir and datadir will be set to empty if DB is set using this option
74-
func WithDB(db *badger.DB) Option {
70+
func WithLogLevel(level string) Option {
7571
return func(cf *Config) {
76-
cf.db = db
77-
cf.dataDir = ""
72+
cf.logLevel = level
7873
}
7974
}
8075

@@ -133,18 +128,18 @@ func getBaseOptions(config *Config) []cmd.Option {
133128
if config.bootstrapDir != "" {
134129
options = append(options, cmd.WithBootstrapDir(config.bootstrapDir))
135130
}
136-
if config.dataDir != "" {
137-
options = append(options, cmd.WithDataDir(config.dataDir))
138-
}
139131
if config.bindAddr != "" {
140132
options = append(options, cmd.WithBindAddress(config.bindAddr))
141133
}
134+
if config.badgerDB != nil {
135+
options = append(options, cmd.WithBadgerDB(config.badgerDB))
136+
}
137+
if config.pebbleDB != nil {
138+
options = append(options, cmd.WithPebbleDB(config.pebbleDB))
139+
}
142140
if config.logLevel != "" {
143141
options = append(options, cmd.WithLogLevel(config.logLevel))
144142
}
145-
if config.db != nil {
146-
options = append(options, cmd.WithDB(config.db))
147-
}
148143
if config.exposeMetrics {
149144
options = append(options, cmd.WithMetricsEnabled(config.exposeMetrics))
150145
}
@@ -187,6 +182,8 @@ func NewConsensusFollower(
187182
networkPrivKey: networkPrivKey,
188183
bootstrapNodes: bootstapIdentities,
189184
bindAddr: bindAddr,
185+
badgerDB: nil,
186+
pebbleDB: nil,
190187
logLevel: "info",
191188
exposeMetrics: false,
192189
}
@@ -206,6 +203,7 @@ func NewConsensusFollower(
206203
anb.FollowerDistributor.AddOnBlockFinalizedConsumer(cf.onBlockFinalized)
207204
cf.NodeConfig = anb.NodeConfig
208205

206+
// Build will initialize the database
209207
cf.Component, err = anb.Build()
210208
if err != nil {
211209
return nil, err

0 commit comments

Comments
 (0)