Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(internal/database): badger v3 and memory implementations #3005

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
86dbc26
internal/database: shared errors and interfaces
qdm12 Dec 13, 2022
f5122f5
internal/database/memory implementation with tests
qdm12 Dec 13, 2022
f52ebc2
internal/database/badger implementation
qdm12 Dec 13, 2022
eab45c2
Remove `DropAll` method on tables
qdm12 Dec 13, 2022
21a4b79
Add copyright notices
qdm12 Dec 13, 2022
20bff2d
Shorter error return for `txn.Set(key, value)`
qdm12 Dec 15, 2022
9283017
internal/database/badger tests and fixes
qdm12 Dec 15, 2022
ca1c1e9
internal/database/memory: discard batch once cancel to match badger b…
qdm12 Dec 15, 2022
b098c6d
Add badger race test
qdm12 Dec 15, 2022
4b39e80
Add race tests to `make test-state-race` including other thread safet…
qdm12 Dec 15, 2022
940ad6d
Add `InMemory` badger setting field
qdm12 Dec 16, 2022
d1d840f
Fix typo in package description for `internal/database`
qdm12 Jan 2, 2023
99ce8f3
`internal/database/memory`: use mutex for close
qdm12 Jan 2, 2023
6e06ba2
Mutex protect closed boolean
qdm12 Jan 5, 2023
9981401
memory: return `database.ErrClosed` instead of panic
qdm12 Jan 9, 2023
84d92fa
Transform badger error in `database.ErrClosed`
qdm12 Jan 9, 2023
6809532
Create blackbox testing database_test package
qdm12 Jan 9, 2023
5256a92
Remove commented test code
qdm12 Jan 9, 2023
db445bf
Fix deepsource warnings
qdm12 Jan 9, 2023
257e2ff
Alias badger/v3 import with `badger`
qdm12 Jan 17, 2023
0e9f18e
`makePrefixedKey` -> `newPrefixedKey`
qdm12 Jan 17, 2023
f020a91
Use atomic.Bool for closed field
qdm12 Jan 31, 2023
e44e10c
Add Stream method
qdm12 Jan 31, 2023
fbd3c74
Badger path must be empty when in-memory
qdm12 Feb 3, 2023
1db53a5
Fix test snake cases
qdm12 Feb 6, 2023
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
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ it-polkadotjs: build
test-state-race:
@echo " > \033[32mRunning race tests...\033[0m "
go test ./dot/state/... -race -timeout=5m
go test -run ^Test_hashToBlockMap_threadSafety$ -race -timeout=30s ./dot/state
go test -run ^Test_lockQueue_threadSafety$ -race -timeout=30s ./dot/sync
go test -run ^Test_Database_threadSafety$ -race -timeout=30s ./internal/database/badger
go test -run ^Test_Database_threadSafety$ -race -timeout=30s ./internal/database/memory
go test -run ^Test_hashToRuntime_threadSafety$ -race -timeout=30s ./lib/blocktree
go test -run ^Test_commitsTracker_threadSafety$ -race -timeout=30s ./lib/grandpa

