github.com/alpe/etcd@v0.1.2-0.20130915230056-09f31af88aeb/raft_stats.go (about) 1 package main 2 3 import ( 4 "math" 5 "sync" 6 "time" 7 8 "github.com/coreos/go-raft" 9 ) 10 11 const ( 12 queueCapacity = 200 13 ) 14 15 // packageStats represent the stats we need for a package. 16 // It has sending time and the size of the package. 17 type packageStats struct { 18 sendingTime time.Time 19 size int 20 } 21 22 // NewPackageStats creates a pacakgeStats and return the pointer to it. 23 func NewPackageStats(now time.Time, size int) *packageStats { 24 return &packageStats{ 25 sendingTime: now, 26 size: size, 27 } 28 } 29 30 // Time return the sending time of the package. 31 func (ps *packageStats) Time() time.Time { 32 return ps.sendingTime 33 } 34 35 type raftServerStats struct { 36 State string `json:"state"` 37 StartTime time.Time `json:"startTime"` 38 Leader string `json:"leader"` 39 LeaderUptime string `json:"leaderUptime"` 40 41 RecvAppendRequestCnt uint64 `json:"recvAppendRequestCnt,"` 42 RecvingPkgRate float64 `json:"recvPkgRate,omitempty"` 43 RecvingBandwidthRate float64 `json:"recvBandwidthRate,omitempty"` 44 45 SendAppendRequestCnt uint64 `json:"sendAppendRequestCnt"` 46 SendingPkgRate float64 `json:"sendPkgRate,omitempty"` 47 SendingBandwidthRate float64 `json:"sendBandwidthRate,omitempty"` 48 49 leaderStartTime time.Time 50 sendRateQueue *statsQueue 51 recvRateQueue *statsQueue 52 } 53 54 func (ss *raftServerStats) RecvAppendReq(leaderName string, pkgSize int) { 55 ss.State = raft.Follower 56 if leaderName != ss.Leader { 57 ss.Leader = leaderName 58 ss.leaderStartTime = time.Now() 59 } 60 61 ss.recvRateQueue.Insert(NewPackageStats(time.Now(), pkgSize)) 62 ss.RecvAppendRequestCnt++ 63 } 64 65 func (ss *raftServerStats) SendAppendReq(pkgSize int) { 66 now := time.Now() 67 if ss.State != raft.Leader { 68 ss.State = raft.Leader 69 ss.Leader = r.Name() 70 ss.leaderStartTime = now 71 } 72 73 ss.sendRateQueue.Insert(NewPackageStats(time.Now(), pkgSize)) 74 75 ss.SendAppendRequestCnt++ 76 } 77 78 type raftPeerStats struct { 79 Latency float64 `json:"latency"` 80 AvgLatency float64 `json:"averageLatency"` 81 avgLatencySquare float64 82 SdvLatency float64 `json:"sdvLatency"` 83 MinLatency float64 `json:"minLatency"` 84 MaxLatency float64 `json:"maxLatency"` 85 FailCnt uint64 `json:"failsCount"` 86 SuccCnt uint64 `json:"successCount"` 87 } 88 89 // Succ function update the raftPeerStats with a successful send 90 func (ps *raftPeerStats) Succ(d time.Duration) { 91 total := float64(ps.SuccCnt) * ps.AvgLatency 92 totalSquare := float64(ps.SuccCnt) * ps.avgLatencySquare 93 94 ps.SuccCnt++ 95 96 ps.Latency = float64(d) / (1000000.0) 97 98 if ps.Latency > ps.MaxLatency { 99 ps.MaxLatency = ps.Latency 100 } 101 102 if ps.Latency < ps.MinLatency { 103 ps.MinLatency = ps.Latency 104 } 105 106 ps.AvgLatency = (total + ps.Latency) / float64(ps.SuccCnt) 107 ps.avgLatencySquare = (totalSquare + ps.Latency*ps.Latency) / float64(ps.SuccCnt) 108 109 // sdv = sqrt(avg(x^2) - avg(x)^2) 110 ps.SdvLatency = math.Sqrt(ps.avgLatencySquare - ps.AvgLatency*ps.AvgLatency) 111 } 112 113 // Fail function update the raftPeerStats with a unsuccessful send 114 func (ps *raftPeerStats) Fail() { 115 ps.FailCnt++ 116 } 117 118 type statsQueue struct { 119 items [queueCapacity]*packageStats 120 size int 121 front int 122 back int 123 totalPkgSize int 124 rwl sync.RWMutex 125 } 126 127 func (q *statsQueue) Len() int { 128 return q.size 129 } 130 131 func (q *statsQueue) PkgSize() int { 132 return q.totalPkgSize 133 } 134 135 // FrontAndBack gets the front and back elements in the queue 136 // We must grab front and back together with the protection of the lock 137 func (q *statsQueue) frontAndBack() (*packageStats, *packageStats) { 138 q.rwl.RLock() 139 defer q.rwl.RUnlock() 140 if q.size != 0 { 141 return q.items[q.front], q.items[q.back] 142 } 143 return nil, nil 144 } 145 146 // Insert function insert a packageStats into the queue and update the records 147 func (q *statsQueue) Insert(p *packageStats) { 148 q.rwl.Lock() 149 defer q.rwl.Unlock() 150 151 q.back = (q.back + 1) % queueCapacity 152 153 if q.size == queueCapacity { //dequeue 154 q.totalPkgSize -= q.items[q.front].size 155 q.front = (q.back + 1) % queueCapacity 156 } else { 157 q.size++ 158 } 159 160 q.items[q.back] = p 161 q.totalPkgSize += q.items[q.back].size 162 163 } 164 165 // Rate function returns the package rate and byte rate 166 func (q *statsQueue) Rate() (float64, float64) { 167 front, back := q.frontAndBack() 168 169 if front == nil || back == nil { 170 return 0, 0 171 } 172 173 if time.Now().Sub(back.Time()) > time.Second { 174 q.Clear() 175 return 0, 0 176 } 177 178 sampleDuration := back.Time().Sub(front.Time()) 179 180 pr := float64(q.Len()) / float64(sampleDuration) * float64(time.Second) 181 182 br := float64(q.PkgSize()) / float64(sampleDuration) * float64(time.Second) 183 184 return pr, br 185 } 186 187 // Clear function clear up the statsQueue 188 func (q *statsQueue) Clear() { 189 q.rwl.Lock() 190 defer q.rwl.Unlock() 191 q.back = -1 192 q.front = 0 193 q.size = 0 194 q.totalPkgSize = 0 195 }