From 84a3ffefa173694c31ae30423c5bdb127063941d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Irmak?= Date: Wed, 20 Dec 2023 11:06:37 +0300 Subject: [PATCH] Add --db-max-handles (#1587) --- cmd/juno/juno.go | 4 ++++ cmd/juno/juno_test.go | 14 ++++++++++++++ db/pebble/db.go | 7 ++++--- node/node.go | 5 +++-- node/node_test.go | 2 +- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/cmd/juno/juno.go b/cmd/juno/juno.go index f498c27ec1..6a0c50f1a9 100644 --- a/cmd/juno/juno.go +++ b/cmd/juno/juno.go @@ -63,6 +63,7 @@ const ( remoteDBF = "remote-db" rpcMaxBlockScanF = "rpc-max-block-scan" dbCacheSizeF = "db-cache-size" + dbMaxHandlesF = "db-max-handles" gwAPIKeyF = "gw-api-key" //nolint: gosec defaultConfig = "" @@ -86,6 +87,7 @@ const ( defaultRemoteDB = "" defaultRPCMaxBlockScan = math.MaxUint defaultCacheSizeMb = 8 + defaultMaxHandles = 1024 defaultGwAPIKey = "" configFlagUsage = "The yaml configuration file." @@ -119,6 +121,7 @@ const ( remoteDBUsage = "gRPC URL of a remote Juno node" rpcMaxBlockScanUsage = "Maximum number of blocks scanned in single starknet_getEvents call" dbCacheSizeUsage = "Determines the amount of memory (in megabytes) allocated for caching data in the database." + dbMaxHandlesUsage = "A soft limit on the number of open files that can be used by the DB" gwAPIKeyUsage = "API key for gateway endpoints to avoid throttling" //nolint: gosec ) @@ -249,6 +252,7 @@ func NewCmd(config *node.Config, run func(*cobra.Command, []string) error) *cobr junoCmd.Flags().Uint(rpcMaxBlockScanF, defaultRPCMaxBlockScan, rpcMaxBlockScanUsage) junoCmd.Flags().Uint(dbCacheSizeF, defaultCacheSizeMb, dbCacheSizeUsage) junoCmd.Flags().String(gwAPIKeyF, defaultGwAPIKey, gwAPIKeyUsage) + junoCmd.Flags().Int(dbMaxHandlesF, defaultMaxHandles, dbMaxHandlesUsage) return junoCmd } diff --git a/cmd/juno/juno_test.go b/cmd/juno/juno_test.go index d788dfc094..8126abb950 100644 --- a/cmd/juno/juno_test.go +++ b/cmd/juno/juno_test.go @@ -46,6 +46,7 @@ func TestConfigPrecedence(t *testing.T) { defaultMaxVMs := uint(3 * runtime.GOMAXPROCS(0)) defaultRPCMaxBlockScan := uint(math.MaxUint) defaultMaxCacheSize := uint(8) + defaultMaxHandles := 1024 tests := map[string]struct { cfgFile bool @@ -82,6 +83,7 @@ func TestConfigPrecedence(t *testing.T) { MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "config file path is empty string": { @@ -111,6 +113,7 @@ func TestConfigPrecedence(t *testing.T) { MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "config file doesn't exist": { @@ -145,6 +148,7 @@ func TestConfigPrecedence(t *testing.T) { MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "config file with all settings but without any other flags": { @@ -181,6 +185,7 @@ pprof: true MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "config file with some settings but without any other flags": { @@ -214,6 +219,7 @@ http-port: 4576 MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "all flags without config file": { @@ -245,6 +251,7 @@ http-port: 4576 MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "some flags without config file": { @@ -277,6 +284,7 @@ http-port: 4576 MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "all setting set in both config file and flags": { @@ -333,6 +341,7 @@ db-cache-size: 8 MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: 9, + DBMaxHandles: defaultMaxHandles, }, }, "some setting set in both config file and flags": { @@ -368,6 +377,7 @@ network: goerli MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "some setting set in default, config file and flags": { @@ -399,6 +409,7 @@ network: goerli MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "only set env variables": { @@ -428,6 +439,7 @@ network: goerli MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "some setting set in both env variables and flags": { @@ -458,6 +470,7 @@ network: goerli MaxVMQueue: 2 * defaultMaxVMs, RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, + DBMaxHandles: defaultMaxHandles, }, }, "some setting set in both env variables and config file": { @@ -489,6 +502,7 @@ network: goerli RPCMaxBlockScan: defaultRPCMaxBlockScan, DBCacheSize: defaultMaxCacheSize, GatewayAPIKey: "apikey", + DBMaxHandles: defaultMaxHandles, }, }, } diff --git a/db/pebble/db.go b/db/pebble/db.go index 6d5c8a7022..664b69db87 100644 --- a/db/pebble/db.go +++ b/db/pebble/db.go @@ -25,14 +25,15 @@ type DB struct { } // New opens a new database at the given path -func New(path string, cache uint, logger pebble.Logger) (db.DB, error) { +func New(path string, cache uint, maxOpenFiles int, logger pebble.Logger) (db.DB, error) { // Ensure that the specified cache size meets a minimum threshold. if cache < minCache { cache = minCache } pDB, err := newPebble(path, &pebble.Options{ - Logger: logger, - Cache: pebble.NewCache(int64(cache * megabyte)), + Logger: logger, + Cache: pebble.NewCache(int64(cache * megabyte)), + MaxOpenFiles: maxOpenFiles, }) if err != nil { return nil, err diff --git a/node/node.go b/node/node.go index ab96b521b0..2dda6aed76 100644 --- a/node/node.go +++ b/node/node.go @@ -77,7 +77,8 @@ type Config struct { MaxVMQueue uint `mapstructure:"max-vm-queue"` RPCMaxBlockScan uint `mapstructure:"rpc-max-block-scan"` - DBCacheSize uint `mapstructure:"db-cache-size"` + DBCacheSize uint `mapstructure:"db-cache-size"` + DBMaxHandles int `mapstructure:"db-max-handles"` GatewayAPIKey string `mapstructure:"gw-api-key"` } @@ -111,7 +112,7 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen if dbIsRemote { database, err = remote.New(cfg.RemoteDB, context.TODO(), log, grpc.WithTransportCredentials(insecure.NewCredentials())) } else { - database, err = pebble.New(cfg.DatabasePath, cfg.DBCacheSize, dbLog) + database, err = pebble.New(cfg.DatabasePath, cfg.DBCacheSize, cfg.DBMaxHandles, dbLog) } if err != nil { return nil, fmt.Errorf("open DB: %w", err) diff --git a/node/node_test.go b/node/node_test.go index 7cebf7add8..643ab0f7cc 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -67,7 +67,7 @@ func TestNetworkVerificationOnNonEmptyDB(t *testing.T) { t.Run(description, func(t *testing.T) { dbPath := t.TempDir() log := utils.NewNopZapLogger() - database, err := pebble.New(dbPath, 1, log) + database, err := pebble.New(dbPath, 1, 1, log) require.NoError(t, err) chain := blockchain.New(database, network, log) syncer := sync.New(chain, adaptfeeder.New(feeder.NewTestClient(t, network)), log, 0, false)