leader.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package stats
  14. import (
  15. "encoding/json"
  16. "log"
  17. "math"
  18. "sync"
  19. "time"
  20. )
  21. // LeaderStats is used by the leader in an etcd cluster, and encapsulates
  22. // statistics about communication with its followers
  23. type LeaderStats struct {
  24. // TODO(jonboulle): clarify that these are IDs, not names
  25. Leader string `json:"leader"`
  26. Followers map[string]*FollowerStats `json:"followers"`
  27. sync.Mutex
  28. }
  29. // NewLeaderStats generates a new LeaderStats with the given id as leader
  30. func NewLeaderStats(id string) *LeaderStats {
  31. return &LeaderStats{
  32. Leader: id,
  33. Followers: make(map[string]*FollowerStats),
  34. }
  35. }
  36. func (ls *LeaderStats) JSON() []byte {
  37. ls.Lock()
  38. stats := *ls
  39. ls.Unlock()
  40. b, err := json.Marshal(stats)
  41. // TODO(jonboulle): appropriate error handling?
  42. if err != nil {
  43. log.Printf("stats: error marshalling leader stats: %v", err)
  44. }
  45. return b
  46. }
  47. func (ls *LeaderStats) Follower(name string) *FollowerStats {
  48. ls.Lock()
  49. defer ls.Unlock()
  50. fs, ok := ls.Followers[name]
  51. if !ok {
  52. fs = &FollowerStats{}
  53. fs.Latency.Minimum = 1 << 63
  54. ls.Followers[name] = fs
  55. }
  56. return fs
  57. }
  58. // FollowerStats encapsulates various statistics about a follower in an etcd cluster
  59. type FollowerStats struct {
  60. Latency struct {
  61. Current float64 `json:"current"`
  62. Average float64 `json:"average"`
  63. averageSquare float64
  64. StandardDeviation float64 `json:"standardDeviation"`
  65. Minimum float64 `json:"minimum"`
  66. Maximum float64 `json:"maximum"`
  67. } `json:"latency"`
  68. Counts struct {
  69. Fail uint64 `json:"fail"`
  70. Success uint64 `json:"success"`
  71. } `json:"counts"`
  72. sync.Mutex
  73. }
  74. // Succ updates the FollowerStats with a successful send
  75. func (fs *FollowerStats) Succ(d time.Duration) {
  76. fs.Lock()
  77. defer fs.Unlock()
  78. total := float64(fs.Counts.Success) * fs.Latency.Average
  79. totalSquare := float64(fs.Counts.Success) * fs.Latency.averageSquare
  80. fs.Counts.Success++
  81. fs.Latency.Current = float64(d) / (1000000.0)
  82. if fs.Latency.Current > fs.Latency.Maximum {
  83. fs.Latency.Maximum = fs.Latency.Current
  84. }
  85. if fs.Latency.Current < fs.Latency.Minimum {
  86. fs.Latency.Minimum = fs.Latency.Current
  87. }
  88. fs.Latency.Average = (total + fs.Latency.Current) / float64(fs.Counts.Success)
  89. fs.Latency.averageSquare = (totalSquare + fs.Latency.Current*fs.Latency.Current) / float64(fs.Counts.Success)
  90. // sdv = sqrt(avg(x^2) - avg(x)^2)
  91. fs.Latency.StandardDeviation = math.Sqrt(fs.Latency.averageSquare - fs.Latency.Average*fs.Latency.Average)
  92. }
  93. // Fail updates the FollowerStats with an unsuccessful send
  94. func (fs *FollowerStats) Fail() {
  95. fs.Lock()
  96. defer fs.Unlock()
  97. fs.Counts.Fail++
  98. }