Skip to content

Commit

Permalink
feat: ADR-040: Implement RocksDB backend (#9851)
Browse files Browse the repository at this point in the history
## Description

Partially resolves: vulcanize#14

Implements a [RocksDB](https://github.com/facebook/rocksdb)-based backend for the DB interface introduced by #9573 and specified by [ADR-040](https://github.com/cosmos/cosmos-sdk/blob/eb7d939f86c6cd7b4218492364cdda3f649f06b5/docs/architecture/adr-040-storage-and-smt-state-commitments.md). 
* Historical versioning is implemented with [Checkpoints](https://github.com/facebook/rocksdb/wiki/Checkpoints). 
* Uses `OptimisticTransactionDB` to allow concurrent transactions with write conflict detection. This depends on some additional CGo bindings - see tecbot/gorocksdb#216, facebook/rocksdb#8526. We'll need to replace the `gorocksdb` module until these are upstream.
---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [x] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - n/a
- [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [x] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [x] updated the relevant documentation or specification
- [x] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
  • Loading branch information
roysc authored Oct 5, 2021
1 parent 9094794 commit 33c8314
Show file tree
Hide file tree
Showing 15 changed files with 1,063 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#9573](https://github.com/cosmos/cosmos-sdk/pull/9573) ADR 040 implementation: New DB interface
* [\#9952](https://github.com/cosmos/cosmos-sdk/pull/9952) ADR 040: Implement in-memory DB backend
* [\#9848](https://github.com/cosmos/cosmos-sdk/pull/9848) ADR-040: Implement BadgerDB backend
* [\#9851](https://github.com/cosmos/cosmos-sdk/pull/9851) ADR-040: Implement RocksDB backend


### Client Breaking Changes
Expand Down
3 changes: 3 additions & 0 deletions db/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,6 @@ tx2.Set(key, []byte("b"))
tx1.Commit() // ok
tx2.Commit() // ok
```
### RocksDB

A [RocksDB](https://github.com/facebook/rocksdb)-based backend. Internally this uses [`OptimisticTransactionDB`](https://github.com/facebook/rocksdb/wiki/Transactions#optimistictransactiondb) to allow concurrent transactions with write conflict detection. Historical versioning is internally implemented with [Checkpoints](https://github.com/facebook/rocksdb/wiki/Checkpoints).
48 changes: 31 additions & 17 deletions db/badgerdb/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package badgerdb
import (
"bytes"
"encoding/csv"
"errors"
"math"
"os"
"path/filepath"
Expand All @@ -11,6 +12,7 @@ import (
"sync/atomic"

dbm "github.com/cosmos/cosmos-sdk/db"
dbutil "github.com/cosmos/cosmos-sdk/db/internal"

"github.com/dgraph-io/badger/v3"
)
Expand Down Expand Up @@ -41,14 +43,16 @@ type badgerTxn struct {

type badgerWriter struct {
badgerTxn
discarded bool
}

type badgerIterator struct {
reverse bool
start, end []byte
iter *badger.Iterator
lastErr error
primed bool
// Whether iterator has been advanced to the first element (is fully initialized)
primed bool
}

// Map our versions to Badger timestamps.
Expand Down Expand Up @@ -168,9 +172,9 @@ func (b *BadgerDB) ReaderAt(version uint64) (dbm.DBReader, error) {
func (b *BadgerDB) ReadWriter() dbm.DBReadWriter {
atomic.AddInt32(&b.openWriters, 1)
b.mtx.RLock()
ts := b.vmgr.lastCommitTs()
ts := b.vmgr.lastTs
b.mtx.RUnlock()
return &badgerWriter{badgerTxn{txn: b.db.NewTransactionAt(ts, true), db: b}}
return &badgerWriter{badgerTxn{txn: b.db.NewTransactionAt(ts, true), db: b}, false}
}

func (b *BadgerDB) Writer() dbm.DBWriter {
Expand Down Expand Up @@ -261,11 +265,8 @@ func (tx *badgerTxn) Has(key []byte) (bool, error) {
}

func (tx *badgerWriter) Set(key, value []byte) error {
if len(key) == 0 {
return dbm.ErrKeyEmpty
}
if value == nil {
return dbm.ErrValueNil
if err := dbutil.ValidateKv(key, value); err != nil {
return err
}
return tx.txn.Set(key, value)
}
Expand All @@ -277,20 +278,31 @@ func (tx *badgerWriter) Delete(key []byte) error {
return tx.txn.Delete(key)
}

func (tx *badgerWriter) Commit() error {
func (tx *badgerWriter) Commit() (err error) {
if tx.discarded {
return errors.New("transaction has been discarded")
}
defer func() { err = dbutil.CombineErrors(err, tx.Discard(), "Discard also failed") }()
// Commit to the current commit TS, after ensuring it is > ReadTs
tx.db.mtx.RLock()
tx.db.vmgr.updateCommitTs(tx.txn.ReadTs())
defer tx.Discard()
return tx.txn.CommitAt(tx.db.vmgr.lastCommitTs(), nil)
ts := tx.db.vmgr.lastTs
tx.db.mtx.RUnlock()
err = tx.txn.CommitAt(ts, nil)
return
}

func (tx *badgerTxn) Discard() {
func (tx *badgerTxn) Discard() error {
tx.txn.Discard()
return nil
}

func (tx *badgerWriter) Discard() {
defer atomic.AddInt32(&tx.db.openWriters, -1)
tx.badgerTxn.Discard()
func (tx *badgerWriter) Discard() error {
if !tx.discarded {
defer atomic.AddInt32(&tx.db.openWriters, -1)
tx.discarded = true
}
return tx.badgerTxn.Discard()
}

func (tx *badgerTxn) iteratorOpts(start, end []byte, opts badger.IteratorOptions) (*badgerIterator, error) {
Expand Down Expand Up @@ -393,9 +405,11 @@ func (vm *versionManager) Copy() *versionManager {
}
}

// updateCommitTs atomically increments the lastTs if equal to readts.
// updateCommitTs increments the lastTs if equal to readts.
func (vm *versionManager) updateCommitTs(readts uint64) {
atomic.CompareAndSwapUint64(&vm.lastTs, readts, readts+1)
if vm.lastTs == readts {
vm.lastTs += 1
}
}
func (vm *versionManager) Save(target uint64) (uint64, error) {
id, err := vm.VersionManager.Save(target)
Expand Down
Loading

0 comments on commit 33c8314

Please sign in to comment.