## deps: Install missing dependencies. Runs `go mod download` internally.
deps:
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ require (
github.com/decred/base58 v1.0.3 // indirect
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/dgraph-io/badger/v3 v3.2103.4
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
Expand All @@ -78,8 +79,10 @@ require (
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ github.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32y
github.com/dgraph-io/badger/v2 v2.2007.3/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/badger/v3 v3.2103.4 h1:WE1B07YNTTJTtG9xjBcSW2wn0RJLyiV99h959RKZqM4=
github.com/dgraph-io/badger/v3 v3.2103.4/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw=
github.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
Expand Down Expand Up @@ -190,8 +192,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
Expand All @@ -218,13 +222,16 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/flatbuffers v1.12.1 h1:MVlul7pQNoDzWRLTw5imwYsl+usrS1TXG2H4jg6ImGw=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
Expand Down Expand Up @@ -630,6 +637,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
Expand Down Expand Up @@ -735,6 +743,7 @@ golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down Expand Up @@ -811,12 +820,14 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
Expand Down
154 changes: 154 additions & 0 deletions internal/database/badger/database.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Copyright 2022 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only

// Package badger provides a database implementation using badger v3.
package badger

import (
"context"
"errors"
"fmt"

"github.com/ChainSafe/gossamer/internal/database"
badger "github.com/dgraph-io/badger/v3"
"github.com/dgraph-io/ristretto/z"
)

// Database is database implementation using a badger/v3 database.
type Database struct {
badgerDatabase *badger.DB
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
}

// New returns a new database based on a badger v3 database.
func New(settings Settings) (database *Database, err error) {
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
settings.SetDefaults()
err = settings.Validate()
if err != nil {
return nil, fmt.Errorf("validating settings: %w", err)
}

badgerOptions := badger.DefaultOptions(*settings.Path)
badgerOptions = badgerOptions.WithLogger(nil)
badgerOptions = badgerOptions.WithInMemory(*settings.InMemory)
// TODO enable once we share the same instance
// See https://github.com/ChainSafe/gossamer/issues/2981
// badgerOptions = badgerOptions.WithBypassLockGuard(true)
badgerDatabase, err := badger.Open(badgerOptions)
if err != nil {
return nil, fmt.Errorf("opening badger database: %w", err)
}

return &Database{
badgerDatabase: badgerDatabase,
}, nil
}

// Get retrieves a value from the database using the given key.
// It returns the wrapped error `database.ErrKeyNotFound` if the
// key is not found.
func (db *Database) Get(key []byte) (value []byte, err error) {
err = db.badgerDatabase.View(func(txn *badger.Txn) error {
item, err := txn.Get(key)
if err != nil {
return fmt.Errorf("getting item from transaction: %w", err)
}

value, err = item.ValueCopy(nil)
if err != nil {
return fmt.Errorf("copying value: %w", err)
}
qdm12 marked this conversation as resolved.
Show resolved Hide resolved

return nil
})

if errors.Is(err, badger.ErrKeyNotFound) {
return nil, fmt.Errorf("%w: 0x%x", database.ErrKeyNotFound, key)
}

return value, transformError(err)
}

// Set sets a value at the given key in the database.
func (db *Database) Set(key, value []byte) (err error) {
err = db.badgerDatabase.Update(func(txn *badger.Txn) error {
return txn.Set(key, value)
})
return transformError(err)
}

// Delete deletes the given key from the database.
// If the key is not found, no error is returned.
func (db *Database) Delete(key []byte) (err error) {
err = db.badgerDatabase.Update(func(txn *badger.Txn) error {
return txn.Delete(key)
})
return transformError(err)
}

// NewWriteBatch returns a new write batch for the database.
func (db *Database) NewWriteBatch() (writeBatch database.WriteBatch) {
prefix := []byte(nil)
badgerWriteBatch := db.badgerDatabase.NewWriteBatch()
return newWriteBatch(prefix, badgerWriteBatch)
}

// NewTable returns a new table using the database.
// All keys on the table will be prefixed with the given prefix.
func (db *Database) NewTable(prefix string) (dbTable database.Table) {
return &table{
prefix: []byte(prefix),
database: db,
}
}

// Stream streams data from the database to the `handle`
// function given. The `prefix` is used to filter the keys
// as well as the `chooseKey` function. Note the `prefix`
// argument is more performant than checking the prefix within
// the `chooseKey` function.
func (db *Database) Stream(ctx context.Context,
prefix []byte,
chooseKey func(key []byte) bool,
handle func(key, value []byte) error,
) error {
stream := db.badgerDatabase.NewStream()

if prefix != nil {
stream.Prefix = make([]byte, len(prefix))
copy(stream.Prefix, prefix)
}

stream.ChooseKey = func(item *badger.Item) bool {
key := item.Key()
return chooseKey(key)
}

stream.Send = func(buf *z.Buffer) (err error) {
kvList, err := badger.BufferToKVList(buf)
if err != nil {
return fmt.Errorf("decoding badger proto key value: %w", err)
}

for _, keyValue := range kvList.Kv {
err = handle(keyValue.Key, keyValue.Value)
if err != nil {
return fmt.Errorf("handling key value: %w", err)
}
}
return nil
}

return stream.Orchestrate(ctx)
}

// Close closes the database.
func (db *Database) Close() (err error) {
err = db.badgerDatabase.Close()
return transformError(err)
}

// DropAll drops all data from the database.
func (db *Database) DropAll() (err error) {
err = db.badgerDatabase.DropAll()
return transformError(err)
}
Loading