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