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 }