blob: d883eb3de9a0f7c1d0579705b2e471ba1e7f6ccb [file] [log] [blame]
Abhay Kumara2ae5992025-11-10 14:02:24 +00001// 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 last seen time of event.
31 records map[uint64]time.Time
32}
33
34// NewTimeoutDetector creates the TimeoutDetector.
35func NewTimeoutDetector(maxDuration time.Duration) *TimeoutDetector {
36 return &TimeoutDetector{
37 maxDuration: maxDuration,
38 records: make(map[uint64]time.Time),
39 }
40}
41
42// Reset resets the TimeoutDetector.
43func (td *TimeoutDetector) Reset() {
44 td.mu.Lock()
45 defer td.mu.Unlock()
46
47 td.records = make(map[uint64]time.Time)
48}
49
50// Observe observes an event of given id. It computes
51// the time elapsed between successive events of given id.
52// It returns whether this time elapsed exceeds the expectation,
53// and the amount by which it exceeds the expectation.
54func (td *TimeoutDetector) Observe(id uint64) (bool, time.Duration) {
55 td.mu.Lock()
56 defer td.mu.Unlock()
57
58 ok := true
59 now := time.Now()
60 exceed := time.Duration(0)
61
62 if pt, found := td.records[id]; found {
63 exceed = now.Sub(pt) - td.maxDuration
64 if exceed > 0 {
65 ok = false
66 }
67 }
68 td.records[id] = now
69 return ok, exceed
70}