316 lines
7.5 KiB
Go
316 lines
7.5 KiB
Go
package ormtable_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/cosmos/cosmos-sdk/orm/internal/testkv"
|
|
"github.com/cosmos/cosmos-sdk/orm/testing/ormtest"
|
|
|
|
dbm "github.com/tendermint/tm-db"
|
|
"gotest.tools/v3/assert"
|
|
|
|
"github.com/cosmos/cosmos-sdk/orm/internal/testpb"
|
|
"github.com/cosmos/cosmos-sdk/orm/model/ormtable"
|
|
"github.com/cosmos/cosmos-sdk/orm/types/kv"
|
|
)
|
|
|
|
func initBalanceTable(t testing.TB) testpb.BalanceTable {
|
|
table, err := ormtable.Build(ormtable.Options{
|
|
MessageType: (&testpb.Balance{}).ProtoReflect().Type(),
|
|
})
|
|
assert.NilError(t, err)
|
|
|
|
balanceTable, err := testpb.NewBalanceTable(table)
|
|
assert.NilError(t, err)
|
|
|
|
return balanceTable
|
|
}
|
|
|
|
func BenchmarkMemory(b *testing.B) {
|
|
bench(b, func(tb testing.TB) ormtable.Backend {
|
|
return ormtest.NewMemoryBackend()
|
|
})
|
|
}
|
|
|
|
func BenchmarkLevelDB(b *testing.B) {
|
|
bench(b, testkv.NewGoLevelDBBackend)
|
|
}
|
|
|
|
func bench(b *testing.B, newBackend func(testing.TB) ormtable.Backend) {
|
|
b.Run("insert", func(b *testing.B) {
|
|
b.StopTimer()
|
|
ctx := ormtable.WrapContextDefault(newBackend(b))
|
|
b.StartTimer()
|
|
benchInsert(b, ctx)
|
|
})
|
|
b.Run("update", func(b *testing.B) {
|
|
b.StopTimer()
|
|
ctx := ormtable.WrapContextDefault(newBackend(b))
|
|
benchInsert(b, ctx)
|
|
b.StartTimer()
|
|
benchUpdate(b, ctx)
|
|
})
|
|
b.Run("get", func(b *testing.B) {
|
|
b.StopTimer()
|
|
ctx := ormtable.WrapContextDefault(newBackend(b))
|
|
benchInsert(b, ctx)
|
|
b.StartTimer()
|
|
benchGet(b, ctx)
|
|
})
|
|
b.Run("delete", func(b *testing.B) {
|
|
b.StopTimer()
|
|
ctx := ormtable.WrapContextDefault(newBackend(b))
|
|
benchInsert(b, ctx)
|
|
b.StartTimer()
|
|
benchDelete(b, ctx)
|
|
})
|
|
}
|
|
|
|
func benchInsert(b *testing.B, ctx context.Context) {
|
|
balanceTable := initBalanceTable(b)
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, balanceTable.Insert(ctx, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
Amount: 10,
|
|
}))
|
|
}
|
|
}
|
|
|
|
func benchUpdate(b *testing.B, ctx context.Context) {
|
|
balanceTable := initBalanceTable(b)
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, balanceTable.Update(ctx, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
Amount: 11,
|
|
}))
|
|
}
|
|
}
|
|
|
|
func benchGet(b *testing.B, ctx context.Context) {
|
|
balanceTable := initBalanceTable(b)
|
|
for i := 0; i < b.N; i++ {
|
|
balance, err := balanceTable.Get(ctx, fmt.Sprintf("acct%d", i), "bar")
|
|
assert.NilError(b, err)
|
|
assert.Equal(b, uint64(10), balance.Amount)
|
|
}
|
|
}
|
|
|
|
func benchDelete(b *testing.B, ctx context.Context) {
|
|
balanceTable := initBalanceTable(b)
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, balanceTable.Delete(ctx, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
}))
|
|
}
|
|
}
|
|
|
|
//
|
|
// Manually written versions of insert, update, delete and get for testpb.Balance
|
|
//
|
|
|
|
const (
|
|
addressDenomPrefix byte = iota
|
|
denomAddressPrefix
|
|
)
|
|
|
|
func insertBalance(store kv.Store, balance *testpb.Balance) error {
|
|
denom := balance.Denom
|
|
balance.Denom = ""
|
|
addr := balance.Address
|
|
balance.Address = ""
|
|
|
|
addressDenomKey := []byte{addressDenomPrefix}
|
|
addressDenomKey = append(addressDenomKey, []byte(addr)...)
|
|
addressDenomKey = append(addressDenomKey, 0x0)
|
|
addressDenomKey = append(addressDenomKey, []byte(denom)...)
|
|
has, err := store.Has(addressDenomKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if has {
|
|
return fmt.Errorf("already exists")
|
|
}
|
|
|
|
bz, err := proto.Marshal(balance)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
balance.Denom = denom
|
|
balance.Address = addr
|
|
|
|
err = store.Set(addressDenomKey, bz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// set denom address index
|
|
denomAddressKey := []byte{denomAddressPrefix}
|
|
denomAddressKey = append(denomAddressKey, []byte(balance.Denom)...)
|
|
denomAddressKey = append(denomAddressKey, 0x0)
|
|
denomAddressKey = append(denomAddressKey, []byte(balance.Address)...)
|
|
err = store.Set(denomAddressKey, []byte{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func updateBalance(store kv.Store, balance *testpb.Balance) error {
|
|
denom := balance.Denom
|
|
balance.Denom = ""
|
|
addr := balance.Address
|
|
balance.Address = ""
|
|
bz, err := proto.Marshal(balance)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
balance.Denom = denom
|
|
balance.Address = addr
|
|
|
|
addressDenomKey := []byte{addressDenomPrefix}
|
|
addressDenomKey = append(addressDenomKey, []byte(addr)...)
|
|
addressDenomKey = append(addressDenomKey, 0x0)
|
|
addressDenomKey = append(addressDenomKey, []byte(denom)...)
|
|
|
|
return store.Set(addressDenomKey, bz)
|
|
}
|
|
|
|
func deleteBalance(store kv.Store, balance *testpb.Balance) error {
|
|
denom := balance.Denom
|
|
addr := balance.Address
|
|
|
|
addressDenomKey := []byte{addressDenomPrefix}
|
|
addressDenomKey = append(addressDenomKey, []byte(addr)...)
|
|
addressDenomKey = append(addressDenomKey, 0x0)
|
|
addressDenomKey = append(addressDenomKey, []byte(denom)...)
|
|
err := store.Delete(addressDenomKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
denomAddressKey := []byte{denomAddressPrefix}
|
|
denomAddressKey = append(denomAddressKey, []byte(balance.Denom)...)
|
|
denomAddressKey = append(denomAddressKey, 0x0)
|
|
denomAddressKey = append(denomAddressKey, []byte(balance.Address)...)
|
|
return store.Delete(denomAddressKey)
|
|
}
|
|
|
|
func getBalance(store kv.Store, address, denom string) (*testpb.Balance, error) {
|
|
addressDenomKey := []byte{addressDenomPrefix}
|
|
addressDenomKey = append(addressDenomKey, []byte(address)...)
|
|
addressDenomKey = append(addressDenomKey, 0x0)
|
|
addressDenomKey = append(addressDenomKey, []byte(denom)...)
|
|
|
|
bz, err := store.Get(addressDenomKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if bz == nil {
|
|
return nil, fmt.Errorf("not found")
|
|
}
|
|
|
|
var balance = testpb.Balance{}
|
|
err = proto.Unmarshal(bz, &balance)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
balance.Address = address
|
|
balance.Denom = denom
|
|
|
|
return &balance, nil
|
|
}
|
|
|
|
func BenchmarkManualInsertMemory(b *testing.B) {
|
|
benchManual(b, func() (dbm.DB, error) {
|
|
return dbm.NewMemDB(), nil
|
|
})
|
|
}
|
|
|
|
func BenchmarkManualInsertLevelDB(b *testing.B) {
|
|
benchManual(b, func() (dbm.DB, error) {
|
|
return dbm.NewGoLevelDB("test", b.TempDir())
|
|
})
|
|
}
|
|
|
|
func benchManual(b *testing.B, newStore func() (dbm.DB, error)) {
|
|
b.Run("insert", func(b *testing.B) {
|
|
b.StopTimer()
|
|
store, err := newStore()
|
|
assert.NilError(b, err)
|
|
b.StartTimer()
|
|
benchManualInsert(b, store)
|
|
})
|
|
b.Run("update", func(b *testing.B) {
|
|
b.StopTimer()
|
|
store, err := newStore()
|
|
assert.NilError(b, err)
|
|
benchManualInsert(b, store)
|
|
b.StartTimer()
|
|
benchManualUpdate(b, store)
|
|
})
|
|
b.Run("get", func(b *testing.B) {
|
|
b.StopTimer()
|
|
store, err := newStore()
|
|
assert.NilError(b, err)
|
|
benchManualInsert(b, store)
|
|
b.StartTimer()
|
|
benchManualGet(b, store)
|
|
})
|
|
b.Run("delete", func(b *testing.B) {
|
|
b.StopTimer()
|
|
store, err := newStore()
|
|
assert.NilError(b, err)
|
|
benchManualInsert(b, store)
|
|
b.StartTimer()
|
|
benchManualDelete(b, store)
|
|
})
|
|
}
|
|
|
|
func benchManualInsert(b *testing.B, store kv.Store) {
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, insertBalance(store, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
Amount: 10,
|
|
}))
|
|
}
|
|
}
|
|
|
|
func benchManualUpdate(b *testing.B, store kv.Store) {
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, updateBalance(store, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
Amount: 11,
|
|
}))
|
|
}
|
|
}
|
|
|
|
func benchManualDelete(b *testing.B, store kv.Store) {
|
|
for i := 0; i < b.N; i++ {
|
|
assert.NilError(b, deleteBalance(store, &testpb.Balance{
|
|
Address: fmt.Sprintf("acct%d", i),
|
|
Denom: "bar",
|
|
}))
|
|
}
|
|
}
|
|
|
|
func benchManualGet(b *testing.B, store kv.Store) {
|
|
for i := 0; i < b.N; i++ {
|
|
balance, err := getBalance(store, fmt.Sprintf("acct%d", i), "bar")
|
|
assert.NilError(b, err)
|
|
assert.Equal(b, uint64(10), balance.Amount)
|
|
}
|
|
}
|