Skip to content

Commit

Permalink
Merge pull request #5401 from multiversx/trie-storage-statistics-comp…
Browse files Browse the repository at this point in the history
…onent

Trie storage statistics component
  • Loading branch information
ssd04 committed Nov 6, 2023
2 parents 8a01c07 + d2f3f82 commit e6e79c4
Show file tree
Hide file tree
Showing 83 changed files with 951 additions and 138 deletions.
25 changes: 25 additions & 0 deletions common/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type StorageManager interface {
type TrieStorageInteractor interface {
BaseStorer
GetIdentifier() string
GetStateStatsHandler() StateStatisticsHandler
}

// BaseStorer define the base methods needed for a storer
Expand Down Expand Up @@ -216,6 +217,30 @@ type TriesStatisticsCollector interface {
GetNumNodes() uint64
}

// StateStatisticsHandler defines the behaviour of a storage statistics handler
type StateStatisticsHandler interface {
Reset()
ResetSnapshot()

IncrCache()
Cache() uint64
IncrSnapshotCache()
SnapshotCache() uint64

IncrPersister(epoch uint32)
Persister(epoch uint32) uint64
IncrSnapshotPersister(epoch uint32)
SnapshotPersister(epoch uint32) uint64

IncrTrie()
Trie() uint64

ProcessingStats() []string
SnapshotStats() []string

IsInterfaceNil() bool
}

// ProcessStatusHandler defines the behavior of a component able to hold the current status of the node and
// able to tell if the node is idle or processing/committing a block
type ProcessStatusHandler interface {
Expand Down
80 changes: 80 additions & 0 deletions common/statistics/disabled/stateStatistics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package disabled

type stateStatistics struct{}

// NewStateStatistics will create a new disabled statistics component
func NewStateStatistics() *stateStatistics {
return &stateStatistics{}
}

// ResetAll does nothing
func (s *stateStatistics) ResetAll() {
}

// Reset does nothing
func (s *stateStatistics) Reset() {
}

// ResetSnapshot does nothing
func (s *stateStatistics) ResetSnapshot() {
}

// IncrCache does nothing
func (s *stateStatistics) IncrCache() {
}

// Cache returns zero
func (s *stateStatistics) Cache() uint64 {
return 0
}

// IncrSnapshotCache does nothing
func (ss *stateStatistics) IncrSnapshotCache() {
}

// SnapshotCache returns the number of cached operations
func (ss *stateStatistics) SnapshotCache() uint64 {
return 0
}

// IncrPersister does nothing
func (s *stateStatistics) IncrPersister(epoch uint32) {
}

// Persister returns zero
func (s *stateStatistics) Persister(epoch uint32) uint64 {
return 0
}

// IncrSnapshotPersister does nothing
func (ss *stateStatistics) IncrSnapshotPersister(epoch uint32) {
}

// SnapshotPersister returns the number of persister operations
func (ss *stateStatistics) SnapshotPersister(epoch uint32) uint64 {
return 0
}

// IncrTrie does nothing
func (s *stateStatistics) IncrTrie() {
}

// Trie returns zero
func (s *stateStatistics) Trie() uint64 {
return 0
}

// ProcessingStats returns nil
func (s *stateStatistics) ProcessingStats() []string {
return nil
}

// SnapshotStats returns nil
func (s *stateStatistics) SnapshotStats() []string {
return nil
}

// IsInterfaceNil returns true if there is no value under the interface
func (s *stateStatistics) IsInterfaceNil() bool {
return s == nil
}
46 changes: 46 additions & 0 deletions common/statistics/disabled/stateStatistics_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package disabled

import (
"fmt"
"testing"

"github.com/multiversx/mx-chain-core-go/core/check"
"github.com/stretchr/testify/require"
)

func TestNewDisabledStateStatistics(t *testing.T) {
t.Parallel()

stats := NewStateStatistics()
require.False(t, check.IfNil(stats))
}

func TestStateStatistics_MethodsShouldNotPanic(t *testing.T) {
t.Parallel()

defer func() {
r := recover()
if r != nil {
require.Fail(t, fmt.Sprintf("should have not panicked %v", r))
}
}()

stats := NewStateStatistics()

stats.Reset()
stats.ResetSnapshot()
stats.ResetAll()

stats.IncrCache()
stats.IncrSnapshotCache()
stats.IncrSnapshotCache()
stats.IncrPersister(1)
stats.IncrSnapshotPersister(1)
stats.IncrTrie()

require.Equal(t, uint64(0), stats.Cache())
require.Equal(t, uint64(0), stats.SnapshotCache())
require.Equal(t, uint64(0), stats.Persister(1))
require.Equal(t, uint64(0), stats.SnapshotPersister(1))
require.Equal(t, uint64(0), stats.Trie())
}
3 changes: 3 additions & 0 deletions common/statistics/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ var ErrNilNetworkStatisticsProvider = errors.New("nil network statistics provide

// ErrInvalidRefreshIntervalValue signals that an invalid value for the refresh interval was provided
var ErrInvalidRefreshIntervalValue = errors.New("invalid refresh interval value")

// ErrNilStateStatsHandler signals that a nil state statistics handler was provided
var ErrNilStateStatsHandler = errors.New("nil state statistics handler")
153 changes: 153 additions & 0 deletions common/statistics/stateStatistics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package statistics

import (
"fmt"
"sync"
"sync/atomic"
)

type stateStatistics struct {
numCache uint64
numSnapshotCache uint64

numPersister map[uint32]uint64
numSnapshotPersister map[uint32]uint64
mutPersisters sync.RWMutex

numTrie uint64
}

// NewStateStatistics returns a structure able to collect statistics for state
func NewStateStatistics() *stateStatistics {
return &stateStatistics{
numPersister: make(map[uint32]uint64),
numSnapshotPersister: make(map[uint32]uint64),
}
}

// ResetAll will reset all statistics
func (ss *stateStatistics) ResetAll() {
ss.Reset()
ss.ResetSnapshot()
}

// Reset will reset processing statistics
func (ss *stateStatistics) Reset() {
atomic.StoreUint64(&ss.numCache, 0)

ss.mutPersisters.Lock()
ss.numPersister = make(map[uint32]uint64)
ss.mutPersisters.Unlock()

atomic.StoreUint64(&ss.numTrie, 0)
}

// ResetSnapshot will reset snapshot statistics
func (ss *stateStatistics) ResetSnapshot() {
atomic.StoreUint64(&ss.numSnapshotCache, 0)

ss.mutPersisters.Lock()
ss.numSnapshotPersister = make(map[uint32]uint64)
ss.mutPersisters.Unlock()
}

// IncrCache will increment cache counter
func (ss *stateStatistics) IncrCache() {
atomic.AddUint64(&ss.numCache, 1)
}

// Cache returns the number of cached operations
func (ss *stateStatistics) Cache() uint64 {
return atomic.LoadUint64(&ss.numCache)
}

// IncrSnapshotCache will increment snapshot cache counter
func (ss *stateStatistics) IncrSnapshotCache() {
atomic.AddUint64(&ss.numSnapshotCache, 1)
}

// SnapshotCache returns the number of snapshot cached operations
func (ss *stateStatistics) SnapshotCache() uint64 {
return atomic.LoadUint64(&ss.numSnapshotCache)
}

// IncrPersister will increment persister counter
func (ss *stateStatistics) IncrPersister(epoch uint32) {
ss.mutPersisters.Lock()
defer ss.mutPersisters.Unlock()

ss.numPersister[epoch]++
}

// Persister returns the number of persister operations
func (ss *stateStatistics) Persister(epoch uint32) uint64 {
ss.mutPersisters.RLock()
defer ss.mutPersisters.RUnlock()

return ss.numPersister[epoch]
}

// IncrSnapshotPersister will increment snapshot persister counter
func (ss *stateStatistics) IncrSnapshotPersister(epoch uint32) {
ss.mutPersisters.Lock()
defer ss.mutPersisters.Unlock()

ss.numSnapshotPersister[epoch]++
}

// SnapshotPersister returns the number of snapshot persister operations
func (ss *stateStatistics) SnapshotPersister(epoch uint32) uint64 {
ss.mutPersisters.RLock()
defer ss.mutPersisters.RUnlock()

return ss.numSnapshotPersister[epoch]
}

// IncrTrie will increment trie counter
func (ss *stateStatistics) IncrTrie() {
atomic.AddUint64(&ss.numTrie, 1)
}

// Trie returns the number of trie operations
func (ss *stateStatistics) Trie() uint64 {
return atomic.LoadUint64(&ss.numTrie)
}

// SnapshotStats returns collected snapshot statistics as string
func (ss *stateStatistics) SnapshotStats() []string {
stats := make([]string, 0)

stats = append(stats, fmt.Sprintf("snapshot cache op = %v", atomic.LoadUint64(&ss.numSnapshotCache)))

ss.mutPersisters.RLock()
defer ss.mutPersisters.RUnlock()

for epoch, counter := range ss.numSnapshotPersister {
stats = append(stats, fmt.Sprintf("snapshot persister epoch = %v op = %v", epoch, counter))
}

return stats
}

// ProcessingStats returns collected processing statistics as string
func (ss *stateStatistics) ProcessingStats() []string {
stats := make([]string, 0)

stats = append(stats, fmt.Sprintf("cache op = %v", atomic.LoadUint64(&ss.numCache)))

ss.mutPersisters.RLock()
defer ss.mutPersisters.RUnlock()

for epoch, counter := range ss.numPersister {
stats = append(stats, fmt.Sprintf("persister epoch = %v op = %v", epoch, counter))
}

stats = append(stats, fmt.Sprintf("trie op = %v", atomic.LoadUint64(&ss.numTrie)))

return stats
}

// IsInterfaceNil returns true if there is no value under the interface
func (ss *stateStatistics) IsInterfaceNil() bool {
return ss == nil
}

0 comments on commit e6e79c4

Please sign in to comment.