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.
22package channelz
23
24import (
25 "sync/atomic"
26 "time"
27
28 "google.golang.org/grpc/internal"
29)
30
31var (
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.
43func TurnOn() {
44 atomic.StoreInt32(&curState, 1)
45}
46
47func init() {
48 internal.ChannelzTurnOffForTesting = func() {
49 atomic.StoreInt32(&curState, 0)
50 }
51}
52
53// IsOn returns whether channelz data collection is on.
54func 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.
65func 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.
75func 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.
86func 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).
91func GetChannel(id int64) *Channel {
92 return db.getChannel(id)
93}
94
95// GetSubChannel returns the SubChannel for the subchannel (identified by id).
96func GetSubChannel(id int64) *SubChannel {
97 return db.getSubChannel(id)
98}
99
100// GetSocket returns the Socket for the socket (identified by id).
101func GetSocket(id int64) *Socket {
102 return db.getSocket(id)
103}
104
105// GetServer returns the ServerMetric for the server (identified by id).
106func 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.
117func 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.
146func 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.
168func 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.
190func 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.
202func 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.
210type 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.
216func (i *IDGenerator) Reset() {
217 atomic.StoreInt64(&i.id, 0)
218}
219
220func (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.
227type Identifier interface {
228 Entity
229 channelzIdentifier()
230}