-
Notifications
You must be signed in to change notification settings - Fork 1
/
atomic-max-duration.go
75 lines (59 loc) · 2.12 KB
/
atomic-max-duration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
© 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
ISC License
*/
package parl
import (
"time"
"github.com/haraldrudell/parl/perrors"
)
// AtomicMaxDuration calculates durations maintaining max duration value
// - Thread-Safe but designed for single thread
// - for re-entrant timer, use SlowDetector
type AtomicMaxDuration struct {
t0Reference AtomicReference[time.Time]
dMax AtomicMax[time.Duration]
}
// Start returns the effective start time for a new timing cycle
// - value is optional start time, default time.Now()
func (ad *AtomicMaxDuration) Start(value ...time.Time) (tStart time.Time) {
// deteremine tStart and store in atomic reference
var previousReference *time.Time
if tStart, previousReference = ad.do(false, value...); previousReference != nil {
panic(perrors.ErrorfPF("two Start without Stop: %s", (*previousReference).Format(Rfc3339ns)))
}
return
}
// Stop returns the duration of a timing cycle
func (ad *AtomicMaxDuration) Stop(value ...time.Time) (duration time.Duration, isNewMax bool) {
// determine tStop, retrieve atomic reference abnd calculate duration
if tStop, previousReference := ad.do(true, value...); previousReference == nil {
panic(perrors.ErrorfPF("Stop without Start: %s", tStop.Format(Rfc3339ns)))
} else {
duration = tStop.Sub(*previousReference)
}
// calculate maximum duration
isNewMax = ad.dMax.Value(duration)
return
}
// Stop returns the duration of a timing cycle
func (ad *AtomicMaxDuration) Max() (max time.Duration, hasValue bool) {
max, hasValue = ad.dMax.Max()
return
}
// do returns the previous reference and the active time for a Start or Stop operation
func (ad *AtomicMaxDuration) do(isStop bool, value ...time.Time) (activeTime time.Time, previousReference *time.Time) {
// get time value for this operation
if len(value) > 0 {
activeTime = value[0]
} else {
activeTime = time.Now()
}
// do reference swap
var newReference *time.Time
if !isStop {
newReference = &activeTime // start time to store for Start operation
}
previousReference = ad.t0Reference.Put(newReference)
return
}