| package probing |
| |
| import ( |
| "sync" |
| "time" |
| ) |
| |
| var ( |
| // weight factor |
| α = 0.125 |
| ) |
| |
| type Status interface { |
| Total() int64 |
| Loss() int64 |
| Health() bool |
| Err() error |
| // Estimated smoothed round trip time |
| SRTT() time.Duration |
| // Estimated clock difference |
| ClockDiff() time.Duration |
| StopNotify() <-chan struct{} |
| } |
| |
| type status struct { |
| mu sync.Mutex |
| srtt time.Duration |
| total int64 |
| loss int64 |
| health bool |
| err error |
| clockdiff time.Duration |
| stopC chan struct{} |
| } |
| |
| // SRTT = (1-α) * SRTT + α * RTT |
| func (s *status) SRTT() time.Duration { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.srtt |
| } |
| |
| func (s *status) Total() int64 { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.total |
| } |
| |
| func (s *status) Loss() int64 { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.loss |
| } |
| |
| func (s *status) Health() bool { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.health |
| } |
| |
| func (s *status) Err() error { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.err |
| } |
| |
| func (s *status) ClockDiff() time.Duration { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| return s.clockdiff |
| } |
| |
| func (s *status) StopNotify() <-chan struct{} { |
| return s.stopC |
| } |
| |
| func (s *status) record(rtt time.Duration, when time.Time) { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| |
| s.total += 1 |
| s.health = true |
| s.srtt = time.Duration((1-α)*float64(s.srtt) + α*float64(rtt)) |
| s.clockdiff = time.Now().Sub(when) - s.srtt/2 |
| s.err = nil |
| } |
| |
| func (s *status) recordFailure(err error) { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| |
| s.total++ |
| s.health = false |
| s.loss += 1 |
| s.err = err |
| } |
| |
| func (s *status) reset() { |
| s.mu.Lock() |
| defer s.mu.Unlock() |
| |
| s.srtt = 0 |
| s.total = 0 |
| s.loss = 0 |
| s.health = false |
| s.clockdiff = 0 |
| s.err = nil |
| } |