frostfs-node/pkg/innerring/indexer.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

124 lines
2.3 KiB
Go

package innerring
import (
"fmt"
"sync"
"time"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
)
type (
irFetcher interface {
InnerRingKeys() (keys.PublicKeys, error)
}
committeeFetcher interface {
Committee() (keys.PublicKeys, error)
}
innerRingIndexer struct {
sync.RWMutex
irFetcher irFetcher
commFetcher committeeFetcher
key *keys.PublicKey
timeout time.Duration
ind indexes
lastAccess time.Time
}
indexes struct {
innerRingIndex, innerRingSize int32
alphabetIndex int32
}
)
func newInnerRingIndexer(comf committeeFetcher, irf irFetcher, key *keys.PublicKey, to time.Duration) *innerRingIndexer {
return &innerRingIndexer{
irFetcher: irf,
commFetcher: comf,
key: key,
timeout: to,
}
}
func (s *innerRingIndexer) update() (ind indexes, err error) {
s.RLock()
if time.Since(s.lastAccess) < s.timeout {
s.RUnlock()
return s.ind, nil
}
s.RUnlock()
s.Lock()
defer s.Unlock()
if time.Since(s.lastAccess) < s.timeout {
return s.ind, nil
}
innerRing, err := s.irFetcher.InnerRingKeys()
if err != nil {
return indexes{}, err
}
s.ind.innerRingIndex = keyPosition(s.key, innerRing)
s.ind.innerRingSize = int32(len(innerRing))
alphabet, err := s.commFetcher.Committee()
if err != nil {
return indexes{}, err
}
s.ind.alphabetIndex = keyPosition(s.key, alphabet)
s.lastAccess = time.Now()
return s.ind, nil
}
func (s *innerRingIndexer) InnerRingIndex() (int32, error) {
ind, err := s.update()
if err != nil {
return 0, fmt.Errorf("can't update index state: %w", err)
}
return ind.innerRingIndex, nil
}
func (s *innerRingIndexer) InnerRingSize() (int32, error) {
ind, err := s.update()
if err != nil {
return 0, fmt.Errorf("can't update index state: %w", err)
}
return ind.innerRingSize, nil
}
func (s *innerRingIndexer) AlphabetIndex() (int32, error) {
ind, err := s.update()
if err != nil {
return 0, fmt.Errorf("can't update index state: %w", err)
}
return ind.alphabetIndex, nil
}
// keyPosition returns "-1" if key is not found in the list, otherwise returns
// index of the key.
func keyPosition(key *keys.PublicKey, list keys.PublicKeys) (result int32) {
result = -1
for i := range list {
if key.Equal(list[i]) {
result = int32(i)
break
}
}
return result
}