forked from storj/utp-go
-
Notifications
You must be signed in to change notification settings - Fork 2
/
utp_statedebug.go
169 lines (155 loc) · 5.89 KB
/
utp_statedebug.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
// Copyright (c) 2021 Storj Labs, Inc.
// See LICENSE for copying information.
//go:build utpstatedebug
// +build utpstatedebug
package utp
import "fmt"
// ReadSideState represents the possible read-side states that a conn can be in.
type ReadSideState int
const (
ReadConnecting ReadSideState = iota // connecting
ReadIdleConn // nothing to do but wait
ReadHasReadData // have some data from remote waiting on user to read it
ReadIdleClosing // closed on local side, waiting for ack from remote
ReadAwaitingData // user wants to read data, but no data available yet
ReadAwaitingAccept // some data is available for a pending read call, but it hasn't accepted the data yet
ReadDrainingReads // have some unread data from remote, also closed by remote
ReadDrainingAwaitingAccept // have some unread data from remote, also closed by remote, also there is a pending read call that hasn't accepted its data yet
ReadClosedByPeer // closed on remote side, waiting for close on local
ReadClosed // all shut down and done
)
// WriteSideState represents the possible write-side states that a Conn can be in.
type WriteSideState int
const (
WriteConnecting WriteSideState = iota // connecting
WriteIdleConn // nothing to do but wait
WriteCallPending // a write call has been made but the data is not queued yet
WriteHasWriteData // there is some data in the write queue for sending
WriteDataAndPending // there is data in the write queue and a pending write call wants to add more
WriteIdleClosing // closed on local side, waiting for ack from remote
WriteClosedByPeer // closed on remote side, waiting for close on local
WriteDrainingWrites // closed on local side, but we have some data to be sent first
WriteClosed // all shut down and done
)
func (st ReadSideState) String() string {
switch st {
case ReadConnecting:
return "READ-CONNECTING"
case ReadIdleConn:
return "READ-IDLE"
case ReadHasReadData:
return "READ-HAS-READ-DATA"
case ReadIdleClosing:
return "READ-IDLE-CLOSING"
case ReadAwaitingData:
return "READ-AWAITING-DATA"
case ReadAwaitingAccept:
return "READ-AWAITING-ACCEPT"
case ReadDrainingReads:
return "READ-DRAINING-READS"
case ReadDrainingAwaitingAccept:
return "READ-DRAINING-AWAITING-ACCEPT"
case ReadClosedByPeer:
return "READ-CLOSED-BY-PEER"
case ReadClosed:
return "READ-CLOSED"
}
return fmt.Sprintf("UNKNOWN READ STATE %d", st)
}
func (st WriteSideState) String() string {
switch st {
case WriteConnecting:
return "WRITE-CONNECTING"
case WriteCallPending:
return "WRITE-CALL-PENDING"
case WriteIdleConn:
return "WRITE-IDLE"
case WriteHasWriteData:
return "WRITE-HAS-WRITE-DATA"
case WriteDataAndPending:
return "WRITE-DATA-AND-PENDING"
case WriteIdleClosing:
return "WRITE-IDLE-CLOSING"
case WriteClosedByPeer:
return "WRITE-CLOSED-BY-PEER"
case WriteDrainingWrites:
return "WRITE-DRAINING-WRITES"
case WriteClosed:
return "WRITE-CLOSED"
}
return fmt.Sprintf("UNKNOWN WRITE STATE %d", st)
}
func (c *Conn) getReadStatus() ReadSideState {
readBufferEmpty := (c.readBuffer.SpaceUsed() == 0)
switch {
case c.connecting:
return ReadConnecting
case c.willClose && c.remoteIsDone:
return ReadClosed
case c.willClose:
return ReadIdleClosing
case !c.readPending && readBufferEmpty && !c.remoteIsDone:
return ReadIdleConn
case !c.readPending && !readBufferEmpty && !c.remoteIsDone:
return ReadHasReadData
case c.readPending && readBufferEmpty && !c.remoteIsDone:
return ReadAwaitingData
case c.readPending && !readBufferEmpty && !c.remoteIsDone:
return ReadAwaitingAccept
case !c.readPending && readBufferEmpty && c.remoteIsDone:
return ReadClosedByPeer
case !c.readPending && !readBufferEmpty && c.remoteIsDone:
return ReadDrainingReads
case c.readPending && !readBufferEmpty && c.remoteIsDone:
return ReadDrainingAwaitingAccept
}
c.logger.Error(nil, "unexpected read state",
"connecting", c.connecting,
"willClose", c.willClose,
"remoteIsDone", c.remoteIsDone,
"readPending", c.readPending,
"readBufferEmpty", readBufferEmpty)
return ReadSideState(-1)
}
func (c *Conn) getWriteStatus() WriteSideState {
writeBufferEmpty := (c.writeBuffer.SpaceUsed() == 0)
switch {
case c.connecting:
return WriteConnecting
case c.remoteIsDone && c.willClose:
return WriteClosed
case c.remoteIsDone && !c.willClose:
return WriteClosedByPeer
case c.willClose && !c.writePending && !writeBufferEmpty:
return WriteDrainingWrites
case c.willClose && !c.writePending && writeBufferEmpty:
return WriteIdleClosing
case !c.willClose && c.writePending && writeBufferEmpty:
return WriteCallPending
case !c.willClose && c.writePending && !writeBufferEmpty:
return WriteDataAndPending
case !c.willClose && !c.writePending && writeBufferEmpty:
return WriteIdleConn
case !c.willClose && !c.writePending && !writeBufferEmpty:
return WriteHasWriteData
}
c.logger.Error(nil, "unexpected write state",
"connecting", c.connecting,
"willClose", c.willClose,
"remoteIsDone", c.remoteIsDone,
"writePending", c.writePending,
"writeBufferEmpty", writeBufferEmpty)
return WriteSideState(-1)
}
func (c *Conn) stateDebugLog(msg string, keys ...interface{}) {
c.stateLock.Lock()
defer c.stateLock.Unlock()
c.stateDebugLogLocked(msg, keys...)
}
func (c *Conn) stateDebugLogLocked(msg string, keys ...interface{}) {
logger := c.logger.V(10)
if logger.Enabled() {
keys = append(keys, "read-status", c.getReadStatus(), "write-status", c.getWriteStatus())
logger.Info(msg, keys...)
}
}