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