Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion .github/workflows/rocksdb-unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jobs:
run: |
export CGO_CFLAGS="-I/usr/local/include"
export CGO_LDFLAGS="-L/usr/local/lib -lrocksdb -lz -lbz2 -lsnappy -llz4 -lzstd -ljemalloc"
go test -v -mod=readonly -tags=rocksdbBackend ./sei-db/ss/rocksdb/... -covermode=atomic -coverprofile=./rdb-profile.out
go test -v -mod=readonly -tags=rocksdbBackend ./sei-db/db_engine/rocksdb/... -covermode=atomic -coverprofile=./rdb-profile.out
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
Expand Down
4 changes: 2 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ import (
evmrpcconfig "github.com/sei-protocol/sei-chain/evmrpc/config"
"github.com/sei-protocol/sei-chain/precompiles"
putils "github.com/sei-protocol/sei-chain/precompiles/utils"
"github.com/sei-protocol/sei-chain/sei-db/ss"
seidb "github.com/sei-protocol/sei-chain/sei-db/ss/types"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss"
seidb "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
"github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer"
ibctransferkeeper "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/keeper"
ibctransfertypes "github.com/sei-protocol/sei-chain/sei-ibc-go/modules/apps/transfer/types"
Expand Down
2 changes: 1 addition & 1 deletion app/seidb.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/storev2/rootmulti"
"github.com/sei-protocol/sei-chain/sei-db/config"
seidb "github.com/sei-protocol/sei-chain/sei-db/ss/types"
seidb "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
"github.com/spf13/cast"
"github.com/tendermint/tendermint/libs/log"
)
Expand Down
4 changes: 2 additions & 2 deletions app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
ssconfig "github.com/sei-protocol/sei-chain/sei-db/config"
"github.com/sei-protocol/sei-chain/sei-db/ss"
seidbtypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss"
seidbtypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
"github.com/sei-protocol/sei-chain/sei-wasmd/x/wasm"
wasmkeeper "github.com/sei-protocol/sei-chain/sei-wasmd/x/wasm/keeper"
"github.com/stretchr/testify/suite"
Expand Down
2 changes: 1 addition & 1 deletion evmrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/sei-protocol/sei-chain/app/legacyabci"
evmrpcconfig "github.com/sei-protocol/sei-chain/evmrpc/config"
"github.com/sei-protocol/sei-chain/evmrpc/stats"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
evmCfg "github.com/sei-protocol/sei-chain/x/evm/config"
"github.com/sei-protocol/sei-chain/x/evm/keeper"
"github.com/tendermint/tendermint/libs/log"
Expand Down
2 changes: 1 addition & 1 deletion evmrpc/simulate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
"github.com/sei-protocol/sei-chain/app/legacyabci"
"github.com/sei-protocol/sei-chain/evmrpc"
"github.com/sei-protocol/sei-chain/example/contracts/simplestorage"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
testkeeper "github.com/sei-protocol/sei-chain/testutil/keeper"
"github.com/sei-protocol/sei-chain/x/evm/types"
"github.com/stretchr/testify/require"
Expand Down
2 changes: 1 addition & 1 deletion evmrpc/watermark_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/rpc"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
rpcclient "github.com/tendermint/tendermint/rpc/client"
"github.com/tendermint/tendermint/rpc/coretypes"
)
Expand Down
2 changes: 1 addition & 1 deletion evmrpc/watermark_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

proto "github.com/sei-protocol/sei-chain/sei-db/proto"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"

abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/bytes"
Expand Down
56 changes: 4 additions & 52 deletions go.work.sum

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions sei-cosmos/storev2/commitment/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/kv"
sctypes "github.com/sei-protocol/sei-chain/sei-db/sc/types"
sctypes "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/types"
iavl "github.com/sei-protocol/sei-chain/sei-iavl"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
Expand All @@ -25,12 +25,12 @@ var (

// Store Implements types.KVStore and CommitKVStore.
type Store struct {
tree sctypes.Tree
tree sctypes.ModuleStore
logger log.Logger
changeSet iavl.ChangeSet
}

func NewStore(tree sctypes.Tree, logger log.Logger) *Store {
func NewStore(tree sctypes.ModuleStore, logger log.Logger) *Store {
return &Store{
tree: tree,
logger: logger,
Expand Down
2 changes: 1 addition & 1 deletion sei-cosmos/storev2/commitment/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"

"github.com/cosmos/cosmos-sdk/store/types"
"github.com/sei-protocol/sei-chain/sei-db/sc/memiavl"
"github.com/sei-protocol/sei-chain/sei-db/state_db/sc/memiavl"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/log"
)
Expand Down
16 changes: 8 additions & 8 deletions sei-cosmos/storev2/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ import (
commonerrors "github.com/sei-protocol/sei-chain/sei-db/common/errors"
"github.com/sei-protocol/sei-chain/sei-db/config"
"github.com/sei-protocol/sei-chain/sei-db/proto"
"github.com/sei-protocol/sei-chain/sei-db/sc"
sctypes "github.com/sei-protocol/sei-chain/sei-db/sc/types"
"github.com/sei-protocol/sei-chain/sei-db/ss"
"github.com/sei-protocol/sei-chain/sei-db/ss/pruning"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
"github.com/sei-protocol/sei-chain/sei-db/state_db/sc"
sctypes "github.com/sei-protocol/sei-chain/sei-db/state_db/sc/types"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss"
"github.com/sei-protocol/sei-chain/sei-db/state_db/ss/pruning"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
Expand Down Expand Up @@ -275,7 +275,7 @@ func (rs *Store) CacheMultiStoreForExport(version int64) (types.CacheMultiStore,
}
for k, store := range rs.ckvStores {
if store.GetStoreType() == types.StoreTypeIAVL {
tree := scStore.GetTreeByName(k.Name())
tree := scStore.GetModuleByName(k.Name())
stores[k] = commitment.NewStore(tree, rs.logger)
}
}
Expand Down Expand Up @@ -439,7 +439,7 @@ func (rs *Store) loadCommitStoreFromParams(key types.StoreKey, params storeParam
case types.StoreTypeMulti:
panic("recursive MultiStores not yet supported")
case types.StoreTypeIAVL:
tree := rs.scStore.GetTreeByName(key.Name())
tree := rs.scStore.GetModuleByName(key.Name())
if tree == nil {
return nil, fmt.Errorf("new store is not added in upgrades: %s", key.Name())
}
Expand Down Expand Up @@ -550,7 +550,7 @@ func (rs *Store) Query(req abci.RequestQuery) abci.ResponseQuery {
return sdkerrors.QueryResult(err)
}
defer scStore.Close()
store = types.Queryable(commitment.NewStore(scStore.GetTreeByName(storeName), rs.logger))
store = types.Queryable(commitment.NewStore(scStore.GetModuleByName(storeName), rs.logger))
commitInfo = convertCommitInfo(scStore.LastCommitInfo())
commitInfo = amendCommitInfo(commitInfo, rs.storesParams)
}
Expand Down
2 changes: 1 addition & 1 deletion sei-cosmos/storev2/state/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/kv"
sstypes "github.com/sei-protocol/sei-chain/sei-db/ss/types"
sstypes "github.com/sei-protocol/sei-chain/sei-db/state_db/ss/types"
abci "github.com/tendermint/tendermint/abci/types"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"path/filepath"
"time"

"github.com/sei-protocol/sei-chain/sei-db/changelog/types"
errorutils "github.com/sei-protocol/sei-chain/sei-db/common/errors"
"github.com/sei-protocol/sei-chain/sei-db/common/logger"
"github.com/sei-protocol/sei-chain/sei-db/proto"
"github.com/sei-protocol/sei-chain/sei-db/stream/types"
"github.com/tidwall/wal"
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package changelog
import (
"fmt"

"github.com/sei-protocol/sei-chain/sei-db/changelog/types"
"github.com/sei-protocol/sei-chain/sei-db/proto"
"github.com/sei-protocol/sei-chain/sei-db/stream/types"
)

var _ types.Subscriber[proto.ChangelogEntry] = (*Subscriber)(nil)
Expand Down
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions sei-db/db_engine/parquet/placeholder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package parquet
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

104 changes: 104 additions & 0 deletions sei-db/db_engine/pebbledb/kv/batch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package pebbledb

import (
"encoding/binary"
goerrors "errors"
"fmt"

"github.com/cockroachdb/pebble"
)

const (
currentVersionKey = "s/_meta/version" // the key name of the version.
VersionSize = 8 // the number of bytes needed to store the version.
)

// Batch is a set of modifications to apply to the store.
type Batch struct {
db *pebble.DB
batch *pebble.Batch
writeOps *pebble.WriteOptions
}

// NewBatch creates new batch.
func NewBatch(db *pebble.DB) *Batch {
batch := db.NewBatch()
return &Batch{
db: db,
batch: batch,
writeOps: pebble.NoSync,
}
}

// Size returns number of operations in the batch.
func (b *Batch) Size() int {
return b.batch.Len()
}

// Reset resets the batch.
func (b *Batch) Reset() {
b.batch.Reset()
}

// Set sets key.
func (b *Batch) Set(key, value []byte) error {
if err := b.batch.Set(key, value, nil); err != nil {
return fmt.Errorf("failed to write PebbleDB batch: %w", err)
}
return nil
}

// SetCurrentVersion sets the version metadata.
func (b *Batch) SetCurrentVersion(version uint64) error {
var versionBz [VersionSize]byte
binary.LittleEndian.PutUint64(versionBz[:], version)
if err := b.batch.Set([]byte(currentVersionKey), versionBz[:], nil); err != nil {
return fmt.Errorf("failed to write current version to PebbleDB batch: %w", err)
}
return nil
}

// Delete deletes key from the store.
func (b *Batch) Delete(key []byte) error {
return b.batch.Delete(key, nil)
}

// Commit commits changes.
func (b *Batch) Commit() (err error) {
defer func() {
err = goerrors.Join(err, b.batch.Close())
}()

return b.batch.Commit(b.writeOps)
}

// SetByStore sets key in the store.
func (b *Batch) SetByStore(storeKey string, key, value []byte) error {
prefixedKey := prependStoreKey(storeKey, key)
if err := b.batch.Set(prefixedKey, value, nil); err != nil {
return fmt.Errorf("failed to write PebbleDB batch: %w", err)
}
return nil
}

// DeleteByStore deletes key from the store.
func (b *Batch) DeleteByStore(storeKey string, key []byte) error {
prefixedKey := prependStoreKey(storeKey, key)
return b.batch.Delete(prefixedKey, nil)
}

func getStorePrefix(storeKey string) []byte {
// "s/k:" + storeKey + "/"
b := make([]byte, 0, len("s/k:/")+len(storeKey))
b = append(b, "s/k:"...)
b = append(b, storeKey...)
b = append(b, '/')
return b
}

func prependStoreKey(storeKey string, key []byte) []byte {
if storeKey == "" {
return key
}
return append(getStorePrefix(storeKey), key...)
}
102 changes: 102 additions & 0 deletions sei-db/db_engine/pebbledb/kv/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package pebbledb

import (
"github.com/cockroachdb/pebble"
"github.com/cockroachdb/pebble/bloom"
"github.com/pkg/errors"
"golang.org/x/exp/slices"
)

// Database represents database.
type Database struct {
storage *pebble.DB
writeOps *pebble.WriteOptions
}

// OpenDB opens an existing or create a new database.
func OpenDB(dbPath string) *Database {
cache := pebble.NewCache(1024 * 1024 * 512)
defer cache.Unref()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

defer cache.Unref() will run when OpenDB() returns, potentially releasing the cache while the DB is still using it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to keep the defer cache.Unref() - it's the correct pattern recommended by PebbleDB. The idea is to keep reference counting down to 0 when closing the DB.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i see!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i double checked this issue. the defer executes immediately when OpenDB returns, not when the DB is closed though

opts := &pebble.Options{
Cache: cache,
FormatMajorVersion: pebble.FormatNewest,
L0CompactionThreshold: 4,
L0StopWritesThreshold: 1000,
LBaseMaxBytes: 64 << 20, // 64 MB
Levels: make([]pebble.LevelOptions, 7),
MaxConcurrentCompactions: func() int { return 3 },
MemTableSize: 64 << 20,
MemTableStopWritesThreshold: 4,
DisableWAL: false,
}

for i := range opts.Levels {
l := &opts.Levels[i]
l.BlockSize = 32 << 10 // 32 KB
l.IndexBlockSize = 256 << 10 // 256 KB
l.FilterPolicy = bloom.FilterPolicy(10)
l.FilterType = pebble.TableFilter
if i > 1 {
l.Compression = pebble.ZstdCompression
}
if i > 0 {
l.TargetFileSize = opts.Levels[i-1].TargetFileSize * 2
}
l.EnsureDefaults()
}
opts.Levels[6].FilterPolicy = nil
opts.FlushSplitBytes = opts.Levels[0].TargetFileSize
opts = opts.EnsureDefaults()

db, err := pebble.Open(dbPath, opts)
if err != nil {
panic(err)
}

database := &Database{
storage: db,
writeOps: pebble.NoSync,
}

return database
}

// Has checks if key is available.
func (db *Database) Has(key []byte) (bool, error) {
val, err := db.Get(key)
if err != nil {
return false, errors.WithStack(err)
}
return val != nil, nil
}

// Get returns value by key.
// The returned value is a copy and safe to use after this call returns.
func (db *Database) Get(key []byte) ([]byte, error) {
Copy link
Contributor

@blindchaser blindchaser Jan 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from ai: Pebble Get() returns a value that is only valid until the returned closer is closed.
value is returned while closer.Close() is also called, which means the caller may observe invalid / corrupted data? We should copy value before closing the closer. we can do:

func (db *Database) Get(key []byte) ([]byte, error) {
    value, closer, err := db.storage.Get(key)
    if err != nil {
        if errors.Is(err, pebble.ErrNotFound) {
            return nil, nil
        }
        return nil, errors.WithStack(err)
    }
    defer closer.Close()

    out := append([]byte(nil), value...) // copy
    return out, nil
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's interesting, I think this is copied from v3 and we didn't really see this issue at all in v3. Will still fix it though

value, closer, err := db.storage.Get(key)
if err != nil {
if errors.Is(err, pebble.ErrNotFound) {
return nil, nil
}
return nil, errors.WithStack(err)
}
defer func() {
_ = closer.Close()
}()
// Must clone the value before closer.Close() is called,
// as PebbleDB's zero-copy semantics mean the underlying
// memory is only valid until the closer is closed.
return slices.Clone(value), nil
}

// Set override and persist key,value pair.
func (db *Database) Set(key []byte, value []byte) error {
return db.storage.Set(key, value, db.writeOps)
}

// Close closes the database.
func (db *Database) Close() error {
_ = db.storage.Flush()
err := db.storage.Close()
return errors.WithStack(err)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pebbledb
package mvcc

import (
"context"
Expand Down
Loading
Loading