[#283] pool: Store methods status in slice

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-07-22 11:06:16 +03:00 committed by fyrchik
parent b4f4ee4f79
commit f4ac75423c
5 changed files with 106 additions and 56 deletions

View file

@ -32,7 +32,7 @@ type mockClient struct {
func newMockClient(addr string, key ecdsa.PrivateKey) *mockClient {
return &mockClient{
key: key,
clientStatusMonitor: newTestStatusMonitor(addr),
clientStatusMonitor: newClientStatusMonitor(addr, 10),
}
}

View file

@ -60,7 +60,7 @@ type clientStatus interface {
address() string
currentErrorRate() uint32
overallErrorRate() uint64
methodsStatus() map[string]methodStatus
methodsStatus() []statusSnapshot
}
type clientStatusMonitor struct {
@ -71,33 +71,106 @@ type clientStatusMonitor struct {
mu sync.RWMutex // protect counters
currentErrorCount uint32
overallErrorCount uint64
methods map[string]methodStatus
methods []*methodStatus
}
type methodStatus struct {
name string
name string
mu sync.RWMutex // protect counters
statusSnapshot
}
type statusSnapshot struct {
allTime uint64
allRequests uint64
}
// MethodIndex index of method in list of statuses in clientStatusMonitor.
type MethodIndex int
const (
methodBalanceGet = "balanceGet"
methodContainerPut = "containerPut"
methodContainerGet = "containerGet"
methodContainerList = "containerList"
methodContainerDelete = "containerDelete"
methodContainerEACL = "containerEACL"
methodContainerSetEACL = "containerSetEACL"
methodEndpointInfo = "endpointInfo"
methodNetworkInfo = "networkInfo"
methodObjectPut = "objectPut"
methodObjectDelete = "objectDelete"
methodObjectGet = "objectGet"
methodObjectHead = "objectHead"
methodObjectRange = "objectRange"
methodSessionCreate = "sessionCreate"
methodBalanceGet MethodIndex = iota
methodContainerPut
methodContainerGet
methodContainerList
methodContainerDelete
methodContainerEACL
methodContainerSetEACL
methodEndpointInfo
methodNetworkInfo
methodObjectPut
methodObjectDelete
methodObjectGet
methodObjectHead
methodObjectRange
methodSessionCreate
)
// String implements fmt.Stringer.
func (m MethodIndex) String() string {
switch m {
case methodBalanceGet:
return "balanceGet"
case methodContainerPut:
return "containerPut"
case methodContainerGet:
return "containerGet"
case methodContainerList:
return "containerList"
case methodContainerDelete:
return "containerDelete"
case methodContainerEACL:
return "containerEACL"
case methodContainerSetEACL:
return "containerSetEACL"
case methodEndpointInfo:
return "endpointInfo"
case methodNetworkInfo:
return "networkInfo"
case methodObjectPut:
return "objectPut"
case methodObjectDelete:
return "objectDelete"
case methodObjectGet:
return "objectGet"
case methodObjectHead:
return "objectHead"
case methodObjectRange:
return "objectRange"
case methodSessionCreate:
return "sessionCreate"
default:
return "unknown"
}
}
func newClientStatusMonitor(addr string, errorThreshold uint32) clientStatusMonitor {
methods := make([]*methodStatus, methodSessionCreate+1)
for i := methodBalanceGet; i <= methodSessionCreate; i++ {
methods[i] = &methodStatus{name: i.String()}
}
return clientStatusMonitor{
addr: addr,
healthy: atomic.NewBool(true),
errorThreshold: errorThreshold,
methods: methods,
}
}
func (m *methodStatus) snapshot() statusSnapshot {
m.mu.RLock()
defer m.mu.RUnlock()
return m.statusSnapshot
}
func (m *methodStatus) incRequests(elapsed time.Duration) {
m.mu.Lock()
defer m.mu.Unlock()
m.allTime += uint64(elapsed)
m.allRequests++
}
// clientWrapper is used by default, alternative implementations are intended for testing purposes only.
type clientWrapper struct {
client sdkClient.Client
@ -139,12 +212,8 @@ func newWrapper(prm wrapperPrm) (*clientWrapper, error) {
prmInit.SetResponseInfoCallback(prm.responseInfoCallback)
res := &clientWrapper{
key: prm.key,
clientStatusMonitor: clientStatusMonitor{
addr: prm.address,
healthy: atomic.NewBool(true),
errorThreshold: prm.errorThreshold,
},
key: prm.key,
clientStatusMonitor: newClientStatusMonitor(prm.address, prm.errorThreshold),
}
res.client.Init(prmInit)
@ -656,28 +725,18 @@ func (c *clientStatusMonitor) overallErrorRate() uint64 {
return c.overallErrorCount
}
func (c *clientStatusMonitor) methodsStatus() map[string]methodStatus {
c.mu.RLock()
defer c.mu.RUnlock()
result := make(map[string]methodStatus)
for key, val := range c.methods {
result[key] = val
func (c *clientStatusMonitor) methodsStatus() []statusSnapshot {
result := make([]statusSnapshot, len(c.methods))
for i, val := range c.methods {
result[i] = val.snapshot()
}
return result
}
func (c *clientStatusMonitor) incRequests(elapsed time.Duration, method string) {
c.mu.Lock()
defer c.mu.Unlock()
methodStat, ok := c.methods[method]
if !ok {
methodStat.name = method
}
methodStat.allTime += uint64(elapsed)
methodStat.allRequests++
c.methods[method] = methodStat
func (c *clientStatusMonitor) incRequests(elapsed time.Duration, method MethodIndex) {
methodStat := c.methods[method]
methodStat.incRequests(elapsed)
}
func (c *clientStatusMonitor) handleError(st apistatus.Status, err error) error {

View file

@ -17,7 +17,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/user"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
"go.uber.org/zap"
)
@ -508,16 +507,8 @@ func TestWaitPresence(t *testing.T) {
})
}
func newTestStatusMonitor(addr string) clientStatusMonitor {
return clientStatusMonitor{
addr: addr,
healthy: atomic.NewBool(true),
errorThreshold: 10,
}
}
func TestStatusMonitor(t *testing.T) {
monitor := newTestStatusMonitor("")
monitor := newClientStatusMonitor("", 10)
monitor.errorThreshold = 3
count := 10
@ -530,7 +521,7 @@ func TestStatusMonitor(t *testing.T) {
}
func TestHandleError(t *testing.T) {
monitor := newTestStatusMonitor("")
monitor := newClientStatusMonitor("", 10)
for i, tc := range []struct {
status apistatus.Status

View file

@ -63,7 +63,7 @@ func newNetmapMock(name string, needErr bool) *clientMock {
}
return &clientMock{
clientWrapper: clientWrapper{
clientStatusMonitor: newTestStatusMonitor(""),
clientStatusMonitor: newClientStatusMonitor("", 10),
},
name: name,
err: err,

View file

@ -39,7 +39,7 @@ func (s Statistic) Node(address string) (*NodeStatistic, error) {
// NodeStatistic is metrics of certain connections.
type NodeStatistic struct {
address string
methods map[string]methodStatus
methods []statusSnapshot
overallErrors uint64
currentErrors uint32
}
@ -144,7 +144,7 @@ func (n NodeStatistic) AverageCreateSession() time.Duration {
return n.averageTime(methodSessionCreate)
}
func (n NodeStatistic) averageTime(method string) time.Duration {
func (n NodeStatistic) averageTime(method MethodIndex) time.Duration {
stat := n.methods[method]
if stat.allRequests == 0 {
return 0