package channelz
import (
)
type entry interface {
addChild(id int64, e entry)
deleteChild(id int64)
triggerDelete()
deleteSelfIfReady()
getParentID() int64
Entity
}
type channelMap struct {
mu sync.RWMutex
topLevelChannels map[int64]struct{}
channels map[int64]*Channel
subChannels map[int64]*SubChannel
sockets map[int64]*Socket
servers map[int64]*Server
}
func () *channelMap {
return &channelMap{
topLevelChannels: make(map[int64]struct{}),
channels: make(map[int64]*Channel),
subChannels: make(map[int64]*SubChannel),
sockets: make(map[int64]*Socket),
servers: make(map[int64]*Server),
}
}
func ( *channelMap) ( int64, *Server) {
.mu.Lock()
defer .mu.Unlock()
.cm =
.servers[] =
}
func ( *channelMap) ( int64, *Channel, bool, int64) {
.mu.Lock()
defer .mu.Unlock()
.trace.cm =
.channels[] =
if {
.topLevelChannels[] = struct{}{}
} else if := .channels[]; != nil {
.addChild(, )
} else {
logger.Infof("channel %d references invalid parent ID %d", , )
}
}
func ( *channelMap) ( int64, *SubChannel, int64) {
.mu.Lock()
defer .mu.Unlock()
.trace.cm =
.subChannels[] =
if := .channels[]; != nil {
.addChild(, )
} else {
logger.Infof("subchannel %d references invalid parent ID %d", , )
}
}
func ( *channelMap) ( *Socket) {
.mu.Lock()
defer .mu.Unlock()
.cm =
.sockets[.ID] =
if .Parent == nil {
logger.Infof("normal socket %d has no parent", .ID)
}
.Parent.(entry).addChild(.ID, )
}
func ( *channelMap) ( int64) {
.mu.Lock()
defer .mu.Unlock()
.findEntry().triggerDelete()
}
type tracedChannel interface {
getChannelTrace() *ChannelTrace
incrTraceRefCount()
decrTraceRefCount()
getRefName() string
}
func ( *channelMap) ( int64) {
:= .findEntry()
if , := .(tracedChannel); {
.decrTraceRefCount()
.deleteSelfIfReady()
}
}
func ( *channelMap) ( int64) entry {
if , := .channels[]; {
return
}
if , := .subChannels[]; {
return
}
if , := .servers[]; {
return
}
if , := .sockets[]; {
return
}
return &dummyEntry{idNotFound: }
}
func ( *channelMap) ( int64) entry {
if , := .sockets[]; {
delete(.sockets, )
return
}
if , := .subChannels[]; {
delete(.subChannels, )
return
}
if , := .channels[]; {
delete(.channels, )
delete(.topLevelChannels, )
return
}
if , := .servers[]; {
delete(.servers, )
return
}
return &dummyEntry{idNotFound: }
}
func ( *channelMap) ( int64, *TraceEvent) {
.mu.Lock()
defer .mu.Unlock()
:= .findEntry()
, := .(tracedChannel)
if ! {
return
}
.getChannelTrace().append(&traceEvent{Desc: .Desc, Severity: .Severity, Timestamp: time.Now()})
if .Parent != nil {
:= .findEntry(.getParentID())
var RefChannelType
switch .(type) {
case *Channel:
= RefChannel
case *SubChannel:
= RefSubChannel
}
if , := .(tracedChannel); {
.getChannelTrace().append(&traceEvent{
Desc: .Parent.Desc,
Severity: .Parent.Severity,
Timestamp: time.Now(),
RefID: ,
RefName: .getRefName(),
RefType: ,
})
.incrTraceRefCount()
}
}
}
type int64Slice []int64
func ( int64Slice) () int { return len() }
func ( int64Slice) (, int) { [], [] = [], [] }
func ( int64Slice) (, int) bool { return [] < [] }
func ( map[int64]string) map[int64]string {
:= make(map[int64]string)
for , := range {
[] =
}
return
}
func ( *channelMap) ( int64, int) ([]*Channel, bool) {
if <= 0 {
= EntriesPerPage
}
.mu.RLock()
defer .mu.RUnlock()
:= int64(len(.topLevelChannels))
:= make([]int64, 0, )
for := range .topLevelChannels {
= append(, )
}
sort.Sort(int64Slice())
:= sort.Search(len(), func( int) bool { return [] >= })
:= true
var []*Channel
for , := range [:] {
if len() == {
= false
break
}
if , := .channels[]; {
= append(, )
}
}
return ,
}
func ( *channelMap) ( int64, int) ([]*Server, bool) {
if <= 0 {
= EntriesPerPage
}
.mu.RLock()
defer .mu.RUnlock()
:= make([]int64, 0, len(.servers))
for := range .servers {
= append(, )
}
sort.Sort(int64Slice())
:= sort.Search(len(), func( int) bool { return [] >= })
:= true
var []*Server
for , := range [:] {
if len() == {
= false
break
}
if , := .servers[]; {
= append(, )
}
}
return ,
}
func ( *channelMap) ( int64, int64, int) ([]*Socket, bool) {
if <= 0 {
= EntriesPerPage
}
.mu.RLock()
defer .mu.RUnlock()
, := .servers[]
if ! {
return nil, true
}
:= .sockets
:= make([]int64, 0, len())
:= make([]*Socket, 0, min(len(), ))
for := range {
= append(, )
}
sort.Sort(int64Slice())
:= sort.Search(len(), func( int) bool { return [] >= })
:= true
for , := range [:] {
if len() == {
= false
break
}
if , := .sockets[]; {
= append(, )
}
}
return ,
}
func ( *channelMap) ( int64) *Channel {
.mu.RLock()
defer .mu.RUnlock()
return .channels[]
}
func ( *channelMap) ( int64) *SubChannel {
.mu.RLock()
defer .mu.RUnlock()
return .subChannels[]
}
func ( *channelMap) ( int64) *Socket {
.mu.RLock()
defer .mu.RUnlock()
return .sockets[]
}
func ( *channelMap) ( int64) *Server {
.mu.RLock()
defer .mu.RUnlock()
return .servers[]
}
type dummyEntry struct {
idNotFound int64
Entity
}
func ( *dummyEntry) () string {
return fmt.Sprintf("non-existent entity #%d", .idNotFound)
}
func ( *dummyEntry) () int64 { return .idNotFound }
func ( *dummyEntry) ( int64, entry) {
logger.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", , , .idNotFound)
}
func ( *dummyEntry) ( int64) {
logger.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", , .idNotFound)
}
func ( *dummyEntry) () {
logger.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", .idNotFound)
}
func (*dummyEntry) () {
}
func (*dummyEntry) () int64 {
return 0
}
type Entity interface {
isEntity()
fmt.Stringer
id() int64
}