github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/raft_stats.go (about) 1 /* 2 Copyright 2013 CoreOS Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "math" 21 "sync" 22 "time" 23 24 "github.com/coreos/go-raft" 25 ) 26 27 const ( 28 queueCapacity = 200 29 ) 30 31 // packageStats represent the stats we need for a package. 32 // It has sending time and the size of the package. 33 type packageStats struct { 34 sendingTime time.Time 35 size int 36 } 37 38 // NewPackageStats creates a pacakgeStats and return the pointer to it. 39 func NewPackageStats(now time.Time, size int) *packageStats { 40 return &packageStats{ 41 sendingTime: now, 42 size: size, 43 } 44 } 45 46 // Time return the sending time of the package. 47 func (ps *packageStats) Time() time.Time { 48 return ps.sendingTime 49 } 50 51 type raftServerStats struct { 52 State string `json:"state"` 53 StartTime time.Time `json:"startTime"` 54 55 LeaderInfo struct { 56 Name string `json:"leader"` 57 Uptime string `json:"uptime"` 58 startTime time.Time 59 } `json:"leaderInfo"` 60 61 RecvAppendRequestCnt uint64 `json:"recvAppendRequestCnt,"` 62 RecvingPkgRate float64 `json:"recvPkgRate,omitempty"` 63 RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"` 64 65 SendAppendRequestCnt uint64 `json:"sendAppendRequestCnt"` 66 SendingPkgRate float64 `json:"sendPkgRate,omitempty"` 67 SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"` 68 69 sendRateQueue *statsQueue 70 recvRateQueue *statsQueue 71 } 72 73 func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) { 74 ss.State = raft.Follower 75 if leaderName != ss.LeaderInfo.Name { 76 ss.LeaderInfo.Name = leaderName 77 ss.LeaderInfo.startTime = time.Now() 78 } 79 80 ss.recvRateQueue.Insert(NewPackageStats(time.Now(), pkgSize)) 81 ss.RecvAppendRequestCnt++ 82 } 83 84 func (ss *raftServerStats) SendAppendReq(pkgSize int) { 85 now := time.Now() 86 87 if ss.State != raft.Leader { 88 ss.State = raft.Leader 89 ss.LeaderInfo.Name = r.Name() 90 ss.LeaderInfo.startTime = now 91 } 92 93 ss.sendRateQueue.Insert(NewPackageStats(now, pkgSize)) 94 95 ss.SendAppendRequestCnt++ 96 } 97 98 type raftFollowersStats struct { 99 Leader string `json:"leader"` 100 Followers map[string]*raftFollowerStats `json:"followers"` 101 } 102 103 type raftFollowerStats struct { 104 Latency struct { 105 Current float64 `json:"current"` 106 Average float64 `json:"average"` 107 averageSquare float64 108 StandardDeviation float64 `json:"standardDeviation"` 109 Minimum float64 `json:"minimum"` 110 Maximum float64 `json:"maximum"` 111 } `json:"latency"` 112 113 Counts struct { 114 Fail uint64 `json:"fail"` 115 Success uint64 `json:"success"` 116 } `json:"counts"` 117 } 118 119 // Succ function update the raftFollowerStats with a successful send 120 func (ps *raftFollowerStats) Succ(d time.Duration) { 121 total := float64(ps.Counts.Success) * ps.Latency.Average 122 totalSquare := float64(ps.Counts.Success) * ps.Latency.averageSquare 123 124 ps.Counts.Success++ 125 126 ps.Latency.Current = float64(d) / (1000000.0) 127 128 if ps.Latency.Current > ps.Latency.Maximum { 129 ps.Latency.Maximum = ps.Latency.Current 130 } 131 132 if ps.Latency.Current < ps.Latency.Minimum { 133 ps.Latency.Minimum = ps.Latency.Current 134 } 135 136 ps.Latency.Average = (total + ps.Latency.Current) / float64(ps.Counts.Success) 137 ps.Latency.averageSquare = (totalSquare + ps.Latency.Current*ps.Latency.Current) / float64(ps.Counts.Success) 138 139 // sdv = sqrt(avg(x^2) - avg(x)^2) 140 ps.Latency.StandardDeviation = math.Sqrt(ps.Latency.averageSquare - ps.Latency.Average*ps.Latency.Average) 141 } 142 143 // Fail function update the raftFollowerStats with a unsuccessful send 144 func (ps *raftFollowerStats) Fail() { 145 ps.Counts.Fail++ 146 } 147 148 type statsQueue struct { 149 items [queueCapacity]*packageStats 150 size int 151 front int 152 back int 153 totalPkgSize int 154 rwl sync.RWMutex 155 } 156 157 func (q *statsQueue) Len() int { 158 return q.size 159 } 160 161 func (q *statsQueue) PkgSize() int { 162 return q.totalPkgSize 163 } 164 165 // FrontAndBack gets the front and back elements in the queue 166 // We must grab front and back together with the protection of the lock 167 func (q *statsQueue) frontAndBack() (*packageStats, *packageStats) { 168 q.rwl.RLock() 169 defer q.rwl.RUnlock() 170 if q.size != 0 { 171 return q.items[q.front], q.items[q.back] 172 } 173 return nil, nil 174 } 175 176 // Insert function insert a packageStats into the queue and update the records 177 func (q *statsQueue) Insert(p *packageStats) { 178 q.rwl.Lock() 179 defer q.rwl.Unlock() 180 181 q.back = (q.back + 1) % queueCapacity 182 183 if q.size == queueCapacity { //dequeue 184 q.totalPkgSize -= q.items[q.front].size 185 q.front = (q.back + 1) % queueCapacity 186 } else { 187 q.size++ 188 } 189 190 q.items[q.back] = p 191 q.totalPkgSize += q.items[q.back].size 192 193 } 194 195 // Rate function returns the package rate and byte rate 196 func (q *statsQueue) Rate() (float64, float64) { 197 front, back := q.frontAndBack() 198 199 if front == nil || back == nil { 200 return 0, 0 201 } 202 203 if time.Now().Sub(back.Time()) > time.Second { 204 q.Clear() 205 return 0, 0 206 } 207 208 sampleDuration := back.Time().Sub(front.Time()) 209 210 pr := float64(q.Len()) / float64(sampleDuration) * float64(time.Second) 211 212 br := float64(q.PkgSize()) / float64(sampleDuration) * float64(time.Second) 213 214 return pr, br 215 } 216 217 // Clear function clear up the statsQueue 218 func (q *statsQueue) Clear() { 219 q.rwl.Lock() 220 defer q.rwl.Unlock() 221 q.back = -1 222 q.front = 0 223 q.size = 0 224 q.totalPkgSize = 0 225 }