blob: 8f6a54ff751ac678fbb110d873887b7ea322b02f [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package stats
16
17import (
18 "encoding/json"
19 "math"
20 "sync"
21 "time"
22)
23
24// LeaderStats is used by the leader in an etcd cluster, and encapsulates
25// statistics about communication with its followers
26type LeaderStats struct {
27 leaderStats
28 sync.Mutex
29}
30
31type leaderStats struct {
32 // Leader is the ID of the leader in the etcd cluster.
33 // TODO(jonboulle): clarify that these are IDs, not names
34 Leader string `json:"leader"`
35 Followers map[string]*FollowerStats `json:"followers"`
36}
37
38// NewLeaderStats generates a new LeaderStats with the given id as leader
39func NewLeaderStats(id string) *LeaderStats {
40 return &LeaderStats{
41 leaderStats: leaderStats{
42 Leader: id,
43 Followers: make(map[string]*FollowerStats),
44 },
45 }
46}
47
48func (ls *LeaderStats) JSON() []byte {
49 ls.Lock()
50 stats := ls.leaderStats
51 ls.Unlock()
52 b, err := json.Marshal(stats)
53 // TODO(jonboulle): appropriate error handling?
54 if err != nil {
55 plog.Errorf("error marshalling leader stats (%v)", err)
56 }
57 return b
58}
59
60func (ls *LeaderStats) Follower(name string) *FollowerStats {
61 ls.Lock()
62 defer ls.Unlock()
63 fs, ok := ls.Followers[name]
64 if !ok {
65 fs = &FollowerStats{}
66 fs.Latency.Minimum = 1 << 63
67 ls.Followers[name] = fs
68 }
69 return fs
70}
71
72// FollowerStats encapsulates various statistics about a follower in an etcd cluster
73type FollowerStats struct {
74 Latency LatencyStats `json:"latency"`
75 Counts CountsStats `json:"counts"`
76
77 sync.Mutex
78}
79
80// LatencyStats encapsulates latency statistics.
81type LatencyStats struct {
82 Current float64 `json:"current"`
83 Average float64 `json:"average"`
84 averageSquare float64
85 StandardDeviation float64 `json:"standardDeviation"`
86 Minimum float64 `json:"minimum"`
87 Maximum float64 `json:"maximum"`
88}
89
90// CountsStats encapsulates raft statistics.
91type CountsStats struct {
92 Fail uint64 `json:"fail"`
93 Success uint64 `json:"success"`
94}
95
96// Succ updates the FollowerStats with a successful send
97func (fs *FollowerStats) Succ(d time.Duration) {
98 fs.Lock()
99 defer fs.Unlock()
100
101 total := float64(fs.Counts.Success) * fs.Latency.Average
102 totalSquare := float64(fs.Counts.Success) * fs.Latency.averageSquare
103
104 fs.Counts.Success++
105
106 fs.Latency.Current = float64(d) / (1000000.0)
107
108 if fs.Latency.Current > fs.Latency.Maximum {
109 fs.Latency.Maximum = fs.Latency.Current
110 }
111
112 if fs.Latency.Current < fs.Latency.Minimum {
113 fs.Latency.Minimum = fs.Latency.Current
114 }
115
116 fs.Latency.Average = (total + fs.Latency.Current) / float64(fs.Counts.Success)
117 fs.Latency.averageSquare = (totalSquare + fs.Latency.Current*fs.Latency.Current) / float64(fs.Counts.Success)
118
119 // sdv = sqrt(avg(x^2) - avg(x)^2)
120 fs.Latency.StandardDeviation = math.Sqrt(fs.Latency.averageSquare - fs.Latency.Average*fs.Latency.Average)
121}
122
123// Fail updates the FollowerStats with an unsuccessful send
124func (fs *FollowerStats) Fail() {
125 fs.Lock()
126 defer fs.Unlock()
127 fs.Counts.Fail++
128}