mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-19 06:31:57 +00:00
store: use db iterators for pruning and range-based queries (#5848)
This commit is contained in:
@@ -37,7 +37,7 @@ func BenchmarkSequence(b *testing.B) {
|
||||
},
|
||||
benchmarkFullNode,
|
||||
[]provider.Provider{benchmarkFullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.SequentialVerification(),
|
||||
)
|
||||
@@ -65,7 +65,7 @@ func BenchmarkBisection(b *testing.B) {
|
||||
},
|
||||
benchmarkFullNode,
|
||||
[]provider.Provider{benchmarkFullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -93,7 +93,7 @@ func BenchmarkBackwards(b *testing.B) {
|
||||
},
|
||||
benchmarkFullNode,
|
||||
[]provider.Provider{benchmarkFullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
+21
-21
@@ -231,7 +231,7 @@ func TestClient_SequentialVerification(t *testing.T) {
|
||||
tc.otherHeaders,
|
||||
tc.vals,
|
||||
)},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.SequentialVerification(),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
@@ -356,7 +356,7 @@ func TestClient_SkippingVerification(t *testing.T) {
|
||||
tc.otherHeaders,
|
||||
tc.vals,
|
||||
)},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.SkippingVerification(light.DefaultTrustLevel),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
@@ -394,7 +394,7 @@ func TestClientLargeBisectionVerification(t *testing.T) {
|
||||
},
|
||||
veryLargeFullNode,
|
||||
[]provider.Provider{veryLargeFullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.SkippingVerification(light.DefaultTrustLevel),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -416,7 +416,7 @@ func TestClientBisectionBetweenTrustedHeaders(t *testing.T) {
|
||||
},
|
||||
fullNode,
|
||||
[]provider.Provider{fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.SkippingVerification(light.DefaultTrustLevel),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -440,7 +440,7 @@ func TestClient_Cleanup(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -460,7 +460,7 @@ func TestClient_Cleanup(t *testing.T) {
|
||||
func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
|
||||
// 1. options.Hash == trustedHeader.Hash
|
||||
{
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -484,7 +484,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
|
||||
|
||||
// 2. options.Hash != trustedHeader.Hash
|
||||
{
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -529,7 +529,7 @@ func TestClientRestoresTrustedHeaderAfterStartup1(t *testing.T) {
|
||||
func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
|
||||
// 1. options.Hash == trustedHeader.Hash
|
||||
{
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -559,7 +559,7 @@ func TestClientRestoresTrustedHeaderAfterStartup2(t *testing.T) {
|
||||
// 2. options.Hash != trustedHeader.Hash
|
||||
// This could happen if previous provider was lying to us.
|
||||
{
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -606,7 +606,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
|
||||
// 1. options.Hash == trustedHeader.Hash
|
||||
{
|
||||
// load the first three headers into the trusted store
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -644,7 +644,7 @@ func TestClientRestoresTrustedHeaderAfterStartup3(t *testing.T) {
|
||||
// 2. options.Hash != trustedHeader.Hash
|
||||
// This could happen if previous provider was lying to us.
|
||||
{
|
||||
trustedStore := dbs.New(dbm.NewMemDB(), chainID)
|
||||
trustedStore := dbs.New(dbm.NewMemDB())
|
||||
err := trustedStore.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -704,7 +704,7 @@ func TestClient_Update(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -725,7 +725,7 @@ func TestClient_Concurrency(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -766,7 +766,7 @@ func TestClientReplacesPrimaryWithWitnessIfPrimaryIsUnavailable(t *testing.T) {
|
||||
trustOptions,
|
||||
deadNode,
|
||||
[]provider.Provider{fullNode, fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
@@ -792,7 +792,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
|
||||
},
|
||||
largeFullNode,
|
||||
[]provider.Provider{largeFullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -874,7 +874,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
|
||||
},
|
||||
tc.provider,
|
||||
[]provider.Provider{tc.provider},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err, idx)
|
||||
@@ -887,7 +887,7 @@ func TestClient_BackwardsVerification(t *testing.T) {
|
||||
|
||||
func TestClient_NewClientFromTrustedStore(t *testing.T) {
|
||||
// 1) Initiate DB and fill with a "trusted" header
|
||||
db := dbs.New(dbm.NewMemDB(), chainID)
|
||||
db := dbs.New(dbm.NewMemDB())
|
||||
err := db.SaveLightBlock(l1)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -944,7 +944,7 @@ func TestClientRemovesWitnessIfItSendsUsIncorrectHeader(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{badProvider1, badProvider2},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
@@ -994,7 +994,7 @@ func TestClient_TrustedValidatorSet(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{badValSetNode, fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
@@ -1012,7 +1012,7 @@ func TestClientPrunesHeadersAndValidatorSets(t *testing.T) {
|
||||
trustOptions,
|
||||
fullNode,
|
||||
[]provider.Provider{fullNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.PruningSize(1),
|
||||
)
|
||||
@@ -1085,7 +1085,7 @@ func TestClientEnsureValidHeadersAndValSets(t *testing.T) {
|
||||
trustOptions,
|
||||
badNode,
|
||||
[]provider.Provider{badNode, badNode},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
@@ -54,7 +54,7 @@ func TestLightClientAttackEvidence_Lunatic(t *testing.T) {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{witness},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
@@ -136,7 +136,7 @@ func TestLightClientAttackEvidence_Equivocation(t *testing.T) {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{witness},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
verificationOption,
|
||||
@@ -191,7 +191,7 @@ func TestClientDivergentTraces1(t *testing.T) {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{witness},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
@@ -215,7 +215,7 @@ func TestClientDivergentTraces2(t *testing.T) {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{deadNode, deadNode, primary},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
@@ -250,7 +250,7 @@ func TestClientDivergentTraces3(t *testing.T) {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{witness},
|
||||
dbs.New(dbm.NewMemDB(), chainID),
|
||||
dbs.New(dbm.NewMemDB()),
|
||||
light.Logger(log.TestingLogger()),
|
||||
light.MaxRetryAttempts(1),
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ func ExampleClient_Update() {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{primary}, // NOTE: primary should not be used here
|
||||
dbs.New(db, chainID),
|
||||
dbs.New(db),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
@@ -129,7 +129,7 @@ func ExampleClient_VerifyLightBlockAtHeight() {
|
||||
},
|
||||
primary,
|
||||
[]provider.Provider{primary}, // NOTE: primary should not be used here
|
||||
dbs.New(db, chainID),
|
||||
dbs.New(db),
|
||||
light.Logger(log.TestingLogger()),
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
+29
-37
@@ -19,18 +19,17 @@ const (
|
||||
)
|
||||
|
||||
type dbs struct {
|
||||
db dbm.DB
|
||||
prefix string
|
||||
db dbm.DB
|
||||
|
||||
mtx tmsync.RWMutex
|
||||
size uint16
|
||||
}
|
||||
|
||||
// New returns a Store that wraps any DB (with an optional prefix in case you
|
||||
// want to use one DB with many light clients).
|
||||
func New(db dbm.DB, prefix string) store.Store {
|
||||
// New returns a Store that wraps any DB
|
||||
// If you want to share one DB across many light clients consider using PrefixDB
|
||||
func New(db dbm.DB) store.Store {
|
||||
|
||||
lightStore := &dbs{db: db, prefix: prefix}
|
||||
lightStore := &dbs{db: db}
|
||||
|
||||
// retrieve the size of the db
|
||||
size := uint16(0)
|
||||
@@ -197,11 +196,17 @@ func (s *dbs) LightBlockBefore(height int64) (*types.LightBlock, error) {
|
||||
defer itr.Close()
|
||||
|
||||
if itr.Valid() {
|
||||
existingHeight, err := s.decodeLbKey(itr.Key())
|
||||
var lbpb tmproto.LightBlock
|
||||
err = lbpb.Unmarshal(itr.Value())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("unmarshal error: %w", err)
|
||||
}
|
||||
return s.LightBlock(existingHeight)
|
||||
|
||||
lightBlock, err := types.LightBlockFromProto(&lbpb)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("proto conversion error: %w", err)
|
||||
}
|
||||
return lightBlock, nil
|
||||
}
|
||||
if err = itr.Error(); err != nil {
|
||||
return nil, err
|
||||
@@ -238,39 +243,32 @@ func (s *dbs) Prune(size uint16) error {
|
||||
b := s.db.NewBatch()
|
||||
defer b.Close()
|
||||
|
||||
pruned := 0
|
||||
for itr.Valid() && numToPrune > 0 {
|
||||
key := itr.Key()
|
||||
height, err := s.decodeLbKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = b.Delete(s.lbKey(height)); err != nil {
|
||||
if err = b.Delete(itr.Key()); err != nil {
|
||||
return err
|
||||
}
|
||||
itr.Next()
|
||||
numToPrune--
|
||||
pruned++
|
||||
}
|
||||
if err = itr.Error(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 3) // update size
|
||||
s.mtx.Lock()
|
||||
s.size = size
|
||||
s.mtx.Unlock()
|
||||
|
||||
if wErr := b.Set(s.sizeKey(), marshalSize(size)); wErr != nil {
|
||||
return fmt.Errorf("failed to persist size: %w", wErr)
|
||||
}
|
||||
|
||||
// 4) write batch deletion to disk
|
||||
err = b.WriteSync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 3) Update size.
|
||||
s.mtx.Lock()
|
||||
defer s.mtx.Unlock()
|
||||
|
||||
s.size -= uint16(pruned)
|
||||
|
||||
if wErr := s.db.SetSync(s.sizeKey(), marshalSize(size)); wErr != nil {
|
||||
return fmt.Errorf("failed to persist size: %w", wErr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -284,7 +282,7 @@ func (s *dbs) Size() uint16 {
|
||||
}
|
||||
|
||||
func (s *dbs) sizeKey() []byte {
|
||||
key, err := orderedcode.Append(nil, s.prefix, prefixSize)
|
||||
key, err := orderedcode.Append(nil, prefixSize)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -292,7 +290,7 @@ func (s *dbs) sizeKey() []byte {
|
||||
}
|
||||
|
||||
func (s *dbs) lbKey(height int64) []byte {
|
||||
key, err := orderedcode.Append(nil, s.prefix, prefixLightBlock, height)
|
||||
key, err := orderedcode.Append(nil, prefixLightBlock, height)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -300,11 +298,8 @@ func (s *dbs) lbKey(height int64) []byte {
|
||||
}
|
||||
|
||||
func (s *dbs) decodeLbKey(key []byte) (height int64, err error) {
|
||||
var (
|
||||
dbPrefix string
|
||||
lightBlockPrefix int64
|
||||
)
|
||||
remaining, err := orderedcode.Parse(string(key), &dbPrefix, &lightBlockPrefix, &height)
|
||||
var lightBlockPrefix int64
|
||||
remaining, err := orderedcode.Parse(string(key), &lightBlockPrefix, &height)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to parse light block key: %w", err)
|
||||
}
|
||||
@@ -314,9 +309,6 @@ func (s *dbs) decodeLbKey(key []byte) (height int64, err error) {
|
||||
if lightBlockPrefix != prefixLightBlock {
|
||||
err = fmt.Errorf("expected light block prefix but got: %d", lightBlockPrefix)
|
||||
}
|
||||
if dbPrefix != s.prefix {
|
||||
err = fmt.Errorf("parsed key has a different prefix. Expected: %s, got: %s", s.prefix, dbPrefix)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
)
|
||||
|
||||
func TestLast_FirstLightBlockHeight(t *testing.T) {
|
||||
dbStore := New(dbm.NewMemDB(), "TestLast_FirstLightBlockHeight")
|
||||
dbStore := New(dbm.NewMemDB())
|
||||
|
||||
// Empty store
|
||||
height, err := dbStore.LastLightBlockHeight()
|
||||
@@ -44,7 +44,7 @@ func TestLast_FirstLightBlockHeight(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_SaveLightBlock(t *testing.T) {
|
||||
dbStore := New(dbm.NewMemDB(), "Test_SaveLightBlockAndValidatorSet")
|
||||
dbStore := New(dbm.NewMemDB())
|
||||
|
||||
// Empty store
|
||||
h, err := dbStore.LightBlock(1)
|
||||
@@ -74,7 +74,7 @@ func Test_SaveLightBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_LightBlockBefore(t *testing.T) {
|
||||
dbStore := New(dbm.NewMemDB(), "Test_LightBlockBefore")
|
||||
dbStore := New(dbm.NewMemDB())
|
||||
|
||||
assert.Panics(t, func() {
|
||||
_, _ = dbStore.LightBlockBefore(0)
|
||||
@@ -95,7 +95,7 @@ func Test_LightBlockBefore(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Prune(t *testing.T) {
|
||||
dbStore := New(dbm.NewMemDB(), "Test_Prune")
|
||||
dbStore := New(dbm.NewMemDB())
|
||||
|
||||
// Empty store
|
||||
assert.EqualValues(t, 0, dbStore.Size())
|
||||
@@ -132,7 +132,7 @@ func Test_Prune(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_Concurrency(t *testing.T) {
|
||||
dbStore := New(dbm.NewMemDB(), "Test_Prune")
|
||||
dbStore := New(dbm.NewMemDB())
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 1; i <= 100; i++ {
|
||||
|
||||
Reference in New Issue
Block a user