diff --git a/core/store/store.go b/core/store/store.go index c153cb4214..8e91aa4434 100644 --- a/core/store/store.go +++ b/core/store/store.go @@ -30,6 +30,56 @@ type KVStore interface { ReverseIterator(start, end []byte) (Iterator, error) } +// Batch represents a group of writes. They may or may not be written atomically depending on the +// backend. Callers must call Close on the batch when done. +// +// As with KVStore, given keys and values should be considered read-only, and must not be modified after +// passing them to the batch. +type Batch interface { + // Set sets a key/value pair. + // CONTRACT: key, value readonly []byte + Set(key, value []byte) error + + // Delete deletes a key/value pair. + // CONTRACT: key readonly []byte + Delete(key []byte) error + + // Write writes the batch, possibly without flushing to disk. Only Close() can be called after, + // other methods will error. + Write() error + + // WriteSync writes the batch and flushes it to disk. Only Close() can be called after, other + // methods will error. + WriteSync() error + + // Close closes the batch. It is idempotent, but calls to other methods afterwards will error. + Close() error + + // GetByteSize that returns the current size of the batch in bytes. Depending on the implementation, + // this may return the size of the underlying LSM batch, including the size of additional metadata + // on top of the expected key and value total byte count. + GetByteSize() (int, error) +} + +// BatchCreator defines an interface for creating a new batch. +type BatchCreator interface { + // NewBatch creates a new batch for atomic updates. The caller must call Batch.Close. + NewBatch() Batch + + // NewBatchWithSize create a new batch for atomic updates, but with pre-allocated size. + // This will does the same thing as NewBatch if the batch implementation doesn't support pre-allocation. + NewBatchWithSize(int) Batch +} + +// KVStoreWithBatch is an extension of KVStore that allows for batch writes. +type KVStoreWithBatch interface { + KVStore + BatchCreator + + // Close closes the KVStoreWithBatch, releasing any resources held. + Close() error +} + // Iterator represents an iterator over a domain of keys. Callers must call // Close when done. No writes can happen to a domain while there exists an // iterator over it. Some backends may take out database locks to ensure this diff --git a/store/v2/batch.go b/store/v2/batch.go index 36178a6a63..b3fd718520 100644 --- a/store/v2/batch.go +++ b/store/v2/batch.go @@ -3,7 +3,15 @@ package store // Batch is a write-only database that commits changes to the underlying database // when Write is called. A batch cannot be used concurrently. type Batch interface { - Writer + // Set inserts the given value into the key-value data store. + // + // Note: are safe to modify and read after calling Set. + Set(storeKey, key, value []byte) error + + // Delete removes the key from the backing key-value data store. + // + // Note: is safe to modify and read after calling Delete. + Delete(storeKey, key []byte) error // Size retrieves the amount of data queued up for writing, this includes // the keys, values, and deleted keys. @@ -15,34 +23,3 @@ type Batch interface { // Reset resets the batch. Reset() error } - -// RawBatch represents a group of writes. They may or may not be written atomically depending on the -// backend. Callers must call Close on the batch when done. -// -// As with RawDB, given keys and values should be considered read-only, and must not be modified after -// passing them to the batch. -type RawBatch interface { - // Set sets a key/value pair. - // CONTRACT: key, value readonly []byte - Set(key, value []byte) error - - // Delete deletes a key/value pair. - // CONTRACT: key readonly []byte - Delete(key []byte) error - - // Write writes the batch, possibly without flushing to disk. Only Close() can be called after, - // other methods will error. - Write() error - - // WriteSync writes the batch and flushes it to disk. Only Close() can be called after, other - // methods will error. - WriteSync() error - - // Close closes the batch. It is idempotent, but calls to other methods afterwards will error. - Close() error - - // GetByteSize that returns the current size of the batch in bytes. Depending on the implementation, - // this may return the size of the underlying LSM batch, including the size of additional metadata - // on top of the expected key and value total byte count. - GetByteSize() (int, error) -} diff --git a/store/v2/commitment/README.md b/store/v2/commitment/README.md index 1e48cc057a..c9bcf111b4 100644 --- a/store/v2/commitment/README.md +++ b/store/v2/commitment/README.md @@ -8,10 +8,10 @@ into store/v2, specifically the `RootStore` type. A foremost design goal is that SC backends should be easily swappable, i.e. not necessarily IAVL. To this end, the scope of SC has been reduced, it must only: -* Provide a stateful root app hash for height h resulting from applying a batch +- Provide a stateful root app hash for height h resulting from applying a batch of key-value set/deletes to height h-1. -* Fulfill (though not necessarily provide) historical proofs for all heights < `h`. -* Provide an API for snapshot create/restore to fulfill state sync requests. +- Fulfill (though not necessarily provide) historical proofs for all heights < `h`. +- Provide an API for snapshot create/restore to fulfill state sync requests. Notably, SC is not required to provide key iteration or value retrieval for either queries or state machine execution, this now being the responsibility of state @@ -42,6 +42,6 @@ and `Restore` methods. Similar to the `storage` package, the `commitment` package is designed to be used in a broader store implementation, i.e. it fulfills the role of the SC backend. -Specifically, it provides a `CommitStore` type which accepts a `store.RawDB` and -a mapping from store key, a string meant to represent a single module, to a `Tree`, -which reflects the commitment structure. +Specifically, it provides a `CommitStore` type which accepts a `corestore.KVStore` +and a mapping from store key, a string meant to represent a single module, to a +`Tree`, which reflects the commitment structure. diff --git a/store/v2/commitment/iavl/tree.go b/store/v2/commitment/iavl/tree.go index f2f7392230..2f4e2cf57a 100644 --- a/store/v2/commitment/iavl/tree.go +++ b/store/v2/commitment/iavl/tree.go @@ -6,8 +6,8 @@ import ( "github.com/cosmos/iavl" ics23 "github.com/cosmos/ics23/go" + corestore "cosmossdk.io/core/store" "cosmossdk.io/log" - "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/commitment" dbm "cosmossdk.io/store/v2/db" ) @@ -20,7 +20,7 @@ type IavlTree struct { } // NewIavlTree creates a new IavlTree instance. -func NewIavlTree(db store.RawDB, logger log.Logger, cfg *Config) *IavlTree { +func NewIavlTree(db corestore.KVStoreWithBatch, logger log.Logger, cfg *Config) *IavlTree { tree := iavl.NewMutableTree(dbm.NewWrapper(db), cfg.CacheSize, cfg.SkipFastStorageUpgrade, logger) return &IavlTree{ tree: tree, diff --git a/store/v2/commitment/iavl/tree_test.go b/store/v2/commitment/iavl/tree_test.go index 526cb36b22..6c69d39be5 100644 --- a/store/v2/commitment/iavl/tree_test.go +++ b/store/v2/commitment/iavl/tree_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + corestore "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/commitment" @@ -14,7 +15,7 @@ import ( func TestCommitterSuite(t *testing.T) { s := &commitment.CommitStoreTestSuite{ - NewStore: func(db store.RawDB, storeKeys []string, pruneOpts *store.PruneOptions, logger log.Logger) (*commitment.CommitStore, error) { + NewStore: func(db corestore.KVStoreWithBatch, storeKeys []string, pruneOpts *store.PruneOptions, logger log.Logger) (*commitment.CommitStore, error) { multiTrees := make(map[string]commitment.Tree) cfg := DefaultConfig() for _, storeKey := range storeKeys { diff --git a/store/v2/commitment/store.go b/store/v2/commitment/store.go index 7a15ff48a2..42f9d3f611 100644 --- a/store/v2/commitment/store.go +++ b/store/v2/commitment/store.go @@ -36,7 +36,7 @@ var ( // and trees. type CommitStore struct { logger log.Logger - db store.RawDB + db corestore.KVStoreWithBatch multiTrees map[string]Tree // pruneOptions is the pruning configuration. @@ -44,7 +44,7 @@ type CommitStore struct { } // NewCommitStore creates a new CommitStore instance. -func NewCommitStore(trees map[string]Tree, db store.RawDB, pruneOpts *store.PruneOptions, logger log.Logger) (*CommitStore, error) { +func NewCommitStore(trees map[string]Tree, db corestore.KVStoreWithBatch, pruneOpts *store.PruneOptions, logger log.Logger) (*CommitStore, error) { if pruneOpts == nil { pruneOpts = store.DefaultPruneOptions() } diff --git a/store/v2/commitment/store_test_suite.go b/store/v2/commitment/store_test_suite.go index aad3e923ec..741337be47 100644 --- a/store/v2/commitment/store_test_suite.go +++ b/store/v2/commitment/store_test_suite.go @@ -25,7 +25,7 @@ const ( type CommitStoreTestSuite struct { suite.Suite - NewStore func(db store.RawDB, storeKeys []string, pruneOpts *store.PruneOptions, logger log.Logger) (*CommitStore, error) + NewStore func(db corestore.KVStoreWithBatch, storeKeys []string, pruneOpts *store.PruneOptions, logger log.Logger) (*CommitStore, error) } func (s *CommitStoreTestSuite) TestStore_Snapshotter() { diff --git a/store/v2/database.go b/store/v2/database.go index 0ff83ef340..52e7dd848e 100644 --- a/store/v2/database.go +++ b/store/v2/database.go @@ -7,42 +7,6 @@ import ( "cosmossdk.io/store/v2/proof" ) -// Reader wraps the Has and Get method of a backing data store. -type Reader interface { - // Has retrieves if a key is present in the key-value data store. - // - // Note: is safe to modify and read after calling Has. - Has(storeKey, key []byte) (bool, error) - - // Get retrieves the given key if it's present in the key-value data store. - // - // Note: is safe to modify and read after calling Get. - // The returned byte slice is safe to read, but cannot be modified. - Get(storeKey, key []byte) ([]byte, error) -} - -// Writer wraps the Set method of a backing data store. -type Writer interface { - // Set inserts the given value into the key-value data store. - // - // Note: are safe to modify and read after calling Set. - Set(storeKey, key, value []byte) error - - // Delete removes the key from the backing key-value data store. - // - // Note: is safe to modify and read after calling Delete. - Delete(storeKey, key []byte) error -} - -// Database contains all the methods required to allow handling different -// key-value data stores backing the database. -type Database interface { - Reader - Writer - corestore.IteratorCreator - io.Closer -} - // VersionedDatabase defines an API for a versioned database that allows reads, // writes, iteration and commitment over a series of versions. type VersionedDatabase interface { @@ -107,44 +71,3 @@ type Committer interface { // only be called once and any call after may panic. io.Closer } - -// RawDB is the main interface for all key-value database backends. DBs are concurrency-safe. -// Callers must call Close on the database when done. -// -// Keys cannot be nil or empty, while values cannot be nil. Keys and values should be considered -// read-only, both when returned and when given, and must be copied before they are modified. -type RawDB interface { - // Get fetches the value of the given key, or nil if it does not exist. - // CONTRACT: key, value readonly []byte - Get([]byte) ([]byte, error) - - // Has checks if a key exists. - // CONTRACT: key, value readonly []byte - Has(key []byte) (bool, error) - - // Iterator returns an iterator over a domain of keys, in ascending order. The caller must call - // Close when done. End is exclusive, and start must be less than end. A nil start iterates - // from the first key, and a nil end iterates to the last key (inclusive). Empty keys are not - // valid. - // CONTRACT: No writes may happen within a domain while an iterator exists over it. - // CONTRACT: start, end readonly []byte - Iterator(start, end []byte) (corestore.Iterator, error) - - // ReverseIterator returns an iterator over a domain of keys, in descending order. The caller - // must call Close when done. End is exclusive, and start must be less than end. A nil end - // iterates from the last key (inclusive), and a nil start iterates to the first key (inclusive). - // Empty keys are not valid. - // CONTRACT: No writes may happen within a domain while an iterator exists over it. - // CONTRACT: start, end readonly []byte - ReverseIterator(start, end []byte) (corestore.Iterator, error) - - // Close closes the database connection. - Close() error - - // NewBatch creates a batch for atomic updates. The caller must call Batch.Close. - NewBatch() RawBatch - - // NewBatchWithSize create a new batch for atomic updates, but with pre-allocated size. - // This will does the same thing as NewBatch if the batch implementation doesn't support pre-allocation. - NewBatchWithSize(int) RawBatch -} diff --git a/store/v2/db/db.go b/store/v2/db/db.go index e24c6e66c7..bb2dd3ca63 100644 --- a/store/v2/db/db.go +++ b/store/v2/db/db.go @@ -3,21 +3,22 @@ package db import ( "fmt" + corestore "cosmossdk.io/core/store" "cosmossdk.io/store/v2" ) -type RawDBType string +type DBType string const ( - DBTypeGoLevelDB RawDBType = "goleveldb" - DBTypeRocksDB RawDBType = "rocksdb" - DBTypePebbleDB RawDBType = "pebbledb" - DBTypePrefixDB RawDBType = "prefixdb" + DBTypeGoLevelDB DBType = "goleveldb" + DBTypeRocksDB DBType = "rocksdb" + DBTypePebbleDB DBType = "pebbledb" + DBTypePrefixDB DBType = "prefixdb" DBFileSuffix string = ".db" ) -func NewRawDB(dbType RawDBType, name, dataDir string, opts store.DBOptions) (store.RawDB, error) { +func NewDB(dbType DBType, name, dataDir string, opts store.DBOptions) (corestore.KVStoreWithBatch, error) { switch dbType { case DBTypeGoLevelDB: return NewGoLevelDB(name, dataDir, opts) diff --git a/store/v2/db/db_test.go b/store/v2/db/db_test.go index cad62a4264..913fdb3243 100644 --- a/store/v2/db/db_test.go +++ b/store/v2/db/db_test.go @@ -7,13 +7,13 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "cosmossdk.io/store/v2" + corestore "cosmossdk.io/core/store" ) type DBTestSuite struct { suite.Suite - db store.RawDB + db corestore.KVStoreWithBatch } func (s *DBTestSuite) TearDownSuite() { @@ -21,7 +21,7 @@ func (s *DBTestSuite) TearDownSuite() { } func (s *DBTestSuite) TestDBOperations() { - // Set + // Batch Set b := s.db.NewBatch() s.Require().NoError(b.Set([]byte("key"), []byte("value"))) s.Require().NoError(b.Set([]byte("key1"), []byte("value1"))) @@ -41,7 +41,7 @@ func (s *DBTestSuite) TestDBOperations() { s.Require().NoError(err) s.Require().False(has) - // Delete + // Batch Delete b = s.db.NewBatch() s.Require().NoError(b.Delete([]byte("key1"))) s.Require().NoError(b.Write()) @@ -50,6 +50,22 @@ func (s *DBTestSuite) TestDBOperations() { has, err = s.db.Has([]byte("key1")) s.Require().NoError(err) s.Require().False(has) + + // Set & Delete + s.Require().NoError(s.db.Set([]byte("key3"), []byte("value3"))) + has, err = s.db.Has([]byte("key3")) + s.Require().NoError(err) + s.Require().True(has) + value, err = s.db.Get([]byte("key3")) + s.Require().NoError(err) + s.Require().Equal([]byte("value3"), value) + s.Require().NoError(s.db.Delete([]byte("key3"))) + has, err = s.db.Has([]byte("key3")) + s.Require().NoError(err) + s.Require().False(has) + value, err = s.db.Get([]byte("key3")) + s.Require().NoError(err) + s.Require().Nil(value) } func (s *DBTestSuite) TestIterator() { diff --git a/store/v2/db/goleveldb.go b/store/v2/db/goleveldb.go index bfdcd218f8..59e2e08ad8 100644 --- a/store/v2/db/goleveldb.go +++ b/store/v2/db/goleveldb.go @@ -19,9 +19,9 @@ import ( storeerrors "cosmossdk.io/store/v2/errors" ) -var _ store.RawDB = (*GoLevelDB)(nil) +var _ corestore.KVStoreWithBatch = (*GoLevelDB)(nil) -// GoLevelDB implements RawDB using github.com/syndtr/goleveldb/leveldb. +// GoLevelDB implements corestore.KVStore using github.com/syndtr/goleveldb/leveldb. // It is used for only store v2 migration, since some clients use goleveldb as // the IAVL v0/v1 backend. type GoLevelDB struct { @@ -52,7 +52,7 @@ func NewGoLevelDBWithOpts(name, dir string, o *opt.Options) (*GoLevelDB, error) return &GoLevelDB{db: db}, nil } -// Get implements RawDB. +// Get implements corestore.KVStore. func (db *GoLevelDB) Get(key []byte) ([]byte, error) { if len(key) == 0 { return nil, storeerrors.ErrKeyEmpty @@ -67,12 +67,12 @@ func (db *GoLevelDB) Get(key []byte) ([]byte, error) { return res, nil } -// Has implements RawDB. +// Has implements corestore.KVStore. func (db *GoLevelDB) Has(key []byte) (bool, error) { return db.db.Has(key, nil) } -// Set implements RawDB. +// Set implements corestore.KVStore. func (db *GoLevelDB) Set(key, value []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -83,7 +83,7 @@ func (db *GoLevelDB) Set(key, value []byte) error { return db.db.Put(key, value, nil) } -// SetSync implements RawDB. +// SetSync implements corestore.KVStore. func (db *GoLevelDB) SetSync(key, value []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -94,7 +94,7 @@ func (db *GoLevelDB) SetSync(key, value []byte) error { return db.db.Put(key, value, &opt.WriteOptions{Sync: true}) } -// Delete implements RawDB. +// Delete implements corestore.KVStore. func (db *GoLevelDB) Delete(key []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -102,7 +102,7 @@ func (db *GoLevelDB) Delete(key []byte) error { return db.db.Delete(key, nil) } -// DeleteSync implements RawDB. +// DeleteSync implements corestore.KVStore. func (db *GoLevelDB) DeleteSync(key []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -114,12 +114,12 @@ func (db *GoLevelDB) RawDB() *leveldb.DB { return db.db } -// Close implements RawDB. +// Close implements corestore.KVStore. func (db *GoLevelDB) Close() error { return db.db.Close() } -// Print implements RawDB. +// Print implements corestore.KVStore. func (db *GoLevelDB) Print() error { str, err := db.db.GetProperty("leveldb.stats") if err != nil { @@ -136,7 +136,7 @@ func (db *GoLevelDB) Print() error { return nil } -// Stats implements RawDB. +// Stats implements corestore.KVStore. func (db *GoLevelDB) Stats() map[string]string { keys := []string{ "leveldb.num-files-at-level{n}", @@ -162,17 +162,17 @@ func (db *GoLevelDB) ForceCompact(start, limit []byte) error { return db.db.CompactRange(util.Range{Start: start, Limit: limit}) } -// NewBatch implements RawDB. -func (db *GoLevelDB) NewBatch() store.RawBatch { +// NewBatch implements corestore.BatchCreator. +func (db *GoLevelDB) NewBatch() corestore.Batch { return newGoLevelDBBatch(db) } -// NewBatchWithSize implements RawDB. -func (db *GoLevelDB) NewBatchWithSize(size int) store.RawBatch { +// NewBatchWithSize implements corestore.BatchCreator. +func (db *GoLevelDB) NewBatchWithSize(size int) corestore.Batch { return newGoLevelDBBatchWithSize(db, size) } -// Iterator implements RawDB. +// Iterator implements corestore.KVStore. func (db *GoLevelDB) Iterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, storeerrors.ErrKeyEmpty @@ -181,7 +181,7 @@ func (db *GoLevelDB) Iterator(start, end []byte) (corestore.Iterator, error) { return newGoLevelDBIterator(itr, start, end, false), nil } -// ReverseIterator implements RawDB. +// ReverseIterator implements corestore.KVStore. func (db *GoLevelDB) ReverseIterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, storeerrors.ErrKeyEmpty @@ -323,7 +323,7 @@ type goLevelDBBatch struct { batch *leveldb.Batch } -var _ store.RawBatch = (*goLevelDBBatch)(nil) +var _ corestore.Batch = (*goLevelDBBatch)(nil) func newGoLevelDBBatch(db *GoLevelDB) *goLevelDBBatch { return &goLevelDBBatch{ @@ -339,7 +339,7 @@ func newGoLevelDBBatchWithSize(db *GoLevelDB, size int) *goLevelDBBatch { } } -// Set implements RawBatch. +// Set implements corestore.Batch. func (b *goLevelDBBatch) Set(key, value []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -354,7 +354,7 @@ func (b *goLevelDBBatch) Set(key, value []byte) error { return nil } -// Delete implements RawBatch. +// Delete implements corestore.Batch. func (b *goLevelDBBatch) Delete(key []byte) error { if len(key) == 0 { return storeerrors.ErrKeyEmpty @@ -366,12 +366,12 @@ func (b *goLevelDBBatch) Delete(key []byte) error { return nil } -// Write implements RawBatch. +// Write implements corestore.Batch. func (b *goLevelDBBatch) Write() error { return b.write(false) } -// WriteSync implements RawBatch. +// WriteSync implements corestore.Batch. func (b *goLevelDBBatch) WriteSync() error { return b.write(true) } @@ -387,7 +387,7 @@ func (b *goLevelDBBatch) write(sync bool) error { return b.Close() } -// Close implements RawBatch. +// Close implements corestore.Batch. func (b *goLevelDBBatch) Close() error { if b.batch != nil { b.batch.Reset() @@ -396,7 +396,7 @@ func (b *goLevelDBBatch) Close() error { return nil } -// GetByteSize implements RawBatch +// GetByteSize implements corestore.Batch func (b *goLevelDBBatch) GetByteSize() (int, error) { if b.batch == nil { return 0, storeerrors.ErrBatchClosed diff --git a/store/v2/db/memdb.go b/store/v2/db/memdb.go index 153cc2727a..c6250db665 100644 --- a/store/v2/db/memdb.go +++ b/store/v2/db/memdb.go @@ -9,7 +9,6 @@ import ( "github.com/google/btree" corestore "cosmossdk.io/core/store" - "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/errors" ) @@ -41,6 +40,8 @@ func newPair(key, value []byte) item { return item{key: key, value: value} } +var _ corestore.KVStoreWithBatch = (*MemDB)(nil) + // MemDB is an in-memory database backend using a B-tree for storage. // // For performance reasons, all given and returned keys and values are pointers to the in-memory @@ -52,8 +53,6 @@ type MemDB struct { btree *btree.BTree } -var _ store.RawDB = (*MemDB)(nil) - // NewMemDB creates a new in-memory database. func NewMemDB() *MemDB { database := &MemDB{ @@ -168,13 +167,13 @@ func (db *MemDB) Stats() map[string]string { } // NewBatch implements DB. -func (db *MemDB) NewBatch() store.RawBatch { +func (db *MemDB) NewBatch() corestore.Batch { return newMemDBBatch(db) } // NewBatchWithSize implements DB. // It does the same thing as NewBatch because we can't pre-allocate memDBBatch -func (db *MemDB) NewBatchWithSize(size int) store.RawBatch { +func (db *MemDB) NewBatchWithSize(size int) corestore.Batch { return newMemDBBatch(db) } @@ -382,7 +381,7 @@ type memDBBatch struct { size int } -var _ store.RawBatch = (*memDBBatch)(nil) +var _ corestore.Batch = (*memDBBatch)(nil) // newMemDBBatch creates a new memDBBatch func newMemDBBatch(db *MemDB) *memDBBatch { diff --git a/store/v2/db/pebbledb.go b/store/v2/db/pebbledb.go index fd661f9ff5..382ee70799 100644 --- a/store/v2/db/pebbledb.go +++ b/store/v2/db/pebbledb.go @@ -15,9 +15,9 @@ import ( storeerrors "cosmossdk.io/store/v2/errors" ) -var _ store.RawDB = (*PebbleDB)(nil) +var _ corestore.KVStoreWithBatch = (*PebbleDB)(nil) -// PebbleDB implements RawDB using PebbleDB as the underlying storage engine. +// PebbleDB implements `corestore.KVStoreWithBatch` using PebbleDB as the underlying storage engine. // It is used for only store v2 migration, since some clients use PebbleDB as // the IAVL v0/v1 backend. type PebbleDB struct { @@ -87,6 +87,25 @@ func (db *PebbleDB) Has(key []byte) (bool, error) { return bz != nil, nil } +func (db *PebbleDB) Set(key, value []byte) error { + if len(key) == 0 { + return storeerrors.ErrKeyEmpty + } + if value == nil { + return storeerrors.ErrValueNil + } + + return db.storage.Set(key, value, &pebble.WriteOptions{Sync: false}) +} + +func (db *PebbleDB) Delete(key []byte) error { + if len(key) == 0 { + return storeerrors.ErrKeyEmpty + } + + return db.storage.Delete(key, &pebble.WriteOptions{Sync: false}) +} + func (db *PebbleDB) Iterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, storeerrors.ErrKeyEmpty @@ -113,14 +132,14 @@ func (db *PebbleDB) ReverseIterator(start, end []byte) (corestore.Iterator, erro return newPebbleDBIterator(itr, start, end, true), nil } -func (db *PebbleDB) NewBatch() store.RawBatch { +func (db *PebbleDB) NewBatch() corestore.Batch { return &pebbleDBBatch{ db: db, batch: db.storage.NewBatch(), } } -func (db *PebbleDB) NewBatchWithSize(size int) store.RawBatch { +func (db *PebbleDB) NewBatchWithSize(size int) corestore.Batch { return &pebbleDBBatch{ db: db, batch: db.storage.NewBatchWithSize(size), @@ -225,7 +244,7 @@ func (itr *pebbleDBIterator) assertIsValid() { } } -var _ store.RawBatch = (*pebbleDBBatch)(nil) +var _ corestore.Batch = (*pebbleDBBatch)(nil) type pebbleDBBatch struct { db *PebbleDB diff --git a/store/v2/db/prefixdb.go b/store/v2/db/prefixdb.go index 7ead2aa699..643f2e95f7 100644 --- a/store/v2/db/prefixdb.go +++ b/store/v2/db/prefixdb.go @@ -6,7 +6,6 @@ import ( "sync" corestore "cosmossdk.io/core/store" - "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/errors" ) @@ -14,20 +13,20 @@ import ( type PrefixDB struct { mtx sync.Mutex prefix []byte - db store.RawDB + db corestore.KVStoreWithBatch } -var _ store.RawDB = (*PrefixDB)(nil) +var _ corestore.KVStoreWithBatch = (*PrefixDB)(nil) -// NewPrefixDB lets you namespace multiple RawDBs within a single RawDB. -func NewPrefixDB(db store.RawDB, prefix []byte) *PrefixDB { +// NewPrefixDB lets you namespace multiple corestore.KVStores within a single corestore.KVStore. +func NewPrefixDB(db corestore.KVStoreWithBatch, prefix []byte) *PrefixDB { return &PrefixDB{ prefix: prefix, db: db, } } -// Get implements RawDB. +// Get implements corestore.KVStore. func (pdb *PrefixDB) Get(key []byte) ([]byte, error) { if len(key) == 0 { return nil, errors.ErrKeyEmpty @@ -38,10 +37,11 @@ func (pdb *PrefixDB) Get(key []byte) ([]byte, error) { if err != nil { return nil, err } + return value, nil } -// Has implements RawDB. +// Has implements corestore.KVStore. func (pdb *PrefixDB) Has(key []byte) (bool, error) { if len(key) == 0 { return false, errors.ErrKeyEmpty @@ -55,7 +55,25 @@ func (pdb *PrefixDB) Has(key []byte) (bool, error) { return ok, nil } -// Iterator implements RawDB. +// Set implements corestore.KVStore. +func (pdb *PrefixDB) Set(key, value []byte) error { + if len(key) == 0 { + return errors.ErrKeyEmpty + } + + return pdb.db.Set(pdb.prefixed(key), value) +} + +// Delete implements corestore.KVStore. +func (pdb *PrefixDB) Delete(key []byte) error { + if len(key) == 0 { + return errors.ErrKeyEmpty + } + + return pdb.db.Delete(pdb.prefixed(key)) +} + +// Iterator implements corestore.KVStore. func (pdb *PrefixDB) Iterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, errors.ErrKeyEmpty @@ -76,7 +94,7 @@ func (pdb *PrefixDB) Iterator(start, end []byte) (corestore.Iterator, error) { return newPrefixIterator(pdb.prefix, start, end, itr) } -// ReverseIterator implements RawDB. +// ReverseIterator implements corestore.KVStore. func (pdb *PrefixDB) ReverseIterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, errors.ErrKeyEmpty @@ -97,17 +115,17 @@ func (pdb *PrefixDB) ReverseIterator(start, end []byte) (corestore.Iterator, err return newPrefixIterator(pdb.prefix, start, end, ritr) } -// NewBatch implements RawDB. -func (pdb *PrefixDB) NewBatch() store.RawBatch { +// NewBatch implements corestore.BatchCreator. +func (pdb *PrefixDB) NewBatch() corestore.Batch { return newPrefixBatch(pdb.prefix, pdb.db.NewBatch()) } -// NewBatchWithSize implements RawDB. -func (pdb *PrefixDB) NewBatchWithSize(size int) store.RawBatch { +// NewBatchWithSize implements corestore.BatchCreator. +func (pdb *PrefixDB) NewBatchWithSize(size int) corestore.Batch { return newPrefixBatch(pdb.prefix, pdb.db.NewBatchWithSize(size)) } -// Close implements RawDB. +// Close implements corestore.KVStore. func (pdb *PrefixDB) Close() error { pdb.mtx.Lock() defer pdb.mtx.Unlock() @@ -115,7 +133,7 @@ func (pdb *PrefixDB) Close() error { return pdb.db.Close() } -// Print implements RawDB. +// Print implements corestore.KVStore. func (pdb *PrefixDB) Print() error { fmt.Printf("prefix: %X\n", pdb.prefix) @@ -138,7 +156,7 @@ func (pdb *PrefixDB) prefixed(key []byte) []byte { // IteratePrefix is a convenience function for iterating over a key domain // restricted by prefix. -func IteratePrefix(db store.RawDB, prefix []byte) (corestore.Iterator, error) { +func IteratePrefix(db corestore.KVStore, prefix []byte) (corestore.Iterator, error) { var start, end []byte if len(prefix) == 0 { start = nil @@ -263,19 +281,19 @@ func (itr *prefixDBIterator) assertIsValid() { type prefixDBBatch struct { prefix []byte - source store.RawBatch + source corestore.Batch } -var _ store.RawBatch = (*prefixDBBatch)(nil) +var _ corestore.Batch = (*prefixDBBatch)(nil) -func newPrefixBatch(prefix []byte, source store.RawBatch) prefixDBBatch { +func newPrefixBatch(prefix []byte, source corestore.Batch) prefixDBBatch { return prefixDBBatch{ prefix: prefix, source: source, } } -// Set implements RawBatch. +// Set implements corestore.Batch. func (pb prefixDBBatch) Set(key, value []byte) error { if len(key) == 0 { return errors.ErrKeyEmpty @@ -287,7 +305,7 @@ func (pb prefixDBBatch) Set(key, value []byte) error { return pb.source.Set(pkey, value) } -// Delete implements RawBatch. +// Delete implements corestore.Batch. func (pb prefixDBBatch) Delete(key []byte) error { if len(key) == 0 { return errors.ErrKeyEmpty @@ -296,22 +314,22 @@ func (pb prefixDBBatch) Delete(key []byte) error { return pb.source.Delete(pkey) } -// Write implements RawBatch. +// Write implements corestore.Batch. func (pb prefixDBBatch) Write() error { return pb.source.Write() } -// WriteSync implements RawBatch. +// WriteSync implements corestore.Batch. func (pb prefixDBBatch) WriteSync() error { return pb.source.WriteSync() } -// Close implements RawBatch. +// Close implements corestore.Batch. func (pb prefixDBBatch) Close() error { return pb.source.Close() } -// GetByteSize implements RawBatch +// GetByteSize implements corestore.Batch func (pb prefixDBBatch) GetByteSize() (int, error) { if pb.source == nil { return 0, errors.ErrBatchClosed diff --git a/store/v2/db/rocksdb.go b/store/v2/db/rocksdb.go index 56054ab0ce..5378de85e7 100644 --- a/store/v2/db/rocksdb.go +++ b/store/v2/db/rocksdb.go @@ -13,17 +13,16 @@ import ( "github.com/linxGnu/grocksdb" corestore "cosmossdk.io/core/store" - "cosmossdk.io/store/v2" storeerrors "cosmossdk.io/store/v2/errors" ) var ( - _ store.RawDB = (*RocksDB)(nil) + _ corestore.KVStoreWithBatch = (*RocksDB)(nil) defaultReadOpts = grocksdb.NewDefaultReadOptions() ) -// RocksDB implements RawDB using RocksDB as the underlying storage engine. +// RocksDB implements `corestore.KVStoreWithBatch` using RocksDB as the underlying storage engine. // It is used for only store v2 migration, since some clients use RocksDB as // the IAVL v0/v1 backend. type RocksDB struct { @@ -92,6 +91,25 @@ func (db *RocksDB) Has(key []byte) (bool, error) { return bz != nil, nil } +func (db *RocksDB) Set(key, value []byte) error { + if len(key) == 0 { + return storeerrors.ErrKeyEmpty + } + if value == nil { + return storeerrors.ErrValueNil + } + + return db.storage.Put(grocksdb.NewDefaultWriteOptions(), key, value) +} + +func (db *RocksDB) Delete(key []byte) error { + if len(key) == 0 { + return storeerrors.ErrKeyEmpty + } + + return db.storage.Delete(grocksdb.NewDefaultWriteOptions(), key) +} + func (db *RocksDB) Iterator(start, end []byte) (corestore.Iterator, error) { if (start != nil && len(start) == 0) || (end != nil && len(end) == 0) { return nil, storeerrors.ErrKeyEmpty @@ -110,14 +128,14 @@ func (db *RocksDB) ReverseIterator(start, end []byte) (corestore.Iterator, error return newRocksDBIterator(itr, start, end, true), nil } -func (db *RocksDB) NewBatch() store.RawBatch { +func (db *RocksDB) NewBatch() corestore.Batch { return &rocksDBBatch{ db: db, batch: grocksdb.NewWriteBatch(), } } -func (db *RocksDB) NewBatchWithSize(_ int) store.RawBatch { +func (db *RocksDB) NewBatchWithSize(_ int) corestore.Batch { return db.NewBatch() } diff --git a/store/v2/db/rocksdb_noflag.go b/store/v2/db/rocksdb_noflag.go index 8ad44e66f9..6e05c9a10a 100644 --- a/store/v2/db/rocksdb_noflag.go +++ b/store/v2/db/rocksdb_noflag.go @@ -8,9 +8,9 @@ import ( "cosmossdk.io/store/v2" ) -var _ store.RawDB = (*RocksDB)(nil) +var _ corestore.KVStoreWithBatch = (*RocksDB)(nil) -// RocksDB implements RawDB using RocksDB as the underlying storage engine. +// RocksDB implements `corestore.KVStoreWithBatch` using RocksDB as the underlying storage engine. // It is used for only store v2 migration, since some clients use RocksDB as // the IAVL v0/v1 backend. type RocksDB struct{} @@ -35,6 +35,14 @@ func (db *RocksDB) Has(key []byte) (bool, error) { panic("rocksdb must be built with -tags rocksdb") } +func (db *RocksDB) Set(key, value []byte) error { + panic("rocksdb must be built with -tags rocksdb") +} + +func (db *RocksDB) Delete(key []byte) error { + panic("rocksdb must be built with -tags rocksdb") +} + func (db *RocksDB) Iterator(start, end []byte) (corestore.Iterator, error) { panic("rocksdb must be built with -tags rocksdb") } @@ -43,10 +51,10 @@ func (db *RocksDB) ReverseIterator(start, end []byte) (corestore.Iterator, error panic("rocksdb must be built with -tags rocksdb") } -func (db *RocksDB) NewBatch() store.RawBatch { +func (db *RocksDB) NewBatch() corestore.Batch { panic("rocksdb must be built with -tags rocksdb") } -func (db *RocksDB) NewBatchWithSize(_ int) store.RawBatch { - return db.NewBatch() +func (db *RocksDB) NewBatchWithSize(_ int) corestore.Batch { + panic("rocksdb must be built with -tags rocksdb") } diff --git a/store/v2/db/wrapper.go b/store/v2/db/wrapper.go index da4b61a2de..72d4ddca30 100644 --- a/store/v2/db/wrapper.go +++ b/store/v2/db/wrapper.go @@ -3,37 +3,37 @@ package db import ( idb "github.com/cosmos/iavl/db" - "cosmossdk.io/store/v2" + corestore "cosmossdk.io/core/store" ) -// Wrapper wraps a RawDB to implement iavl.DB which is used by iavl.Tree. +// Wrapper wraps a `corestore.KVStoreWithBatch` to implement iavl.DB which is used by iavl.Tree. type Wrapper struct { - store.RawDB + corestore.KVStoreWithBatch } var _ idb.DB = (*Wrapper)(nil) // NewWrapper returns a new Wrapper. -func NewWrapper(db store.RawDB) *Wrapper { - return &Wrapper{RawDB: db} +func NewWrapper(db corestore.KVStoreWithBatch) *Wrapper { + return &Wrapper{KVStoreWithBatch: db} } // Iterator implements iavl.DB. func (db *Wrapper) Iterator(start, end []byte) (idb.Iterator, error) { - return db.RawDB.Iterator(start, end) + return db.KVStoreWithBatch.Iterator(start, end) } // ReverseIterator implements iavl.DB. func (db *Wrapper) ReverseIterator(start, end []byte) (idb.Iterator, error) { - return db.RawDB.ReverseIterator(start, end) + return db.KVStoreWithBatch.ReverseIterator(start, end) } // NewBatch implements iavl.DB. func (db *Wrapper) NewBatch() idb.Batch { - return db.RawDB.NewBatch() + return db.KVStoreWithBatch.NewBatch() } // NewBatchWithSize implements iavl.DB. func (db *Wrapper) NewBatchWithSize(size int) idb.Batch { - return db.RawDB.NewBatchWithSize(size) + return db.KVStoreWithBatch.NewBatchWithSize(size) } diff --git a/store/v2/migration/manager.go b/store/v2/migration/manager.go index bae585b1e5..73976e2471 100644 --- a/store/v2/migration/manager.go +++ b/store/v2/migration/manager.go @@ -12,7 +12,6 @@ import ( corestore "cosmossdk.io/core/store" "cosmossdk.io/log" - "cosmossdk.io/store/v2" "cosmossdk.io/store/v2/commitment" "cosmossdk.io/store/v2/internal/encoding" "cosmossdk.io/store/v2/snapshots" @@ -43,7 +42,7 @@ type Manager struct { stateStorage *storage.StorageStore stateCommitment *commitment.CommitStore - db store.RawDB + db corestore.KVStoreWithBatch mtx sync.Mutex // mutex for migratedVersion migratedVersion uint64 @@ -54,7 +53,7 @@ type Manager struct { // NewManager returns a new Manager. // // NOTE: `sc` can be `nil` if don't want to migrate the commitment. -func NewManager(db store.RawDB, sm *snapshots.Manager, ss *storage.StorageStore, sc *commitment.CommitStore, logger log.Logger) *Manager { +func NewManager(db corestore.KVStoreWithBatch, sm *snapshots.Manager, ss *storage.StorageStore, sc *commitment.CommitStore, logger log.Logger) *Manager { return &Manager{ logger: logger, snapshotsManager: sm, diff --git a/store/v2/snapshots/store.go b/store/v2/snapshots/store.go index 5c82a095e6..50c8e1dbd6 100644 --- a/store/v2/snapshots/store.go +++ b/store/v2/snapshots/store.go @@ -16,8 +16,8 @@ import ( "github.com/cosmos/gogoproto/proto" + corestore "cosmossdk.io/core/store" "cosmossdk.io/errors" - "cosmossdk.io/store/v2" storeerrors "cosmossdk.io/store/v2/errors" "cosmossdk.io/store/v2/snapshots/types" ) @@ -420,7 +420,7 @@ func legacyV1EncodeKey(height uint64, format uint32) []byte { return k } -func (s *Store) MigrateFromV1(db store.RawDB) error { +func (s *Store) MigrateFromV1(db corestore.KVStore) error { itr, err := db.Iterator(legacyV1EncodeKey(0, 0), legacyV1EncodeKey(math.MaxUint64, math.MaxUint32)) if err != nil { return err