frostfs-node/pkg/innerring/indexer_test.go
Evgenii Stratonikov cddc58ace2 [#752] innerring: Optimize keyPosition()
```
goos: linux
goarch: amd64
pkg: git.frostfs.info/TrueCloudLab/frostfs-node/pkg/innerring
cpu: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
              │      old       │                 new                 │
              │     sec/op     │   sec/op     vs base                │
KeyPosition-8   2771.50n ± 10%   40.32n ± 4%  -98.55% (p=0.000 n=10)

              │     old      │                  new                  │
              │     B/op     │     B/op      vs base                 │
KeyPosition-8   1.531Ki ± 0%   0.000Ki ± 0%  -100.00% (p=0.000 n=10)

              │    old     │                new                 │
              │ allocs/op  │ allocs/op  vs base                 │
KeyPosition-8   21.00 ± 0%   0.00 ± 0%  -100.00% (p=0.000 n=10)
```

Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-10-25 16:06:44 +03:00

245 lines
7.4 KiB
Go

package innerring
import (
"fmt"
"sync/atomic"
"testing"
"time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
func TestIndexerReturnsIndexes(t *testing.T) {
t.Parallel()
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{
"03ff65b6ae79134a4dce9d0d39d3851e9bab4ee97abf86e81e1c5bbc50cd2826ae",
"022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131",
})
require.NoError(t, err, "convert string to commitee public keys failed")
cf := &testCommiteeFetcher{
keys: commiteeKeys,
}
irKeys, err := keys.NewPublicKeysFromStrings([]string{
"038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35",
"02ac920cd7df0b61b289072e6b946e2da4e1a31b9ab1c621bb475e30fa4ab102c3",
"022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131",
})
require.NoError(t, err, "convert string to IR public keys failed")
irf := &testIRFetcher{
keys: irKeys,
}
t.Run("success", func(t *testing.T) {
t.Parallel()
key := irKeys[2]
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
idx, err := indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(1), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(2), idx, "invalid IR index")
size, err := indexer.InnerRingSize()
require.NoError(t, err, "failed to get IR size")
require.Equal(t, int32(3), size, "invalid IR size")
})
t.Run("not found alphabet", func(t *testing.T) {
t.Parallel()
key := irKeys[0]
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
idx, err := indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(-1), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(0), idx, "invalid IR index")
})
t.Run("not found IR", func(t *testing.T) {
t.Parallel()
key := commiteeKeys[0]
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
idx, err := indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(0), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(-1), idx, "invalid IR index")
})
}
func TestIndexerCachesIndexes(t *testing.T) {
t.Parallel()
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{})
require.NoError(t, err, "convert string to commitee public keys failed")
cf := &testCommiteeFetcher{
keys: commiteeKeys,
}
irKeys, err := keys.NewPublicKeysFromStrings([]string{})
require.NoError(t, err, "convert string to IR public keys failed")
irf := &testIRFetcher{
keys: irKeys,
}
key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131")
require.NoError(t, err, "convert string to public key failed")
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
idx, err := indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(-1), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(-1), idx, "invalid IR index")
size, err := indexer.InnerRingSize()
require.NoError(t, err, "failed to get IR size")
require.Equal(t, int32(0), size, "invalid IR size")
require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count")
require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count")
idx, err = indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(-1), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(-1), idx, "invalid IR index")
size, err = indexer.InnerRingSize()
require.NoError(t, err, "failed to get IR size")
require.Equal(t, int32(0), size, "invalid IR size")
require.Equal(t, int32(1), cf.calls.Load(), "invalid commitee calls count")
require.Equal(t, int32(1), irf.calls.Load(), "invalid IR calls count")
time.Sleep(2 * time.Second)
idx, err = indexer.AlphabetIndex()
require.NoError(t, err, "failed to get alphabet index")
require.Equal(t, int32(-1), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.NoError(t, err, "failed to get IR index")
require.Equal(t, int32(-1), idx, "invalid IR index")
size, err = indexer.InnerRingSize()
require.NoError(t, err, "failed to get IR size")
require.Equal(t, int32(0), size, "invalid IR size")
require.Equal(t, int32(2), cf.calls.Load(), "invalid commitee calls count")
require.Equal(t, int32(2), irf.calls.Load(), "invalid IR calls count")
}
func TestIndexerThrowsErrors(t *testing.T) {
t.Parallel()
cf := &testCommiteeFetcher{
err: fmt.Errorf("test commitee error"),
}
irKeys, err := keys.NewPublicKeysFromStrings([]string{})
require.NoError(t, err, "convert string to IR public keys failed")
irf := &testIRFetcher{
keys: irKeys,
}
key, err := keys.NewPublicKeyFromString("022bb4041c50d607ff871dec7e4cd7778388e0ea6849d84ccbd9aa8f32e16a8131")
require.NoError(t, err, "convert string to public key failed")
indexer := newInnerRingIndexer(cf, irf, key, time.Second)
idx, err := indexer.AlphabetIndex()
require.ErrorContains(t, err, "test commitee error", "error from commitee not throwed")
require.Equal(t, int32(0), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.ErrorContains(t, err, "test commitee error", "error from IR not throwed")
require.Equal(t, int32(0), idx, "invalid IR index")
size, err := indexer.InnerRingSize()
require.ErrorContains(t, err, "test commitee error", "error from IR not throwed")
require.Equal(t, int32(0), size, "invalid IR size")
commiteeKeys, err := keys.NewPublicKeysFromStrings([]string{})
require.NoError(t, err, "convert string to commitee public keys failed")
cf = &testCommiteeFetcher{
keys: commiteeKeys,
}
irf = &testIRFetcher{
err: fmt.Errorf("test IR error"),
}
indexer = newInnerRingIndexer(cf, irf, key, time.Second)
idx, err = indexer.AlphabetIndex()
require.ErrorContains(t, err, "test IR error", "error from commitee not throwed")
require.Equal(t, int32(0), idx, "invalid alphabet index")
idx, err = indexer.InnerRingIndex()
require.ErrorContains(t, err, "test IR error", "error from IR not throwed")
require.Equal(t, int32(0), idx, "invalid IR index")
size, err = indexer.InnerRingSize()
require.ErrorContains(t, err, "test IR error", "error from IR not throwed")
require.Equal(t, int32(0), size, "invalid IR size")
}
type testCommiteeFetcher struct {
keys keys.PublicKeys
err error
calls atomic.Int32
}
func (f *testCommiteeFetcher) Committee() (keys.PublicKeys, error) {
f.calls.Add(1)
return f.keys, f.err
}
type testIRFetcher struct {
keys keys.PublicKeys
err error
calls atomic.Int32
}
func (f *testIRFetcher) InnerRingKeys() (keys.PublicKeys, error) {
f.calls.Add(1)
return f.keys, f.err
}
func BenchmarkKeyPosition(b *testing.B) {
list := make(keys.PublicKeys, 7)
for i := range list {
p, err := keys.NewPrivateKey()
require.NoError(b, err)
list[i] = p.PublicKey()
}
key := new(keys.PublicKey)
require.NoError(b, key.DecodeBytes(list[5].Bytes()))
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
if keyPosition(key, list) != 5 {
b.FailNow()
}
}
}