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 19 // Package channelz defines internal APIs for enabling channelz service, entry
20 // registration/deletion, and accessing channelz data. It also defines channelz
21 // metric struct formats.
22 package channelz
23 24 import (
25 "sync/atomic"
26 "time"
27 28 "google.golang.org/grpc/internal"
29 )
30 31 var (
32 // IDGen is the global channelz entity ID generator. It should not be used
33 // outside this package except by tests.
34 IDGen IDGenerator
35 36 db = newChannelMap()
37 // EntriesPerPage defines the number of channelz entries to be shown on a web page.
38 EntriesPerPage = 50
39 curState int32
40 )
41 42 // TurnOn turns on channelz data collection.
43 func TurnOn() {
44 atomic.StoreInt32(&curState, 1)
45 }
46 47 func init() {
48 internal.ChannelzTurnOffForTesting = func() {
49 atomic.StoreInt32(&curState, 0)
50 }
51 }
52 53 // IsOn returns whether channelz data collection is on.
54 func IsOn() bool {
55 return atomic.LoadInt32(&curState) == 1
56 }
57 58 // GetTopChannels returns a slice of top channel's ChannelMetric, along with a
59 // boolean indicating whether there's more top channels to be queried for.
60 //
61 // The arg id specifies that only top channel with id at or above it will be
62 // included in the result. The returned slice is up to a length of the arg
63 // maxResults or EntriesPerPage if maxResults is zero, and is sorted in ascending
64 // id order.
65 func GetTopChannels(id int64, maxResults int) ([]*Channel, bool) {
66 return db.getTopChannels(id, maxResults)
67 }
68 69 // GetServers returns a slice of server's ServerMetric, along with a
70 // boolean indicating whether there's more servers to be queried for.
71 //
72 // The arg id specifies that only server with id at or above it will be included
73 // in the result. The returned slice is up to a length of the arg maxResults or
74 // EntriesPerPage if maxResults is zero, and is sorted in ascending id order.
75 func GetServers(id int64, maxResults int) ([]*Server, bool) {
76 return db.getServers(id, maxResults)
77 }
78 79 // GetServerSockets returns a slice of server's (identified by id) normal socket's
80 // SocketMetrics, along with a boolean indicating whether there's more sockets to
81 // be queried for.
82 //
83 // The arg startID specifies that only sockets with id at or above it will be
84 // included in the result. The returned slice is up to a length of the arg maxResults
85 // or EntriesPerPage if maxResults is zero, and is sorted in ascending id order.
86 func GetServerSockets(id int64, startID int64, maxResults int) ([]*Socket, bool) {
87 return db.getServerSockets(id, startID, maxResults)
88 }
89 90 // GetChannel returns the Channel for the channel (identified by id).
91 func GetChannel(id int64) *Channel {
92 return db.getChannel(id)
93 }
94 95 // GetSubChannel returns the SubChannel for the subchannel (identified by id).
96 func GetSubChannel(id int64) *SubChannel {
97 return db.getSubChannel(id)
98 }
99 100 // GetSocket returns the Socket for the socket (identified by id).
101 func GetSocket(id int64) *Socket {
102 return db.getSocket(id)
103 }
104 105 // GetServer returns the ServerMetric for the server (identified by id).
106 func GetServer(id int64) *Server {
107 return db.getServer(id)
108 }
109 110 // RegisterChannel registers the given channel c in the channelz database with
111 // target as its target and reference name, and adds it to the child list of its
112 // parent. parent == nil means no parent.
113 //
114 // Returns a unique channelz identifier assigned to this channel.
115 //
116 // If channelz is not turned ON, the channelz database is not mutated.
117 func RegisterChannel(parent *Channel, target string) *Channel {
118 id := IDGen.genID()
119 120 if !IsOn() {
121 return &Channel{ID: id}
122 }
123 124 isTopChannel := parent == nil
125 126 cn := &Channel{
127 ID: id,
128 RefName: target,
129 nestedChans: make(map[int64]string),
130 subChans: make(map[int64]string),
131 Parent: parent,
132 trace: &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())},
133 }
134 cn.ChannelMetrics.Target.Store(&target)
135 db.addChannel(id, cn, isTopChannel, cn.getParentID())
136 return cn
137 }
138 139 // RegisterSubChannel registers the given subChannel c in the channelz database
140 // with ref as its reference name, and adds it to the child list of its parent
141 // (identified by pid).
142 //
143 // Returns a unique channelz identifier assigned to this subChannel.
144 //
145 // If channelz is not turned ON, the channelz database is not mutated.
146 func RegisterSubChannel(parent *Channel, ref string) *SubChannel {
147 id := IDGen.genID()
148 sc := &SubChannel{
149 ID: id,
150 RefName: ref,
151 parent: parent,
152 }
153 154 if !IsOn() {
155 return sc
156 }
157 158 sc.sockets = make(map[int64]string)
159 sc.trace = &ChannelTrace{CreationTime: time.Now(), Events: make([]*traceEvent, 0, getMaxTraceEntry())}
160 db.addSubChannel(id, sc, parent.ID)
161 return sc
162 }
163 164 // RegisterServer registers the given server s in channelz database. It returns
165 // the unique channelz tracking id assigned to this server.
166 //
167 // If channelz is not turned ON, the channelz database is not mutated.
168 func RegisterServer(ref string) *Server {
169 id := IDGen.genID()
170 if !IsOn() {
171 return &Server{ID: id}
172 }
173 174 svr := &Server{
175 RefName: ref,
176 sockets: make(map[int64]string),
177 listenSockets: make(map[int64]string),
178 ID: id,
179 }
180 db.addServer(id, svr)
181 return svr
182 }
183 184 // RegisterSocket registers the given normal socket s in channelz database
185 // with ref as its reference name, and adds it to the child list of its parent
186 // (identified by skt.Parent, which must be set). It returns the unique channelz
187 // tracking id assigned to this normal socket.
188 //
189 // If channelz is not turned ON, the channelz database is not mutated.
190 func RegisterSocket(skt *Socket) *Socket {
191 skt.ID = IDGen.genID()
192 if IsOn() {
193 db.addSocket(skt)
194 }
195 return skt
196 }
197 198 // RemoveEntry removes an entry with unique channelz tracking id to be id from
199 // channelz database.
200 //
201 // If channelz is not turned ON, this function is a no-op.
202 func RemoveEntry(id int64) {
203 if !IsOn() {
204 return
205 }
206 db.removeEntry(id)
207 }
208 209 // IDGenerator is an incrementing atomic that tracks IDs for channelz entities.
210 type IDGenerator struct {
211 id int64
212 }
213 214 // Reset resets the generated ID back to zero. Should only be used at
215 // initialization or by tests sensitive to the ID number.
216 func (i *IDGenerator) Reset() {
217 atomic.StoreInt64(&i.id, 0)
218 }
219 220 func (i *IDGenerator) genID() int64 {
221 return atomic.AddInt64(&i.id, 1)
222 }
223 224 // Identifier is an opaque channelz identifier used to expose channelz symbols
225 // outside of grpc. Currently only implemented by Channel since no other
226 // types require exposure outside grpc.
227 type Identifier interface {
228 Entity
229 channelzIdentifier()
230 }
231