-
Notifications
You must be signed in to change notification settings - Fork 405
/
state_trackers.go
183 lines (147 loc) · 4.09 KB
/
state_trackers.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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package agent
import (
"context"
"sync"
"time"
"go.opencensus.io/stats"
)
type RequestStateType int
type ContainerStateType int
type containerState struct {
lock sync.Mutex
state ContainerStateType
start time.Time
}
type requestState struct {
lock sync.Mutex
state RequestStateType
start time.Time
}
type ContainerState interface {
UpdateState(ctx context.Context, newState ContainerStateType, slots *slotQueue)
GetState() string
}
type RequestState interface {
UpdateState(ctx context.Context, newState RequestStateType, slots *slotQueue)
}
func NewRequestState() RequestState {
return &requestState{}
}
func NewContainerState() ContainerState {
return &containerState{}
}
const (
RequestStateNone RequestStateType = iota // uninitialized
RequestStateWait // request is waiting
RequestStateExec // request is executing
RequestStateDone // request is done
RequestStateMax
)
const (
ContainerStateNone ContainerStateType = iota // uninitialized
ContainerStateWait // resource (cpu + mem) waiting
ContainerStateStart // launching
ContainerStateIdle // running: idle but not paused
ContainerStatePaused // running: idle but paused
ContainerStateBusy // running: busy
ContainerStateDone // exited/failed/done
ContainerStateMax
)
var containerStateKeys = [ContainerStateMax]string{
"none",
"wait",
"start",
"idle",
"paused",
"busy",
"done",
}
var containerGaugeKeys = [ContainerStateMax]string{
"",
"container_wait_total",
"container_start_total",
"container_idle_total",
"container_paused_total",
"container_busy_total",
}
var containerTimeKeys = [ContainerStateMax]string{
"",
"container_wait_duration_seconds",
"container_start_duration_seconds",
"container_idle_duration_seconds",
"container_paused_duration_seconds",
"container_busy_duration_seconds",
}
func (c *requestState) UpdateState(ctx context.Context, newState RequestStateType, slots *slotQueue) {
var now time.Time
var oldState RequestStateType
c.lock.Lock()
// we can only advance our state forward
if c.state < newState {
now = time.Now()
oldState = c.state
c.state = newState
c.start = now
}
c.lock.Unlock()
if now.IsZero() {
return
}
// reflect this change to slot mgr if defined (AKA hot)
if slots != nil {
slots.enterRequestState(newState)
slots.exitRequestState(oldState)
}
}
func isIdleState(state ContainerStateType) bool {
return state == ContainerStateIdle || state == ContainerStatePaused
}
func (c *containerState) GetState() string {
var res ContainerStateType
c.lock.Lock()
res = c.state
c.lock.Unlock()
return containerStateKeys[res]
}
func (c *containerState) UpdateState(ctx context.Context, newState ContainerStateType, slots *slotQueue) {
var now time.Time
var oldState ContainerStateType
var before time.Time
c.lock.Lock()
// Only the following state transitions are allowed:
// 1) any move forward in states as per ContainerStateType order
// 2) move back: from paused to idle
// 3) move back: from busy to idle/paused
if c.state < newState ||
(c.state == ContainerStatePaused && newState == ContainerStateIdle) ||
(c.state == ContainerStateBusy && isIdleState(newState)) {
now = time.Now()
oldState = c.state
before = c.start
c.state = newState
c.start = now
}
c.lock.Unlock()
if now.IsZero() {
return
}
// reflect this change to slot mgr if defined (AKA hot)
if slots != nil {
slots.enterContainerState(newState)
slots.exitContainerState(oldState)
}
// update old state stats
gaugeKey := containerGaugeKeys[oldState]
if gaugeKey != "" {
stats.Record(ctx, containerGaugeMeasures[oldState].M(-1))
}
timeKey := containerTimeKeys[oldState]
if timeKey != "" {
stats.Record(ctx, containerTimeMeasures[oldState].M(int64(now.Sub(before)/time.Millisecond)))
}
// update new state stats
gaugeKey = containerGaugeKeys[newState]
if gaugeKey != "" {
stats.Record(ctx, containerGaugeMeasures[newState].M(1))
}
}