blob: 26ce9a2f3473cfa6c91a3b1cbb70d7a0401d3785 [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001// Copyright 2016 The etcd Authors
2//
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//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package contention
16
17import (
18 "sync"
19 "time"
20)
21
22// TimeoutDetector detects routine starvations by
23// observing the actual time duration to finish an action
24// or between two events that should happen in a fixed
25// interval. If the observed duration is longer than
26// the expectation, the detector will report the result.
27type TimeoutDetector struct {
28 mu sync.Mutex // protects all
29 maxDuration time.Duration
30 // map from event to time
31 // time is the last seen time of the event.
32 records map[uint64]time.Time
33}
34
35// NewTimeoutDetector creates the TimeoutDetector.
36func NewTimeoutDetector(maxDuration time.Duration) *TimeoutDetector {
37 return &TimeoutDetector{
38 maxDuration: maxDuration,
39 records: make(map[uint64]time.Time),
40 }
41}
42
43// Reset resets the NewTimeoutDetector.
44func (td *TimeoutDetector) Reset() {
45 td.mu.Lock()
46 defer td.mu.Unlock()
47
48 td.records = make(map[uint64]time.Time)
49}
50
51// Observe observes an event for given id. It returns false and exceeded duration
52// if the interval is longer than the expectation.
53func (td *TimeoutDetector) Observe(which uint64) (bool, time.Duration) {
54 td.mu.Lock()
55 defer td.mu.Unlock()
56
57 ok := true
58 now := time.Now()
59 exceed := time.Duration(0)
60
61 if pt, found := td.records[which]; found {
62 exceed = now.Sub(pt) - td.maxDuration
63 if exceed > 0 {
64 ok = false
65 }
66 }
67 td.records[which] = now
68 return ok, exceed
69}