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 }