blob: 153d75340e419cca4093b5c90f0af5d4fb045cf4 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package channelz
20
21import (
22 "net"
23 "time"
24
25 "google.golang.org/grpc/connectivity"
26 "google.golang.org/grpc/grpclog"
27)
28
29// entry represents a node in the channelz database.
30type entry interface {
31 // addChild adds a child e, whose channelz id is id to child list
32 addChild(id int64, e entry)
33 // deleteChild deletes a child with channelz id to be id from child list
34 deleteChild(id int64)
35 // triggerDelete tries to delete self from channelz database. However, if child
36 // list is not empty, then deletion from the database is on hold until the last
37 // child is deleted from database.
38 triggerDelete()
39 // deleteSelfIfReady check whether triggerDelete() has been called before, and whether child
40 // list is now empty. If both conditions are met, then delete self from database.
41 deleteSelfIfReady()
42}
43
44// dummyEntry is a fake entry to handle entry not found case.
45type dummyEntry struct {
46 idNotFound int64
47}
48
49func (d *dummyEntry) addChild(id int64, e entry) {
50 // Note: It is possible for a normal program to reach here under race condition.
51 // For example, there could be a race between ClientConn.Close() info being propagated
52 // to addrConn and http2Client. ClientConn.Close() cancel the context and result
53 // in http2Client to error. The error info is then caught by transport monitor
54 // and before addrConn.tearDown() is called in side ClientConn.Close(). Therefore,
55 // the addrConn will create a new transport. And when registering the new transport in
56 // channelz, its parent addrConn could have already been torn down and deleted
57 // from channelz tracking, and thus reach the code here.
58 grpclog.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", e, id, d.idNotFound)
59}
60
61func (d *dummyEntry) deleteChild(id int64) {
62 // It is possible for a normal program to reach here under race condition.
63 // Refer to the example described in addChild().
64 grpclog.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", id, d.idNotFound)
65}
66
67func (d *dummyEntry) triggerDelete() {
68 grpclog.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", d.idNotFound)
69}
70
71func (*dummyEntry) deleteSelfIfReady() {
72 // code should not reach here. deleteSelfIfReady is always called on an existing entry.
73}
74
75// ChannelMetric defines the info channelz provides for a specific Channel, which
76// includes ChannelInternalMetric and channelz-specific data, such as channelz id,
77// child list, etc.
78type ChannelMetric struct {
79 // ID is the channelz id of this channel.
80 ID int64
81 // RefName is the human readable reference string of this channel.
82 RefName string
83 // ChannelData contains channel internal metric reported by the channel through
84 // ChannelzMetric().
85 ChannelData *ChannelInternalMetric
86 // NestedChans tracks the nested channel type children of this channel in the format of
87 // a map from nested channel channelz id to corresponding reference string.
88 NestedChans map[int64]string
89 // SubChans tracks the subchannel type children of this channel in the format of a
90 // map from subchannel channelz id to corresponding reference string.
91 SubChans map[int64]string
92 // Sockets tracks the socket type children of this channel in the format of a map
93 // from socket channelz id to corresponding reference string.
94 // Note current grpc implementation doesn't allow channel having sockets directly,
95 // therefore, this is field is unused.
96 Sockets map[int64]string
97}
98
99// SubChannelMetric defines the info channelz provides for a specific SubChannel,
100// which includes ChannelInternalMetric and channelz-specific data, such as
101// channelz id, child list, etc.
102type SubChannelMetric struct {
103 // ID is the channelz id of this subchannel.
104 ID int64
105 // RefName is the human readable reference string of this subchannel.
106 RefName string
107 // ChannelData contains subchannel internal metric reported by the subchannel
108 // through ChannelzMetric().
109 ChannelData *ChannelInternalMetric
110 // NestedChans tracks the nested channel type children of this subchannel in the format of
111 // a map from nested channel channelz id to corresponding reference string.
112 // Note current grpc implementation doesn't allow subchannel to have nested channels
113 // as children, therefore, this field is unused.
114 NestedChans map[int64]string
115 // SubChans tracks the subchannel type children of this subchannel in the format of a
116 // map from subchannel channelz id to corresponding reference string.
117 // Note current grpc implementation doesn't allow subchannel to have subchannels
118 // as children, therefore, this field is unused.
119 SubChans map[int64]string
120 // Sockets tracks the socket type children of this subchannel in the format of a map
121 // from socket channelz id to corresponding reference string.
122 Sockets map[int64]string
123}
124
125// ChannelInternalMetric defines the struct that the implementor of Channel interface
126// should return from ChannelzMetric().
127type ChannelInternalMetric struct {
128 // current connectivity state of the channel.
129 State connectivity.State
130 // The target this channel originally tried to connect to. May be absent
131 Target string
132 // The number of calls started on the channel.
133 CallsStarted int64
134 // The number of calls that have completed with an OK status.
135 CallsSucceeded int64
136 // The number of calls that have a completed with a non-OK status.
137 CallsFailed int64
138 // The last time a call was started on the channel.
139 LastCallStartedTimestamp time.Time
140 //TODO: trace
141}
142
143// Channel is the interface that should be satisfied in order to be tracked by
144// channelz as Channel or SubChannel.
145type Channel interface {
146 ChannelzMetric() *ChannelInternalMetric
147}
148
149type channel struct {
150 refName string
151 c Channel
152 closeCalled bool
153 nestedChans map[int64]string
154 subChans map[int64]string
155 id int64
156 pid int64
157 cm *channelMap
158}
159
160func (c *channel) addChild(id int64, e entry) {
161 switch v := e.(type) {
162 case *subChannel:
163 c.subChans[id] = v.refName
164 case *channel:
165 c.nestedChans[id] = v.refName
166 default:
167 grpclog.Errorf("cannot add a child (id = %d) of type %T to a channel", id, e)
168 }
169}
170
171func (c *channel) deleteChild(id int64) {
172 delete(c.subChans, id)
173 delete(c.nestedChans, id)
174 c.deleteSelfIfReady()
175}
176
177func (c *channel) triggerDelete() {
178 c.closeCalled = true
179 c.deleteSelfIfReady()
180}
181
182func (c *channel) deleteSelfIfReady() {
183 if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 {
184 return
185 }
186 c.cm.deleteEntry(c.id)
187 // not top channel
188 if c.pid != 0 {
189 c.cm.findEntry(c.pid).deleteChild(c.id)
190 }
191}
192
193type subChannel struct {
194 refName string
195 c Channel
196 closeCalled bool
197 sockets map[int64]string
198 id int64
199 pid int64
200 cm *channelMap
201}
202
203func (sc *subChannel) addChild(id int64, e entry) {
204 if v, ok := e.(*normalSocket); ok {
205 sc.sockets[id] = v.refName
206 } else {
207 grpclog.Errorf("cannot add a child (id = %d) of type %T to a subChannel", id, e)
208 }
209}
210
211func (sc *subChannel) deleteChild(id int64) {
212 delete(sc.sockets, id)
213 sc.deleteSelfIfReady()
214}
215
216func (sc *subChannel) triggerDelete() {
217 sc.closeCalled = true
218 sc.deleteSelfIfReady()
219}
220
221func (sc *subChannel) deleteSelfIfReady() {
222 if !sc.closeCalled || len(sc.sockets) != 0 {
223 return
224 }
225 sc.cm.deleteEntry(sc.id)
226 sc.cm.findEntry(sc.pid).deleteChild(sc.id)
227}
228
229// SocketMetric defines the info channelz provides for a specific Socket, which
230// includes SocketInternalMetric and channelz-specific data, such as channelz id, etc.
231type SocketMetric struct {
232 // ID is the channelz id of this socket.
233 ID int64
234 // RefName is the human readable reference string of this socket.
235 RefName string
236 // SocketData contains socket internal metric reported by the socket through
237 // ChannelzMetric().
238 SocketData *SocketInternalMetric
239}
240
241// SocketInternalMetric defines the struct that the implementor of Socket interface
242// should return from ChannelzMetric().
243type SocketInternalMetric struct {
244 // The number of streams that have been started.
245 StreamsStarted int64
246 // The number of streams that have ended successfully:
247 // On client side, receiving frame with eos bit set.
248 // On server side, sending frame with eos bit set.
249 StreamsSucceeded int64
250 // The number of streams that have ended unsuccessfully:
251 // On client side, termination without receiving frame with eos bit set.
252 // On server side, termination without sending frame with eos bit set.
253 StreamsFailed int64
254 // The number of messages successfully sent on this socket.
255 MessagesSent int64
256 MessagesReceived int64
257 // The number of keep alives sent. This is typically implemented with HTTP/2
258 // ping messages.
259 KeepAlivesSent int64
260 // The last time a stream was created by this endpoint. Usually unset for
261 // servers.
262 LastLocalStreamCreatedTimestamp time.Time
263 // The last time a stream was created by the remote endpoint. Usually unset
264 // for clients.
265 LastRemoteStreamCreatedTimestamp time.Time
266 // The last time a message was sent by this endpoint.
267 LastMessageSentTimestamp time.Time
268 // The last time a message was received by this endpoint.
269 LastMessageReceivedTimestamp time.Time
270 // The amount of window, granted to the local endpoint by the remote endpoint.
271 // This may be slightly out of date due to network latency. This does NOT
272 // include stream level or TCP level flow control info.
273 LocalFlowControlWindow int64
274 // The amount of window, granted to the remote endpoint by the local endpoint.
275 // This may be slightly out of date due to network latency. This does NOT
276 // include stream level or TCP level flow control info.
277 RemoteFlowControlWindow int64
278 // The locally bound address.
279 LocalAddr net.Addr
280 // The remote bound address. May be absent.
281 RemoteAddr net.Addr
282 // Optional, represents the name of the remote endpoint, if different than
283 // the original target name.
284 RemoteName string
285 //TODO: socket options
286 //TODO: Security
287}
288
289// Socket is the interface that should be satisfied in order to be tracked by
290// channelz as Socket.
291type Socket interface {
292 ChannelzMetric() *SocketInternalMetric
293}
294
295type listenSocket struct {
296 refName string
297 s Socket
298 id int64
299 pid int64
300 cm *channelMap
301}
302
303func (ls *listenSocket) addChild(id int64, e entry) {
304 grpclog.Errorf("cannot add a child (id = %d) of type %T to a listen socket", id, e)
305}
306
307func (ls *listenSocket) deleteChild(id int64) {
308 grpclog.Errorf("cannot delete a child (id = %d) from a listen socket", id)
309}
310
311func (ls *listenSocket) triggerDelete() {
312 ls.cm.deleteEntry(ls.id)
313 ls.cm.findEntry(ls.pid).deleteChild(ls.id)
314}
315
316func (ls *listenSocket) deleteSelfIfReady() {
317 grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket")
318}
319
320type normalSocket struct {
321 refName string
322 s Socket
323 id int64
324 pid int64
325 cm *channelMap
326}
327
328func (ns *normalSocket) addChild(id int64, e entry) {
329 grpclog.Errorf("cannot add a child (id = %d) of type %T to a normal socket", id, e)
330}
331
332func (ns *normalSocket) deleteChild(id int64) {
333 grpclog.Errorf("cannot delete a child (id = %d) from a normal socket", id)
334}
335
336func (ns *normalSocket) triggerDelete() {
337 ns.cm.deleteEntry(ns.id)
338 ns.cm.findEntry(ns.pid).deleteChild(ns.id)
339}
340
341func (ns *normalSocket) deleteSelfIfReady() {
342 grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket")
343}
344
345// ServerMetric defines the info channelz provides for a specific Server, which
346// includes ServerInternalMetric and channelz-specific data, such as channelz id,
347// child list, etc.
348type ServerMetric struct {
349 // ID is the channelz id of this server.
350 ID int64
351 // RefName is the human readable reference string of this server.
352 RefName string
353 // ServerData contains server internal metric reported by the server through
354 // ChannelzMetric().
355 ServerData *ServerInternalMetric
356 // ListenSockets tracks the listener socket type children of this server in the
357 // format of a map from socket channelz id to corresponding reference string.
358 ListenSockets map[int64]string
359}
360
361// ServerInternalMetric defines the struct that the implementor of Server interface
362// should return from ChannelzMetric().
363type ServerInternalMetric struct {
364 // The number of incoming calls started on the server.
365 CallsStarted int64
366 // The number of incoming calls that have completed with an OK status.
367 CallsSucceeded int64
368 // The number of incoming calls that have a completed with a non-OK status.
369 CallsFailed int64
370 // The last time a call was started on the server.
371 LastCallStartedTimestamp time.Time
372 //TODO: trace
373}
374
375// Server is the interface to be satisfied in order to be tracked by channelz as
376// Server.
377type Server interface {
378 ChannelzMetric() *ServerInternalMetric
379}
380
381type server struct {
382 refName string
383 s Server
384 closeCalled bool
385 sockets map[int64]string
386 listenSockets map[int64]string
387 id int64
388 cm *channelMap
389}
390
391func (s *server) addChild(id int64, e entry) {
392 switch v := e.(type) {
393 case *normalSocket:
394 s.sockets[id] = v.refName
395 case *listenSocket:
396 s.listenSockets[id] = v.refName
397 default:
398 grpclog.Errorf("cannot add a child (id = %d) of type %T to a server", id, e)
399 }
400}
401
402func (s *server) deleteChild(id int64) {
403 delete(s.sockets, id)
404 delete(s.listenSockets, id)
405 s.deleteSelfIfReady()
406}
407
408func (s *server) triggerDelete() {
409 s.closeCalled = true
410 s.deleteSelfIfReady()
411}
412
413func (s *server) deleteSelfIfReady() {
414 if !s.closeCalled || len(s.sockets)+len(s.listenSockets) != 0 {
415 return
416 }
417 s.cm.deleteEntry(s.id)
418}