github.com/soulinfo/etcd@v0.1.2-0.20130922053317-3a0a8c89e859/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  }