diff --git a/.github/workflows/ci-rocksdb-build.yml b/.github/workflows/ci-rocksdb-build.yml new file mode 100644 index 0000000000..fea7f0c5e5 --- /dev/null +++ b/.github/workflows/ci-rocksdb-build.yml @@ -0,0 +1,47 @@ +name: Continuous Integration (Rocksdb Build) + +env: + ROCKSDB_VERSION: v8.1.1 + +on: + workflow_call: +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: checkout repo from current commit + uses: actions/checkout@v3 + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: "1.20" + check-latest: true + cache: true + - name: build rocksdb dependency + run: bash ${GITHUB_WORKSPACE}/.github/scripts/install-rocksdb.sh + - name: build application + run: make build COSMOS_BUILD_OPTIONS=rocksdb + test: + runs-on: ubuntu-latest + steps: + - name: install RocksDB dependencies + run: sudo apt-get update + && sudo apt-get install -y git make gcc libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev + - name: install RocksDB as shared library + run: git clone https://github.com/facebook/rocksdb.git + && cd rocksdb + && git checkout $ROCKSDB_VERSION + && sudo make -j$(nproc) install-shared + && sudo ldconfig + - name: checkout repo from current commit + uses: actions/checkout@v3 + with: + submodules: true + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: "1.20" + check-latest: true + cache: true + - name: run unit tests + run: make test-rocksdb diff --git a/Dockerfile-rocksdb b/Dockerfile-rocksdb new file mode 100644 index 0000000000..200fd6e5f7 --- /dev/null +++ b/Dockerfile-rocksdb @@ -0,0 +1,47 @@ +FROM golang:1.20-bullseye AS kava-builder + +# Set up dependencies +RUN apt-get update \ + && apt-get install -y git make gcc libgflags-dev libsnappy-dev zlib1g-dev libbz2-dev liblz4-dev libzstd-dev \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory for the build +WORKDIR /root +# default home directory is /root + +# install rocksdb +ARG rocksdb_version=v8.1.1 +ENV ROCKSDB_VERSION=$rocksdb_version + +RUN git clone https://github.com/facebook/rocksdb.git \ + && cd rocksdb \ + && git checkout $ROCKSDB_VERSION \ + && make -j$(nproc) install-shared \ + && ldconfig + +# Add source files for kava +COPY . kava + +ARG kava_database_backend=rocksdb +ENV KAVA_DATABASE_BACKEND=$kava_database_backend + +# Mount go build and mod caches as container caches, persisted between builder invocations +RUN --mount=type=cache,target=/root/.cache/go-build \ + --mount=type=cache,target=/go/pkg/mod \ + cd kava && make install COSMOS_BUILD_OPTIONS=$KAVA_DATABASE_BACKEND + + +FROM ubuntu:22.04 + +RUN apt-get update \ + && apt-get install -y libsnappy1v5 libgflags2.2 zlib1g libbz2-1.0 curl jq \ + && rm -rf /var/lib/apt/lists/* + +# copy rocksdb shared objects +COPY --from=kava-builder /usr/local/lib/ /usr/local/lib/ +RUN ldconfig + +# copy kava binary +COPY --from=kava-builder /go/bin/kava /bin/kava + +CMD ["kava"] diff --git a/Makefile b/Makefile index 18f0c22c67..afe0294243 100644 --- a/Makefile +++ b/Makefile @@ -278,6 +278,9 @@ test-basic: test test: @go test $$(go list ./... | grep -v 'contrib') +test-rocksdb: + @go test -tags=rocksdb ./cmd/kava/opendb + # Run cli integration tests # `-p 4` to use 4 cores, `-tags cli_test` to tell go not to ignore the cli package # These tests use the `kvd` or `kvcli` binaries in the build dir, or in `$BUILDDIR` if that env var is set. diff --git a/cmd/kava/cmd/root.go b/cmd/kava/cmd/root.go index e195c8c491..2dbffcf67b 100644 --- a/cmd/kava/cmd/root.go +++ b/cmd/kava/cmd/root.go @@ -22,7 +22,11 @@ import ( "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app/params" kavaclient "github.com/kava-labs/kava/client" +<<<<<<< HEAD "github.com/kava-labs/kava/migrate" +======= + "github.com/kava-labs/kava/cmd/kava/opendb" +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) ) // EnvPrefix is the prefix environment variables must have to configure the app. @@ -100,8 +104,22 @@ func addSubCmds(rootCmd *cobra.Command, encodingConfig params.EncodingConfig, de encodingConfig: encodingConfig, } + opts := ethermintserver.StartOptions{ + AppCreator: ac.newApp, + DefaultNodeHome: app.DefaultNodeHome, + DBOpener: opendb.OpenDB, + } // ethermintserver adds additional flags to start the JSON-RPC server for evm support +<<<<<<< HEAD ethermintserver.AddCommands(rootCmd, defaultNodeHome, ac.newApp, ac.appExport, ac.addStartCmdFlags) +======= + ethermintserver.AddCommands( + rootCmd, + opts, + ac.appExport, + ac.addStartCmdFlags, + ) +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) // add keybase, auxiliary RPC, query, and tx child commands rootCmd.AddCommand( diff --git a/cmd/kava/opendb/opendb.go b/cmd/kava/opendb/opendb.go new file mode 100644 index 0000000000..367dfd3f04 --- /dev/null +++ b/cmd/kava/opendb/opendb.go @@ -0,0 +1,18 @@ +//go:build !rocksdb +// +build !rocksdb + +package opendb + +import ( + "path/filepath" + + "github.com/cosmos/cosmos-sdk/server/types" + dbm "github.com/tendermint/tm-db" +) + +// OpenDB is a copy of default DBOpener function used by ethermint, see for details: +// https://github.com/evmos/ethermint/blob/07cf2bd2b1ce9bdb2e44ec42a39e7239292a14af/server/start.go#L647 +func OpenDB(_ types.AppOptions, home string, backendType dbm.BackendType) (dbm.DB, error) { + dataDir := filepath.Join(home, "data") + return dbm.NewDB("application", backendType, dataDir) +} diff --git a/cmd/kava/opendb/opendb_rocksdb.go b/cmd/kava/opendb/opendb_rocksdb.go new file mode 100644 index 0000000000..d8042e1ec9 --- /dev/null +++ b/cmd/kava/opendb/opendb_rocksdb.go @@ -0,0 +1,170 @@ +//go:build rocksdb +// +build rocksdb + +// Copyright 2023 Kava Labs, Inc. +// Copyright 2023 Cronos Labs, Inc. +// +// Derived from https://github.com/crypto-org-chain/cronos@496ce7e +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package opendb + +import ( + "errors" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/cosmos/cosmos-sdk/server/types" + "github.com/linxGnu/grocksdb" + "github.com/spf13/cast" + dbm "github.com/tendermint/tm-db" +) + +var ErrUnexpectedConfiguration = errors.New("unexpected rocksdb configuration, rocksdb should have only one column family named default") + +const ( + // default tm-db block cache size for RocksDB + blockCacheSize = 1 << 30 + + defaultColumnFamilyName = "default" + + maxOpenFilesDBOptName = "max_open_files" + maxFileOpeningThreadsDBOptName = "max_file_opening_threads" + + writeBufferSizeCFOptName = "write_buffer_size" + numLevelsCFOptName = "num_levels" +) + +func OpenDB(appOpts types.AppOptions, home string, backendType dbm.BackendType) (dbm.DB, error) { + dataDir := filepath.Join(home, "data") + if backendType == dbm.RocksDBBackend { + return openRocksdb(filepath.Join(dataDir, "application.db"), appOpts) + } + + return dbm.NewDB("application", backendType, dataDir) +} + +// openRocksdb loads existing options, overrides some of them with appOpts and opens database +// option will be overridden only in case if it explicitly specified in appOpts +func openRocksdb(dir string, appOpts types.AppOptions) (dbm.DB, error) { + dbOpts, cfOpts, err := loadLatestOptions(dir) + if err != nil { + return nil, err + } + // customize rocksdb options + dbOpts = overrideDBOpts(dbOpts, appOpts) + cfOpts = overrideCFOpts(cfOpts, appOpts) + + return newRocksDBWithOptions("application", dir, dbOpts, cfOpts) +} + +// loadLatestOptions loads and returns database and column family options +// if options file not found, it means database isn't created yet, in such case default tm-db options will be returned +// if database exists it should have only one column family named default +func loadLatestOptions(dir string) (*grocksdb.Options, *grocksdb.Options, error) { + latestOpts, err := grocksdb.LoadLatestOptions(dir, grocksdb.NewDefaultEnv(), true, grocksdb.NewLRUCache(blockCacheSize)) + if err != nil && strings.HasPrefix(err.Error(), "NotFound: ") { + return newDefaultOptions(), newDefaultOptions(), nil + } + if err != nil { + return nil, nil, err + } + + cfNames := latestOpts.ColumnFamilyNames() + cfOpts := latestOpts.ColumnFamilyOpts() + // db should have only one column family named default + ok := len(cfNames) == 1 && cfNames[0] == defaultColumnFamilyName + if !ok { + return nil, nil, ErrUnexpectedConfiguration + } + + // return db and cf opts + return latestOpts.Options(), &cfOpts[0], nil +} + +// overrideDBOpts merges dbOpts and appOpts, appOpts takes precedence +func overrideDBOpts(dbOpts *grocksdb.Options, appOpts types.AppOptions) *grocksdb.Options { + maxOpenFiles := appOpts.Get(maxOpenFilesDBOptName) + if maxOpenFiles != nil { + dbOpts.SetMaxOpenFiles(cast.ToInt(maxOpenFiles)) + } + + maxFileOpeningThreads := appOpts.Get(maxFileOpeningThreadsDBOptName) + if maxFileOpeningThreads != nil { + dbOpts.SetMaxFileOpeningThreads(cast.ToInt(maxFileOpeningThreads)) + } + + return dbOpts +} + +// overrideCFOpts merges cfOpts and appOpts, appOpts takes precedence +func overrideCFOpts(cfOpts *grocksdb.Options, appOpts types.AppOptions) *grocksdb.Options { + writeBufferSize := appOpts.Get(writeBufferSizeCFOptName) + if writeBufferSize != nil { + cfOpts.SetWriteBufferSize(cast.ToUint64(writeBufferSize)) + } + + numLevels := appOpts.Get(numLevelsCFOptName) + if numLevels != nil { + cfOpts.SetNumLevels(cast.ToInt(numLevels)) + } + + return cfOpts +} + +// newRocksDBWithOptions opens rocksdb with provided database and column family options +// newRocksDBWithOptions expects that db has only one column family named default +func newRocksDBWithOptions(name string, dir string, dbOpts, cfOpts *grocksdb.Options) (*dbm.RocksDB, error) { + dbPath := filepath.Join(dir, name+".db") + + // Ensure path exists + if err := os.MkdirAll(dbPath, 0755); err != nil { + return nil, fmt.Errorf("failed to create db path: %w", err) + } + + db, _, err := grocksdb.OpenDbColumnFamilies(dbOpts, dbPath, []string{defaultColumnFamilyName}, []*grocksdb.Options{cfOpts}) + if err != nil { + return nil, err + } + ro := grocksdb.NewDefaultReadOptions() + wo := grocksdb.NewDefaultWriteOptions() + woSync := grocksdb.NewDefaultWriteOptions() + woSync.SetSync(true) + return dbm.NewRocksDBWithRawDB(db, ro, wo, woSync), nil +} + +// newDefaultOptions returns default tm-db options for RocksDB, see for details: +// https://github.com/Kava-Labs/tm-db/blob/94ff76d31724965f8883cddebabe91e0d01bc03f/rocksdb.go#L30 +func newDefaultOptions() *grocksdb.Options { + // default rocksdb option, good enough for most cases, including heavy workloads. + // 1GB table cache, 512MB write buffer(may use 50% more on heavy workloads). + // compression: snappy as default, need to -lsnappy to enable. + bbto := grocksdb.NewDefaultBlockBasedTableOptions() + bbto.SetBlockCache(grocksdb.NewLRUCache(1 << 30)) + bbto.SetFilterPolicy(grocksdb.NewBloomFilter(10)) + + opts := grocksdb.NewDefaultOptions() + opts.SetBlockBasedTableFactory(bbto) + // SetMaxOpenFiles to 4096 seems to provide a reliable performance boost + opts.SetMaxOpenFiles(4096) + opts.SetCreateIfMissing(true) + opts.IncreaseParallelism(runtime.NumCPU()) + // 1.5GB maximum memory use for writebuffer. + opts.OptimizeLevelStyleCompaction(512 * 1024 * 1024) + + return opts +} diff --git a/cmd/kava/opendb/opendb_rocksdb_test.go b/cmd/kava/opendb/opendb_rocksdb_test.go new file mode 100644 index 0000000000..a7eafa92d6 --- /dev/null +++ b/cmd/kava/opendb/opendb_rocksdb_test.go @@ -0,0 +1,357 @@ +//go:build rocksdb +// +build rocksdb + +package opendb + +import ( + "os" + "path/filepath" + "testing" + + "github.com/linxGnu/grocksdb" + "github.com/stretchr/testify/require" +) + +type mockAppOptions struct { + opts map[string]interface{} +} + +func newMockAppOptions(opts map[string]interface{}) *mockAppOptions { + return &mockAppOptions{ + opts: opts, + } +} + +func (m *mockAppOptions) Get(key string) interface{} { + return m.opts[key] +} + +func TestOpenRocksdb(t *testing.T) { + t.Run("db already exists", func(t *testing.T) { + defaultOpts := newDefaultOptions() + + for _, tc := range []struct { + desc string + mockAppOptions *mockAppOptions + maxOpenFiles int + maxFileOpeningThreads int + writeBufferSize uint64 + numLevels int + }{ + { + desc: "default options", + mockAppOptions: newMockAppOptions(map[string]interface{}{}), + maxOpenFiles: defaultOpts.GetMaxOpenFiles(), + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + writeBufferSize: defaultOpts.GetWriteBufferSize(), + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "change 2 options", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + maxOpenFilesDBOptName: 999, + writeBufferSizeCFOptName: 999_999, + }), + maxOpenFiles: 999, + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + writeBufferSize: 999_999, + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "change 4 options", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + maxOpenFilesDBOptName: 999, + maxFileOpeningThreadsDBOptName: 9, + writeBufferSizeCFOptName: 999_999, + numLevelsCFOptName: 9, + }), + maxOpenFiles: 999, + maxFileOpeningThreads: 9, + writeBufferSize: 999_999, + numLevels: 9, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + dir, err := os.MkdirTemp("", "rocksdb") + require.NoError(t, err) + defer func() { + err := os.RemoveAll(dir) + require.NoError(t, err) + }() + + db, err := openRocksdb(dir, tc.mockAppOptions) + require.NoError(t, err) + require.NoError(t, db.Close()) + + dbOpts, cfOpts, err := loadLatestOptions(filepath.Join(dir, "application.db")) + require.NoError(t, err) + require.Equal(t, tc.maxOpenFiles, dbOpts.GetMaxOpenFiles()) + require.Equal(t, tc.maxFileOpeningThreads, dbOpts.GetMaxFileOpeningThreads()) + require.Equal(t, tc.writeBufferSize, cfOpts.GetWriteBufferSize()) + require.Equal(t, tc.numLevels, cfOpts.GetNumLevels()) + }) + } + }) + + t.Run("db doesn't exist yet", func(t *testing.T) { + defaultOpts := newDefaultOptions() + + dir, err := os.MkdirTemp("", "rocksdb") + require.NoError(t, err) + defer func() { + err := os.RemoveAll(dir) + require.NoError(t, err) + }() + + mockAppOpts := newMockAppOptions(map[string]interface{}{}) + db, err := openRocksdb(dir, mockAppOpts) + require.NoError(t, err) + require.NoError(t, db.Close()) + + dbOpts, cfOpts, err := loadLatestOptions(filepath.Join(dir, "application.db")) + require.NoError(t, err) + require.Equal(t, defaultOpts.GetMaxOpenFiles(), dbOpts.GetMaxOpenFiles()) + require.Equal(t, defaultOpts.GetMaxFileOpeningThreads(), dbOpts.GetMaxFileOpeningThreads()) + require.Equal(t, defaultOpts.GetWriteBufferSize(), cfOpts.GetWriteBufferSize()) + require.Equal(t, defaultOpts.GetNumLevels(), cfOpts.GetNumLevels()) + }) +} + +func TestLoadLatestOptions(t *testing.T) { + t.Run("db already exists", func(t *testing.T) { + defaultOpts := newDefaultOptions() + + const testCasesNum = 3 + dbOptsList := make([]*grocksdb.Options, testCasesNum) + cfOptsList := make([]*grocksdb.Options, testCasesNum) + + dbOptsList[0] = newDefaultOptions() + cfOptsList[0] = newDefaultOptions() + + dbOptsList[1] = newDefaultOptions() + dbOptsList[1].SetMaxOpenFiles(999) + cfOptsList[1] = newDefaultOptions() + cfOptsList[1].SetWriteBufferSize(999_999) + + dbOptsList[2] = newDefaultOptions() + dbOptsList[2].SetMaxOpenFiles(999) + dbOptsList[2].SetMaxFileOpeningThreads(9) + cfOptsList[2] = newDefaultOptions() + cfOptsList[2].SetWriteBufferSize(999_999) + cfOptsList[2].SetNumLevels(9) + + for _, tc := range []struct { + desc string + dbOpts *grocksdb.Options + cfOpts *grocksdb.Options + maxOpenFiles int + maxFileOpeningThreads int + writeBufferSize uint64 + numLevels int + }{ + { + desc: "default options", + dbOpts: dbOptsList[0], + cfOpts: cfOptsList[0], + maxOpenFiles: defaultOpts.GetMaxOpenFiles(), + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + writeBufferSize: defaultOpts.GetWriteBufferSize(), + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "change 2 options", + dbOpts: dbOptsList[1], + cfOpts: cfOptsList[1], + maxOpenFiles: 999, + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + writeBufferSize: 999_999, + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "change 4 options", + dbOpts: dbOptsList[2], + cfOpts: cfOptsList[2], + maxOpenFiles: 999, + maxFileOpeningThreads: 9, + writeBufferSize: 999_999, + numLevels: 9, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + name := "application" + dir, err := os.MkdirTemp("", "rocksdb") + require.NoError(t, err) + defer func() { + err := os.RemoveAll(dir) + require.NoError(t, err) + }() + + db, err := newRocksDBWithOptions(name, dir, tc.dbOpts, tc.cfOpts) + require.NoError(t, err) + require.NoError(t, db.Close()) + + dbOpts, cfOpts, err := loadLatestOptions(filepath.Join(dir, "application.db")) + require.NoError(t, err) + require.Equal(t, tc.maxOpenFiles, dbOpts.GetMaxOpenFiles()) + require.Equal(t, tc.maxFileOpeningThreads, dbOpts.GetMaxFileOpeningThreads()) + require.Equal(t, tc.writeBufferSize, cfOpts.GetWriteBufferSize()) + require.Equal(t, tc.numLevels, cfOpts.GetNumLevels()) + }) + } + }) + + t.Run("db doesn't exist yet", func(t *testing.T) { + defaultOpts := newDefaultOptions() + + dir, err := os.MkdirTemp("", "rocksdb") + require.NoError(t, err) + defer func() { + err := os.RemoveAll(dir) + require.NoError(t, err) + }() + + dbOpts, cfOpts, err := loadLatestOptions(filepath.Join(dir, "application.db")) + require.NoError(t, err) + require.Equal(t, defaultOpts.GetMaxOpenFiles(), dbOpts.GetMaxOpenFiles()) + require.Equal(t, defaultOpts.GetMaxFileOpeningThreads(), dbOpts.GetMaxFileOpeningThreads()) + require.Equal(t, defaultOpts.GetWriteBufferSize(), cfOpts.GetWriteBufferSize()) + require.Equal(t, defaultOpts.GetNumLevels(), cfOpts.GetNumLevels()) + }) +} + +func TestOverrideDBOpts(t *testing.T) { + defaultOpts := newDefaultOptions() + + for _, tc := range []struct { + desc string + mockAppOptions *mockAppOptions + maxOpenFiles int + maxFileOpeningThreads int + }{ + { + desc: "override nothing", + mockAppOptions: newMockAppOptions(map[string]interface{}{}), + maxOpenFiles: defaultOpts.GetMaxOpenFiles(), + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + }, + { + desc: "override max-open-files", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + maxOpenFilesDBOptName: 999, + }), + maxOpenFiles: 999, + maxFileOpeningThreads: defaultOpts.GetMaxFileOpeningThreads(), + }, + { + desc: "override max-file-opening-threads", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + maxFileOpeningThreadsDBOptName: 9, + }), + maxOpenFiles: defaultOpts.GetMaxOpenFiles(), + maxFileOpeningThreads: 9, + }, + { + desc: "override max-open-files and max-file-opening-threads", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + maxOpenFilesDBOptName: 999, + maxFileOpeningThreadsDBOptName: 9, + }), + maxOpenFiles: 999, + maxFileOpeningThreads: 9, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + dbOpts := newDefaultOptions() + dbOpts = overrideDBOpts(dbOpts, tc.mockAppOptions) + + require.Equal(t, tc.maxOpenFiles, dbOpts.GetMaxOpenFiles()) + require.Equal(t, tc.maxFileOpeningThreads, dbOpts.GetMaxFileOpeningThreads()) + }) + } +} + +func TestOverrideCFOpts(t *testing.T) { + defaultOpts := newDefaultOptions() + + for _, tc := range []struct { + desc string + mockAppOptions *mockAppOptions + writeBufferSize uint64 + numLevels int + }{ + { + desc: "override nothing", + mockAppOptions: newMockAppOptions(map[string]interface{}{}), + writeBufferSize: defaultOpts.GetWriteBufferSize(), + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "override write-buffer-size", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + writeBufferSizeCFOptName: 999_999, + }), + writeBufferSize: 999_999, + numLevels: defaultOpts.GetNumLevels(), + }, + { + desc: "override num-levels", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + numLevelsCFOptName: 9, + }), + writeBufferSize: defaultOpts.GetWriteBufferSize(), + numLevels: 9, + }, + { + desc: "override write-buffer-size and num-levels", + mockAppOptions: newMockAppOptions(map[string]interface{}{ + writeBufferSizeCFOptName: 999_999, + numLevelsCFOptName: 9, + }), + writeBufferSize: 999_999, + numLevels: 9, + }, + } { + t.Run(tc.desc, func(t *testing.T) { + cfOpts := newDefaultOptions() + cfOpts = overrideCFOpts(cfOpts, tc.mockAppOptions) + + require.Equal(t, tc.writeBufferSize, cfOpts.GetWriteBufferSize()) + require.Equal(t, tc.numLevels, cfOpts.GetNumLevels()) + }) + } +} + +func TestNewRocksDBWithOptions(t *testing.T) { + defaultOpts := newDefaultOptions() + + name := "application" + dir, err := os.MkdirTemp("", "rocksdb") + require.NoError(t, err) + defer func() { + err := os.RemoveAll(dir) + require.NoError(t, err) + }() + + dbOpts := newDefaultOptions() + dbOpts.SetMaxOpenFiles(999) + cfOpts := newDefaultOptions() + cfOpts.SetWriteBufferSize(999_999) + + db, err := newRocksDBWithOptions(name, dir, dbOpts, cfOpts) + require.NoError(t, err) + require.NoError(t, db.Close()) + + dbOpts, cfOpts, err = loadLatestOptions(filepath.Join(dir, "application.db")) + require.NoError(t, err) + require.Equal(t, 999, dbOpts.GetMaxOpenFiles()) + require.Equal(t, defaultOpts.GetMaxFileOpeningThreads(), dbOpts.GetMaxFileOpeningThreads()) + require.Equal(t, uint64(999_999), cfOpts.GetWriteBufferSize()) + require.Equal(t, defaultOpts.GetNumLevels(), dbOpts.GetNumLevels()) +} + +func TestNewDefaultOptions(t *testing.T) { + defaultOpts := newDefaultOptions() + + maxOpenFiles := defaultOpts.GetMaxOpenFiles() + require.Equal(t, 4096, maxOpenFiles) +} diff --git a/go.mod b/go.mod index a63b666236..d7b086f178 100644 --- a/go.mod +++ b/go.mod @@ -13,12 +13,23 @@ require ( github.com/golang/protobuf v1.5.2 github.com/gorilla/mux v1.8.0 github.com/grpc-ecosystem/grpc-gateway v1.16.0 +<<<<<<< HEAD github.com/kava-labs/kava-bridge v0.2.0 github.com/prometheus/client_golang v1.12.2 github.com/spf13/cast v1.5.0 github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.0 github.com/tendermint/tendermint v0.34.21 +======= + github.com/linxGnu/grocksdb v1.8.0 + github.com/pelletier/go-toml/v2 v2.0.6 + github.com/spf13/cast v1.5.0 + github.com/spf13/cobra v1.6.1 + github.com/spf13/viper v1.15.0 + github.com/stretchr/testify v1.8.3 + github.com/subosito/gotenv v1.4.2 + github.com/tendermint/tendermint v0.34.27 +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) github.com/tendermint/tm-db v0.6.7 github.com/tharsis/ethermint v0.14.0 google.golang.org/genproto v0.0.0-20220725144611-272f38e5d71b @@ -98,10 +109,17 @@ require ( github.com/klauspost/compress v1.15.9 // indirect github.com/lib/pq v1.10.6 // indirect github.com/libp2p/go-buffer-pool v0.1.0 // indirect +<<<<<<< HEAD github.com/linxGnu/grocksdb v1.7.1 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect +======= + github.com/magiconair/properties v1.8.7 // indirect + github.com/manifoldco/promptui v0.9.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.17 // indirect +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) github.com/mattn/go-runewidth v0.0.9 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect @@ -169,10 +187,19 @@ replace ( github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.7.0 // Use the cosmos modified protobufs github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 +<<<<<<< HEAD // Use rocksdb 7.1.2 github.com/tendermint/tm-db => github.com/kava-labs/tm-db v0.6.7-kava.1 // Use ethermint fork that respects min-gas-price with NoBaseFee true and london enabled, newProto w/ height parameter github.com/tharsis/ethermint => github.com/Kava-Labs/ethermint v0.14.0-kava-v18.2 // Make sure that we use grpc compatible with cosmos google.golang.org/grpc => google.golang.org/grpc v1.33.2 +======= + // Downgraded to avoid bugs in following commits which causes "version does not exist" errors + github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 + // Use cometbft fork of tendermint + github.com/tendermint/tendermint => github.com/kava-labs/cometbft v0.34.27-kava.0 + // Indirect dependencies still use tendermint/tm-db + github.com/tendermint/tm-db => github.com/kava-labs/tm-db v0.6.7-kava.4 +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) ) diff --git a/go.sum b/go.sum index 7f39098310..b79c2a01d1 100644 --- a/go.sum +++ b/go.sum @@ -566,6 +566,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= github.com/karalabe/usb v0.0.2/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= +<<<<<<< HEAD github.com/kava-labs/cosmos-sdk v0.45.9-kava.1 h1:1oaPsDNuLT+0tZtoN0SkJg1LngNnm6KMYwgETGKt2Mo= github.com/kava-labs/cosmos-sdk v0.45.9-kava.1/go.mod h1:Z5M4TX7PsHNHlF/1XanI2DIpORQ+Q/st7oaeufEjnvU= github.com/kava-labs/kava-bridge v0.2.0 h1:5t9AsPUy9Riwi+gRLgozhv0dut/xQcvRF+yIB+wLuo8= @@ -574,6 +575,18 @@ github.com/kava-labs/tm-db v0.6.7-kava.1 h1:7cVYlvWx1yP+gGdaAWcfm6NwMLzf4z6DxXgu github.com/kava-labs/tm-db v0.6.7-kava.1/go.mod h1:HVZfZzWXuqWseXQVplxsWXK6kLHLkk3kQB6c+nuSZvk= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= +======= +github.com/kava-labs/cometbft v0.34.27-kava.0 h1:FUEGRkF3xtrJH+h9A5G4eA2skf7QaNoOCPaoVqHkh8k= +github.com/kava-labs/cometbft v0.34.27-kava.0/go.mod h1:BcCbhKv7ieM0KEddnYXvQZR+pZykTKReJJYf7YC7qhw= +github.com/kava-labs/cometbft-db v0.7.0-rocksdb-v7.9.2-kava.1 h1:EZnZAkZ+dqK+1OM4AK+e6wYH8a5xuyg4yFTR4Ez3AXk= +github.com/kava-labs/cometbft-db v0.7.0-rocksdb-v7.9.2-kava.1/go.mod h1:mI/4J4IxRzPrXvMiwefrt0fucGwaQ5Hm9IKS7HnoJeI= +github.com/kava-labs/cosmos-sdk v0.46.11-kava.1 h1:3VRpm4zf/gQgmpRVd1p99/2P8ZecAu2FVAXHru5caIo= +github.com/kava-labs/cosmos-sdk v0.46.11-kava.1/go.mod h1:bG4AkW9bqc8ycrryyKGQEl3YV9BY2wr6HggGq8kvcgM= +github.com/kava-labs/ethermint v0.21.0-kava-v23-1 h1:5TSyCtPvFdMuSe8p2iMVqXmFBlK3lHyjaT9EqN752aI= +github.com/kava-labs/ethermint v0.21.0-kava-v23-1/go.mod h1:rdm6AinxZ4dzPEv/cjH+/AGyTbKufJ3RE7M2MDyklH0= +github.com/kava-labs/tm-db v0.6.7-kava.4 h1:M2RibOKmbi+k2OhAFry8z9+RJF0CYuDETB7/PrSdoro= +github.com/kava-labs/tm-db v0.6.7-kava.4/go.mod h1:70tpLhNfwCP64nAlq+bU+rOiVfWr3Nnju1D1nhGDGKs= +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= @@ -611,8 +624,13 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6 github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +<<<<<<< HEAD github.com/linxGnu/grocksdb v1.7.1 h1:KBdzX2OQ6tZcZglsRdBwZmGpwHTEb+VqXR5iLuh72+Q= github.com/linxGnu/grocksdb v1.7.1/go.mod h1:Puj0cSlfTWTp9UdIBijNtNrudkMXXu4er2g+p+CvlJo= +======= +github.com/linxGnu/grocksdb v1.8.0 h1:H4L/LhP7GOMf1j17oQAElHgVlbEje2h14A8Tz9cM2BE= +github.com/linxGnu/grocksdb v1.8.0/go.mod h1:09CeBborffXhXdNpEcOeZrLKEnRtrZFEpFdPNI9Zjjg= +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= @@ -894,9 +912,17 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +<<<<<<< HEAD github.com/subosito/gotenv v1.4.0 h1:yAzM1+SmVcz5R4tXGsNMu1jUl2aOJXoiWUCEwwnGrvs= github.com/subosito/gotenv v1.4.0/go.mod h1:mZd6rFysKEcUhUHXJk0C/08wAgyDBFuwEYL7vWWGaGo= github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= +======= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= +github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +>>>>>>> 90fbe1aa (Make rocksdb configurable (#1658)) github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=