google.golang.org/grpc@v1.62.1/internal/channelz/funcs.go (about)

     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 APIs for enabling channelz service, entry
    20  // registration/deletion, and accessing channelz data. It also defines channelz
    21  // metric struct formats.
    22  //
    23  // All APIs in this package are experimental.
    24  package channelz
    25  
    26  import (
    27  	"errors"
    28  	"sort"
    29  	"sync"
    30  	"sync/atomic"
    31  	"time"
    32  
    33  	"google.golang.org/grpc/grpclog"
    34  	"google.golang.org/grpc/internal"
    35  )
    36  
    37  const (
    38  	defaultMaxTraceEntry int32 = 30
    39  )
    40  
    41  var (
    42  	// IDGen is the global channelz entity ID generator.  It should not be used
    43  	// outside this package except by tests.
    44  	IDGen IDGenerator
    45  
    46  	db dbWrapper
    47  	// EntryPerPage defines the number of channelz entries to be shown on a web page.
    48  	EntryPerPage  = int64(50)
    49  	curState      int32
    50  	maxTraceEntry = defaultMaxTraceEntry
    51  )
    52  
    53  // TurnOn turns on channelz data collection.
    54  func TurnOn() {
    55  	if !IsOn() {
    56  		db.set(newChannelMap())
    57  		IDGen.Reset()
    58  		atomic.StoreInt32(&curState, 1)
    59  	}
    60  }
    61  
    62  func init() {
    63  	internal.ChannelzTurnOffForTesting = func() {
    64  		atomic.StoreInt32(&curState, 0)
    65  	}
    66  }
    67  
    68  // IsOn returns whether channelz data collection is on.
    69  func IsOn() bool {
    70  	return atomic.LoadInt32(&curState) == 1
    71  }
    72  
    73  // SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel).
    74  // Setting it to 0 will disable channel tracing.
    75  func SetMaxTraceEntry(i int32) {
    76  	atomic.StoreInt32(&maxTraceEntry, i)
    77  }
    78  
    79  // ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default.
    80  func ResetMaxTraceEntryToDefault() {
    81  	atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry)
    82  }
    83  
    84  func getMaxTraceEntry() int {
    85  	i := atomic.LoadInt32(&maxTraceEntry)
    86  	return int(i)
    87  }
    88  
    89  // dbWarpper wraps around a reference to internal channelz data storage, and
    90  // provide synchronized functionality to set and get the reference.
    91  type dbWrapper struct {
    92  	mu sync.RWMutex
    93  	DB *channelMap
    94  }
    95  
    96  func (d *dbWrapper) set(db *channelMap) {
    97  	d.mu.Lock()
    98  	d.DB = db
    99  	d.mu.Unlock()
   100  }
   101  
   102  func (d *dbWrapper) get() *channelMap {
   103  	d.mu.RLock()
   104  	defer d.mu.RUnlock()
   105  	return d.DB
   106  }
   107  
   108  // GetTopChannels returns a slice of top channel's ChannelMetric, along with a
   109  // boolean indicating whether there's more top channels to be queried for.
   110  //
   111  // The arg id specifies that only top channel with id at or above it will be included
   112  // in the result. The returned slice is up to a length of the arg maxResults or
   113  // EntryPerPage if maxResults is zero, and is sorted in ascending id order.
   114  func GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) {
   115  	return db.get().GetTopChannels(id, maxResults)
   116  }
   117  
   118  // GetServers returns a slice of server's ServerMetric, along with a
   119  // boolean indicating whether there's more servers to be queried for.
   120  //
   121  // The arg id specifies that only server with id at or above it will be included
   122  // in the result. The returned slice is up to a length of the arg maxResults or
   123  // EntryPerPage if maxResults is zero, and is sorted in ascending id order.
   124  func GetServers(id int64, maxResults int64) ([]*ServerMetric, bool) {
   125  	return db.get().GetServers(id, maxResults)
   126  }
   127  
   128  // GetServerSockets returns a slice of server's (identified by id) normal socket's
   129  // SocketMetric, along with a boolean indicating whether there's more sockets to
   130  // be queried for.
   131  //
   132  // The arg startID specifies that only sockets with id at or above it will be
   133  // included in the result. The returned slice is up to a length of the arg maxResults
   134  // or EntryPerPage if maxResults is zero, and is sorted in ascending id order.
   135  func GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) {
   136  	return db.get().GetServerSockets(id, startID, maxResults)
   137  }
   138  
   139  // GetChannel returns the ChannelMetric for the channel (identified by id).
   140  func GetChannel(id int64) *ChannelMetric {
   141  	return db.get().GetChannel(id)
   142  }
   143  
   144  // GetSubChannel returns the SubChannelMetric for the subchannel (identified by id).
   145  func GetSubChannel(id int64) *SubChannelMetric {
   146  	return db.get().GetSubChannel(id)
   147  }
   148  
   149  // GetSocket returns the SocketInternalMetric for the socket (identified by id).
   150  func GetSocket(id int64) *SocketMetric {
   151  	return db.get().GetSocket(id)
   152  }
   153  
   154  // GetServer returns the ServerMetric for the server (identified by id).
   155  func GetServer(id int64) *ServerMetric {
   156  	return db.get().GetServer(id)
   157  }
   158  
   159  // RegisterChannel registers the given channel c in the channelz database with
   160  // ref as its reference name, and adds it to the child list of its parent
   161  // (identified by pid). pid == nil means no parent.
   162  //
   163  // Returns a unique channelz identifier assigned to this channel.
   164  //
   165  // If channelz is not turned ON, the channelz database is not mutated.
   166  func RegisterChannel(c Channel, pid *Identifier, ref string) *Identifier {
   167  	id := IDGen.genID()
   168  	var parent int64
   169  	isTopChannel := true
   170  	if pid != nil {
   171  		isTopChannel = false
   172  		parent = pid.Int()
   173  	}
   174  
   175  	if !IsOn() {
   176  		return newIdentifer(RefChannel, id, pid)
   177  	}
   178  
   179  	cn := &channel{
   180  		refName:     ref,
   181  		c:           c,
   182  		subChans:    make(map[int64]string),
   183  		nestedChans: make(map[int64]string),
   184  		id:          id,
   185  		pid:         parent,
   186  		trace:       &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
   187  	}
   188  	db.get().addChannel(id, cn, isTopChannel, parent)
   189  	return newIdentifer(RefChannel, id, pid)
   190  }
   191  
   192  // RegisterSubChannel registers the given subChannel c in the channelz database
   193  // with ref as its reference name, and adds it to the child list of its parent
   194  // (identified by pid).
   195  //
   196  // Returns a unique channelz identifier assigned to this subChannel.
   197  //
   198  // If channelz is not turned ON, the channelz database is not mutated.
   199  func RegisterSubChannel(c Channel, pid *Identifier, ref string) (*Identifier, error) {
   200  	if pid == nil {
   201  		return nil, errors.New("a SubChannel's parent id cannot be nil")
   202  	}
   203  	id := IDGen.genID()
   204  	if !IsOn() {
   205  		return newIdentifer(RefSubChannel, id, pid), nil
   206  	}
   207  
   208  	sc := &subChannel{
   209  		refName: ref,
   210  		c:       c,
   211  		sockets: make(map[int64]string),
   212  		id:      id,
   213  		pid:     pid.Int(),
   214  		trace:   &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
   215  	}
   216  	db.get().addSubChannel(id, sc, pid.Int())
   217  	return newIdentifer(RefSubChannel, id, pid), nil
   218  }
   219  
   220  // RegisterServer registers the given server s in channelz database. It returns
   221  // the unique channelz tracking id assigned to this server.
   222  //
   223  // If channelz is not turned ON, the channelz database is not mutated.
   224  func RegisterServer(s Server, ref string) *Identifier {
   225  	id := IDGen.genID()
   226  	if !IsOn() {
   227  		return newIdentifer(RefServer, id, nil)
   228  	}
   229  
   230  	svr := &server{
   231  		refName:       ref,
   232  		s:             s,
   233  		sockets:       make(map[int64]string),
   234  		listenSockets: make(map[int64]string),
   235  		id:            id,
   236  	}
   237  	db.get().addServer(id, svr)
   238  	return newIdentifer(RefServer, id, nil)
   239  }
   240  
   241  // RegisterListenSocket registers the given listen socket s in channelz database
   242  // with ref as its reference name, and add it to the child list of its parent
   243  // (identified by pid). It returns the unique channelz tracking id assigned to
   244  // this listen socket.
   245  //
   246  // If channelz is not turned ON, the channelz database is not mutated.
   247  func RegisterListenSocket(s Socket, pid *Identifier, ref string) (*Identifier, error) {
   248  	if pid == nil {
   249  		return nil, errors.New("a ListenSocket's parent id cannot be 0")
   250  	}
   251  	id := IDGen.genID()
   252  	if !IsOn() {
   253  		return newIdentifer(RefListenSocket, id, pid), nil
   254  	}
   255  
   256  	ls := &listenSocket{refName: ref, s: s, id: id, pid: pid.Int()}
   257  	db.get().addListenSocket(id, ls, pid.Int())
   258  	return newIdentifer(RefListenSocket, id, pid), nil
   259  }
   260  
   261  // RegisterNormalSocket registers the given normal socket s in channelz database
   262  // with ref as its reference name, and adds it to the child list of its parent
   263  // (identified by pid). It returns the unique channelz tracking id assigned to
   264  // this normal socket.
   265  //
   266  // If channelz is not turned ON, the channelz database is not mutated.
   267  func RegisterNormalSocket(s Socket, pid *Identifier, ref string) (*Identifier, error) {
   268  	if pid == nil {
   269  		return nil, errors.New("a NormalSocket's parent id cannot be 0")
   270  	}
   271  	id := IDGen.genID()
   272  	if !IsOn() {
   273  		return newIdentifer(RefNormalSocket, id, pid), nil
   274  	}
   275  
   276  	ns := &normalSocket{refName: ref, s: s, id: id, pid: pid.Int()}
   277  	db.get().addNormalSocket(id, ns, pid.Int())
   278  	return newIdentifer(RefNormalSocket, id, pid), nil
   279  }
   280  
   281  // RemoveEntry removes an entry with unique channelz tracking id to be id from
   282  // channelz database.
   283  //
   284  // If channelz is not turned ON, this function is a no-op.
   285  func RemoveEntry(id *Identifier) {
   286  	if !IsOn() {
   287  		return
   288  	}
   289  	db.get().removeEntry(id.Int())
   290  }
   291  
   292  // TraceEventDesc is what the caller of AddTraceEvent should provide to describe
   293  // the event to be added to the channel trace.
   294  //
   295  // The Parent field is optional. It is used for an event that will be recorded
   296  // in the entity's parent trace.
   297  type TraceEventDesc struct {
   298  	Desc     string
   299  	Severity Severity
   300  	Parent   *TraceEventDesc
   301  }
   302  
   303  // AddTraceEvent adds trace related to the entity with specified id, using the
   304  // provided TraceEventDesc.
   305  //
   306  // If channelz is not turned ON, this will simply log the event descriptions.
   307  func AddTraceEvent(l grpclog.DepthLoggerV2, id *Identifier, depth int, desc *TraceEventDesc) {
   308  	// Log only the trace description associated with the bottom most entity.
   309  	switch desc.Severity {
   310  	case CtUnknown, CtInfo:
   311  		l.InfoDepth(depth+1, withParens(id)+desc.Desc)
   312  	case CtWarning:
   313  		l.WarningDepth(depth+1, withParens(id)+desc.Desc)
   314  	case CtError:
   315  		l.ErrorDepth(depth+1, withParens(id)+desc.Desc)
   316  	}
   317  
   318  	if getMaxTraceEntry() == 0 {
   319  		return
   320  	}
   321  	if IsOn() {
   322  		db.get().traceEvent(id.Int(), desc)
   323  	}
   324  }
   325  
   326  // channelMap is the storage data structure for channelz.
   327  // Methods of channelMap can be divided in two two categories with respect to locking.
   328  // 1. Methods acquire the global lock.
   329  // 2. Methods that can only be called when global lock is held.
   330  // A second type of method need always to be called inside a first type of method.
   331  type channelMap struct {
   332  	mu               sync.RWMutex
   333  	topLevelChannels map[int64]struct{}
   334  	servers          map[int64]*server
   335  	channels         map[int64]*channel
   336  	subChannels      map[int64]*subChannel
   337  	listenSockets    map[int64]*listenSocket
   338  	normalSockets    map[int64]*normalSocket
   339  }
   340  
   341  func newChannelMap() *channelMap {
   342  	return &channelMap{
   343  		topLevelChannels: make(map[int64]struct{}),
   344  		channels:         make(map[int64]*channel),
   345  		listenSockets:    make(map[int64]*listenSocket),
   346  		normalSockets:    make(map[int64]*normalSocket),
   347  		servers:          make(map[int64]*server),
   348  		subChannels:      make(map[int64]*subChannel),
   349  	}
   350  }
   351  
   352  func (c *channelMap) addServer(id int64, s *server) {
   353  	c.mu.Lock()
   354  	s.cm = c
   355  	c.servers[id] = s
   356  	c.mu.Unlock()
   357  }
   358  
   359  func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64) {
   360  	c.mu.Lock()
   361  	cn.cm = c
   362  	cn.trace.cm = c
   363  	c.channels[id] = cn
   364  	if isTopChannel {
   365  		c.topLevelChannels[id] = struct{}{}
   366  	} else {
   367  		c.findEntry(pid).addChild(id, cn)
   368  	}
   369  	c.mu.Unlock()
   370  }
   371  
   372  func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64) {
   373  	c.mu.Lock()
   374  	sc.cm = c
   375  	sc.trace.cm = c
   376  	c.subChannels[id] = sc
   377  	c.findEntry(pid).addChild(id, sc)
   378  	c.mu.Unlock()
   379  }
   380  
   381  func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64) {
   382  	c.mu.Lock()
   383  	ls.cm = c
   384  	c.listenSockets[id] = ls
   385  	c.findEntry(pid).addChild(id, ls)
   386  	c.mu.Unlock()
   387  }
   388  
   389  func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64) {
   390  	c.mu.Lock()
   391  	ns.cm = c
   392  	c.normalSockets[id] = ns
   393  	c.findEntry(pid).addChild(id, ns)
   394  	c.mu.Unlock()
   395  }
   396  
   397  // removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to
   398  // wait on the deletion of its children and until no other entity's channel trace references it.
   399  // It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully
   400  // shutting down server will lead to the server being also deleted.
   401  func (c *channelMap) removeEntry(id int64) {
   402  	c.mu.Lock()
   403  	c.findEntry(id).triggerDelete()
   404  	c.mu.Unlock()
   405  }
   406  
   407  // c.mu must be held by the caller
   408  func (c *channelMap) decrTraceRefCount(id int64) {
   409  	e := c.findEntry(id)
   410  	if v, ok := e.(tracedChannel); ok {
   411  		v.decrTraceRefCount()
   412  		e.deleteSelfIfReady()
   413  	}
   414  }
   415  
   416  // c.mu must be held by the caller.
   417  func (c *channelMap) findEntry(id int64) entry {
   418  	var v entry
   419  	var ok bool
   420  	if v, ok = c.channels[id]; ok {
   421  		return v
   422  	}
   423  	if v, ok = c.subChannels[id]; ok {
   424  		return v
   425  	}
   426  	if v, ok = c.servers[id]; ok {
   427  		return v
   428  	}
   429  	if v, ok = c.listenSockets[id]; ok {
   430  		return v
   431  	}
   432  	if v, ok = c.normalSockets[id]; ok {
   433  		return v
   434  	}
   435  	return &dummyEntry{idNotFound: id}
   436  }
   437  
   438  // c.mu must be held by the caller
   439  // deleteEntry simply deletes an entry from the channelMap. Before calling this
   440  // method, caller must check this entry is ready to be deleted, i.e removeEntry()
   441  // has been called on it, and no children still exist.
   442  // Conditionals are ordered by the expected frequency of deletion of each entity
   443  // type, in order to optimize performance.
   444  func (c *channelMap) deleteEntry(id int64) {
   445  	var ok bool
   446  	if _, ok = c.normalSockets[id]; ok {
   447  		delete(c.normalSockets, id)
   448  		return
   449  	}
   450  	if _, ok = c.subChannels[id]; ok {
   451  		delete(c.subChannels, id)
   452  		return
   453  	}
   454  	if _, ok = c.channels[id]; ok {
   455  		delete(c.channels, id)
   456  		delete(c.topLevelChannels, id)
   457  		return
   458  	}
   459  	if _, ok = c.listenSockets[id]; ok {
   460  		delete(c.listenSockets, id)
   461  		return
   462  	}
   463  	if _, ok = c.servers[id]; ok {
   464  		delete(c.servers, id)
   465  		return
   466  	}
   467  }
   468  
   469  func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) {
   470  	c.mu.Lock()
   471  	child := c.findEntry(id)
   472  	childTC, ok := child.(tracedChannel)
   473  	if !ok {
   474  		c.mu.Unlock()
   475  		return
   476  	}
   477  	childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()})
   478  	if desc.Parent != nil {
   479  		parent := c.findEntry(child.getParentID())
   480  		var chanType RefChannelType
   481  		switch child.(type) {
   482  		case *channel:
   483  			chanType = RefChannel
   484  		case *subChannel:
   485  			chanType = RefSubChannel
   486  		}
   487  		if parentTC, ok := parent.(tracedChannel); ok {
   488  			parentTC.getChannelTrace().append(&TraceEvent{
   489  				Desc:      desc.Parent.Desc,
   490  				Severity:  desc.Parent.Severity,
   491  				Timestamp: time.Now(),
   492  				RefID:     id,
   493  				RefName:   childTC.getRefName(),
   494  				RefType:   chanType,
   495  			})
   496  			childTC.incrTraceRefCount()
   497  		}
   498  	}
   499  	c.mu.Unlock()
   500  }
   501  
   502  type int64Slice []int64
   503  
   504  func (s int64Slice) Len() int           { return len(s) }
   505  func (s int64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   506  func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] }
   507  
   508  func copyMap(m map[int64]string) map[int64]string {
   509  	n := make(map[int64]string)
   510  	for k, v := range m {
   511  		n[k] = v
   512  	}
   513  	return n
   514  }
   515  
   516  func min(a, b int64) int64 {
   517  	if a < b {
   518  		return a
   519  	}
   520  	return b
   521  }
   522  
   523  func (c *channelMap) GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) {
   524  	if maxResults <= 0 {
   525  		maxResults = EntryPerPage
   526  	}
   527  	c.mu.RLock()
   528  	l := int64(len(c.topLevelChannels))
   529  	ids := make([]int64, 0, l)
   530  	cns := make([]*channel, 0, min(l, maxResults))
   531  
   532  	for k := range c.topLevelChannels {
   533  		ids = append(ids, k)
   534  	}
   535  	sort.Sort(int64Slice(ids))
   536  	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
   537  	count := int64(0)
   538  	var end bool
   539  	var t []*ChannelMetric
   540  	for i, v := range ids[idx:] {
   541  		if count == maxResults {
   542  			break
   543  		}
   544  		if cn, ok := c.channels[v]; ok {
   545  			cns = append(cns, cn)
   546  			t = append(t, &ChannelMetric{
   547  				NestedChans: copyMap(cn.nestedChans),
   548  				SubChans:    copyMap(cn.subChans),
   549  			})
   550  			count++
   551  		}
   552  		if i == len(ids[idx:])-1 {
   553  			end = true
   554  			break
   555  		}
   556  	}
   557  	c.mu.RUnlock()
   558  	if count == 0 {
   559  		end = true
   560  	}
   561  
   562  	for i, cn := range cns {
   563  		t[i].ChannelData = cn.c.ChannelzMetric()
   564  		t[i].ID = cn.id
   565  		t[i].RefName = cn.refName
   566  		t[i].Trace = cn.trace.dumpData()
   567  	}
   568  	return t, end
   569  }
   570  
   571  func (c *channelMap) GetServers(id, maxResults int64) ([]*ServerMetric, bool) {
   572  	if maxResults <= 0 {
   573  		maxResults = EntryPerPage
   574  	}
   575  	c.mu.RLock()
   576  	l := int64(len(c.servers))
   577  	ids := make([]int64, 0, l)
   578  	ss := make([]*server, 0, min(l, maxResults))
   579  	for k := range c.servers {
   580  		ids = append(ids, k)
   581  	}
   582  	sort.Sort(int64Slice(ids))
   583  	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
   584  	count := int64(0)
   585  	var end bool
   586  	var s []*ServerMetric
   587  	for i, v := range ids[idx:] {
   588  		if count == maxResults {
   589  			break
   590  		}
   591  		if svr, ok := c.servers[v]; ok {
   592  			ss = append(ss, svr)
   593  			s = append(s, &ServerMetric{
   594  				ListenSockets: copyMap(svr.listenSockets),
   595  			})
   596  			count++
   597  		}
   598  		if i == len(ids[idx:])-1 {
   599  			end = true
   600  			break
   601  		}
   602  	}
   603  	c.mu.RUnlock()
   604  	if count == 0 {
   605  		end = true
   606  	}
   607  
   608  	for i, svr := range ss {
   609  		s[i].ServerData = svr.s.ChannelzMetric()
   610  		s[i].ID = svr.id
   611  		s[i].RefName = svr.refName
   612  	}
   613  	return s, end
   614  }
   615  
   616  func (c *channelMap) GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) {
   617  	if maxResults <= 0 {
   618  		maxResults = EntryPerPage
   619  	}
   620  	var svr *server
   621  	var ok bool
   622  	c.mu.RLock()
   623  	if svr, ok = c.servers[id]; !ok {
   624  		// server with id doesn't exist.
   625  		c.mu.RUnlock()
   626  		return nil, true
   627  	}
   628  	svrskts := svr.sockets
   629  	l := int64(len(svrskts))
   630  	ids := make([]int64, 0, l)
   631  	sks := make([]*normalSocket, 0, min(l, maxResults))
   632  	for k := range svrskts {
   633  		ids = append(ids, k)
   634  	}
   635  	sort.Sort(int64Slice(ids))
   636  	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= startID })
   637  	count := int64(0)
   638  	var end bool
   639  	for i, v := range ids[idx:] {
   640  		if count == maxResults {
   641  			break
   642  		}
   643  		if ns, ok := c.normalSockets[v]; ok {
   644  			sks = append(sks, ns)
   645  			count++
   646  		}
   647  		if i == len(ids[idx:])-1 {
   648  			end = true
   649  			break
   650  		}
   651  	}
   652  	c.mu.RUnlock()
   653  	if count == 0 {
   654  		end = true
   655  	}
   656  	s := make([]*SocketMetric, 0, len(sks))
   657  	for _, ns := range sks {
   658  		sm := &SocketMetric{}
   659  		sm.SocketData = ns.s.ChannelzMetric()
   660  		sm.ID = ns.id
   661  		sm.RefName = ns.refName
   662  		s = append(s, sm)
   663  	}
   664  	return s, end
   665  }
   666  
   667  func (c *channelMap) GetChannel(id int64) *ChannelMetric {
   668  	cm := &ChannelMetric{}
   669  	var cn *channel
   670  	var ok bool
   671  	c.mu.RLock()
   672  	if cn, ok = c.channels[id]; !ok {
   673  		// channel with id doesn't exist.
   674  		c.mu.RUnlock()
   675  		return nil
   676  	}
   677  	cm.NestedChans = copyMap(cn.nestedChans)
   678  	cm.SubChans = copyMap(cn.subChans)
   679  	// cn.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of cn.c when
   680  	// holding the lock to prevent potential data race.
   681  	chanCopy := cn.c
   682  	c.mu.RUnlock()
   683  	cm.ChannelData = chanCopy.ChannelzMetric()
   684  	cm.ID = cn.id
   685  	cm.RefName = cn.refName
   686  	cm.Trace = cn.trace.dumpData()
   687  	return cm
   688  }
   689  
   690  func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric {
   691  	cm := &SubChannelMetric{}
   692  	var sc *subChannel
   693  	var ok bool
   694  	c.mu.RLock()
   695  	if sc, ok = c.subChannels[id]; !ok {
   696  		// subchannel with id doesn't exist.
   697  		c.mu.RUnlock()
   698  		return nil
   699  	}
   700  	cm.Sockets = copyMap(sc.sockets)
   701  	// sc.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of sc.c when
   702  	// holding the lock to prevent potential data race.
   703  	chanCopy := sc.c
   704  	c.mu.RUnlock()
   705  	cm.ChannelData = chanCopy.ChannelzMetric()
   706  	cm.ID = sc.id
   707  	cm.RefName = sc.refName
   708  	cm.Trace = sc.trace.dumpData()
   709  	return cm
   710  }
   711  
   712  func (c *channelMap) GetSocket(id int64) *SocketMetric {
   713  	sm := &SocketMetric{}
   714  	c.mu.RLock()
   715  	if ls, ok := c.listenSockets[id]; ok {
   716  		c.mu.RUnlock()
   717  		sm.SocketData = ls.s.ChannelzMetric()
   718  		sm.ID = ls.id
   719  		sm.RefName = ls.refName
   720  		return sm
   721  	}
   722  	if ns, ok := c.normalSockets[id]; ok {
   723  		c.mu.RUnlock()
   724  		sm.SocketData = ns.s.ChannelzMetric()
   725  		sm.ID = ns.id
   726  		sm.RefName = ns.refName
   727  		return sm
   728  	}
   729  	c.mu.RUnlock()
   730  	return nil
   731  }
   732  
   733  func (c *channelMap) GetServer(id int64) *ServerMetric {
   734  	sm := &ServerMetric{}
   735  	var svr *server
   736  	var ok bool
   737  	c.mu.RLock()
   738  	if svr, ok = c.servers[id]; !ok {
   739  		c.mu.RUnlock()
   740  		return nil
   741  	}
   742  	sm.ListenSockets = copyMap(svr.listenSockets)
   743  	c.mu.RUnlock()
   744  	sm.ID = svr.id
   745  	sm.RefName = svr.refName
   746  	sm.ServerData = svr.s.ChannelzMetric()
   747  	return sm
   748  }
   749  
   750  // IDGenerator is an incrementing atomic that tracks IDs for channelz entities.
   751  type IDGenerator struct {
   752  	id int64
   753  }
   754  
   755  // Reset resets the generated ID back to zero.  Should only be used at
   756  // initialization or by tests sensitive to the ID number.
   757  func (i *IDGenerator) Reset() {
   758  	atomic.StoreInt64(&i.id, 0)
   759  }
   760  
   761  func (i *IDGenerator) genID() int64 {
   762  	return atomic.AddInt64(&i.id, 1)
   763  }