mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-01 00:23:56 +08:00 
			
		
		
		
	vendor: initial vendor
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
		
							
								
								
									
										699
									
								
								vendor/google.golang.org/grpc/internal/channelz/funcs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										699
									
								
								vendor/google.golang.org/grpc/internal/channelz/funcs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,699 @@ | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| // Package channelz defines APIs for enabling channelz service, entry | ||||
| // registration/deletion, and accessing channelz data. It also defines channelz | ||||
| // metric struct formats. | ||||
| // | ||||
| // All APIs in this package are experimental. | ||||
| package channelz | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	defaultMaxTraceEntry int32 = 30 | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	db    dbWrapper | ||||
| 	idGen idGenerator | ||||
| 	// EntryPerPage defines the number of channelz entries to be shown on a web page. | ||||
| 	EntryPerPage  = int64(50) | ||||
| 	curState      int32 | ||||
| 	maxTraceEntry = defaultMaxTraceEntry | ||||
| ) | ||||
|  | ||||
| // TurnOn turns on channelz data collection. | ||||
| func TurnOn() { | ||||
| 	if !IsOn() { | ||||
| 		NewChannelzStorage() | ||||
| 		atomic.StoreInt32(&curState, 1) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // IsOn returns whether channelz data collection is on. | ||||
| func IsOn() bool { | ||||
| 	return atomic.CompareAndSwapInt32(&curState, 1, 1) | ||||
| } | ||||
|  | ||||
| // SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel). | ||||
| // Setting it to 0 will disable channel tracing. | ||||
| func SetMaxTraceEntry(i int32) { | ||||
| 	atomic.StoreInt32(&maxTraceEntry, i) | ||||
| } | ||||
|  | ||||
| // ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default. | ||||
| func ResetMaxTraceEntryToDefault() { | ||||
| 	atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry) | ||||
| } | ||||
|  | ||||
| func getMaxTraceEntry() int { | ||||
| 	i := atomic.LoadInt32(&maxTraceEntry) | ||||
| 	return int(i) | ||||
| } | ||||
|  | ||||
| // dbWarpper wraps around a reference to internal channelz data storage, and | ||||
| // provide synchronized functionality to set and get the reference. | ||||
| type dbWrapper struct { | ||||
| 	mu sync.RWMutex | ||||
| 	DB *channelMap | ||||
| } | ||||
|  | ||||
| func (d *dbWrapper) set(db *channelMap) { | ||||
| 	d.mu.Lock() | ||||
| 	d.DB = db | ||||
| 	d.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (d *dbWrapper) get() *channelMap { | ||||
| 	d.mu.RLock() | ||||
| 	defer d.mu.RUnlock() | ||||
| 	return d.DB | ||||
| } | ||||
|  | ||||
| // NewChannelzStorage initializes channelz data storage and id generator. | ||||
| // | ||||
| // Note: This function is exported for testing purpose only. User should not call | ||||
| // it in most cases. | ||||
| func NewChannelzStorage() { | ||||
| 	db.set(&channelMap{ | ||||
| 		topLevelChannels: make(map[int64]struct{}), | ||||
| 		channels:         make(map[int64]*channel), | ||||
| 		listenSockets:    make(map[int64]*listenSocket), | ||||
| 		normalSockets:    make(map[int64]*normalSocket), | ||||
| 		servers:          make(map[int64]*server), | ||||
| 		subChannels:      make(map[int64]*subChannel), | ||||
| 	}) | ||||
| 	idGen.reset() | ||||
| } | ||||
|  | ||||
| // GetTopChannels returns a slice of top channel's ChannelMetric, along with a | ||||
| // boolean indicating whether there's more top channels to be queried for. | ||||
| // | ||||
| // The arg id specifies that only top channel with id at or above it will be included | ||||
| // in the result. The returned slice is up to a length of the arg maxResults or | ||||
| // EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||||
| func GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) { | ||||
| 	return db.get().GetTopChannels(id, maxResults) | ||||
| } | ||||
|  | ||||
| // GetServers returns a slice of server's ServerMetric, along with a | ||||
| // boolean indicating whether there's more servers to be queried for. | ||||
| // | ||||
| // The arg id specifies that only server with id at or above it will be included | ||||
| // in the result. The returned slice is up to a length of the arg maxResults or | ||||
| // EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||||
| func GetServers(id int64, maxResults int64) ([]*ServerMetric, bool) { | ||||
| 	return db.get().GetServers(id, maxResults) | ||||
| } | ||||
|  | ||||
| // GetServerSockets returns a slice of server's (identified by id) normal socket's | ||||
| // SocketMetric, along with a boolean indicating whether there's more sockets to | ||||
| // be queried for. | ||||
| // | ||||
| // The arg startID specifies that only sockets with id at or above it will be | ||||
| // included in the result. The returned slice is up to a length of the arg maxResults | ||||
| // or EntryPerPage if maxResults is zero, and is sorted in ascending id order. | ||||
| func GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) { | ||||
| 	return db.get().GetServerSockets(id, startID, maxResults) | ||||
| } | ||||
|  | ||||
| // GetChannel returns the ChannelMetric for the channel (identified by id). | ||||
| func GetChannel(id int64) *ChannelMetric { | ||||
| 	return db.get().GetChannel(id) | ||||
| } | ||||
|  | ||||
| // GetSubChannel returns the SubChannelMetric for the subchannel (identified by id). | ||||
| func GetSubChannel(id int64) *SubChannelMetric { | ||||
| 	return db.get().GetSubChannel(id) | ||||
| } | ||||
|  | ||||
| // GetSocket returns the SocketInternalMetric for the socket (identified by id). | ||||
| func GetSocket(id int64) *SocketMetric { | ||||
| 	return db.get().GetSocket(id) | ||||
| } | ||||
|  | ||||
| // GetServer returns the ServerMetric for the server (identified by id). | ||||
| func GetServer(id int64) *ServerMetric { | ||||
| 	return db.get().GetServer(id) | ||||
| } | ||||
|  | ||||
| // RegisterChannel registers the given channel c in channelz database with ref | ||||
| // as its reference name, and add it to the child list of its parent (identified | ||||
| // by pid). pid = 0 means no parent. It returns the unique channelz tracking id | ||||
| // assigned to this channel. | ||||
| func RegisterChannel(c Channel, pid int64, ref string) int64 { | ||||
| 	id := idGen.genID() | ||||
| 	cn := &channel{ | ||||
| 		refName:     ref, | ||||
| 		c:           c, | ||||
| 		subChans:    make(map[int64]string), | ||||
| 		nestedChans: make(map[int64]string), | ||||
| 		id:          id, | ||||
| 		pid:         pid, | ||||
| 		trace:       &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, | ||||
| 	} | ||||
| 	if pid == 0 { | ||||
| 		db.get().addChannel(id, cn, true, pid, ref) | ||||
| 	} else { | ||||
| 		db.get().addChannel(id, cn, false, pid, ref) | ||||
| 	} | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // RegisterSubChannel registers the given channel c in channelz database with ref | ||||
| // as its reference name, and add it to the child list of its parent (identified | ||||
| // by pid). It returns the unique channelz tracking id assigned to this subchannel. | ||||
| func RegisterSubChannel(c Channel, pid int64, ref string) int64 { | ||||
| 	if pid == 0 { | ||||
| 		grpclog.Error("a SubChannel's parent id cannot be 0") | ||||
| 		return 0 | ||||
| 	} | ||||
| 	id := idGen.genID() | ||||
| 	sc := &subChannel{ | ||||
| 		refName: ref, | ||||
| 		c:       c, | ||||
| 		sockets: make(map[int64]string), | ||||
| 		id:      id, | ||||
| 		pid:     pid, | ||||
| 		trace:   &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())}, | ||||
| 	} | ||||
| 	db.get().addSubChannel(id, sc, pid, ref) | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // RegisterServer registers the given server s in channelz database. It returns | ||||
| // the unique channelz tracking id assigned to this server. | ||||
| func RegisterServer(s Server, ref string) int64 { | ||||
| 	id := idGen.genID() | ||||
| 	svr := &server{ | ||||
| 		refName:       ref, | ||||
| 		s:             s, | ||||
| 		sockets:       make(map[int64]string), | ||||
| 		listenSockets: make(map[int64]string), | ||||
| 		id:            id, | ||||
| 	} | ||||
| 	db.get().addServer(id, svr) | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // RegisterListenSocket registers the given listen socket s in channelz database | ||||
| // with ref as its reference name, and add it to the child list of its parent | ||||
| // (identified by pid). It returns the unique channelz tracking id assigned to | ||||
| // this listen socket. | ||||
| func RegisterListenSocket(s Socket, pid int64, ref string) int64 { | ||||
| 	if pid == 0 { | ||||
| 		grpclog.Error("a ListenSocket's parent id cannot be 0") | ||||
| 		return 0 | ||||
| 	} | ||||
| 	id := idGen.genID() | ||||
| 	ls := &listenSocket{refName: ref, s: s, id: id, pid: pid} | ||||
| 	db.get().addListenSocket(id, ls, pid, ref) | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // RegisterNormalSocket registers the given normal socket s in channelz database | ||||
| // with ref as its reference name, and add it to the child list of its parent | ||||
| // (identified by pid). It returns the unique channelz tracking id assigned to | ||||
| // this normal socket. | ||||
| func RegisterNormalSocket(s Socket, pid int64, ref string) int64 { | ||||
| 	if pid == 0 { | ||||
| 		grpclog.Error("a NormalSocket's parent id cannot be 0") | ||||
| 		return 0 | ||||
| 	} | ||||
| 	id := idGen.genID() | ||||
| 	ns := &normalSocket{refName: ref, s: s, id: id, pid: pid} | ||||
| 	db.get().addNormalSocket(id, ns, pid, ref) | ||||
| 	return id | ||||
| } | ||||
|  | ||||
| // RemoveEntry removes an entry with unique channelz trakcing id to be id from | ||||
| // channelz database. | ||||
| func RemoveEntry(id int64) { | ||||
| 	db.get().removeEntry(id) | ||||
| } | ||||
|  | ||||
| // TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added | ||||
| // to the channel trace. | ||||
| // The Parent field is optional. It is used for event that will be recorded in the entity's parent | ||||
| // trace also. | ||||
| type TraceEventDesc struct { | ||||
| 	Desc     string | ||||
| 	Severity Severity | ||||
| 	Parent   *TraceEventDesc | ||||
| } | ||||
|  | ||||
| // AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc. | ||||
| func AddTraceEvent(id int64, desc *TraceEventDesc) { | ||||
| 	if getMaxTraceEntry() == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	db.get().traceEvent(id, desc) | ||||
| } | ||||
|  | ||||
| // channelMap is the storage data structure for channelz. | ||||
| // Methods of channelMap can be divided in two two categories with respect to locking. | ||||
| // 1. Methods acquire the global lock. | ||||
| // 2. Methods that can only be called when global lock is held. | ||||
| // A second type of method need always to be called inside a first type of method. | ||||
| type channelMap struct { | ||||
| 	mu               sync.RWMutex | ||||
| 	topLevelChannels map[int64]struct{} | ||||
| 	servers          map[int64]*server | ||||
| 	channels         map[int64]*channel | ||||
| 	subChannels      map[int64]*subChannel | ||||
| 	listenSockets    map[int64]*listenSocket | ||||
| 	normalSockets    map[int64]*normalSocket | ||||
| } | ||||
|  | ||||
| func (c *channelMap) addServer(id int64, s *server) { | ||||
| 	c.mu.Lock() | ||||
| 	s.cm = c | ||||
| 	c.servers[id] = s | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) { | ||||
| 	c.mu.Lock() | ||||
| 	cn.cm = c | ||||
| 	cn.trace.cm = c | ||||
| 	c.channels[id] = cn | ||||
| 	if isTopChannel { | ||||
| 		c.topLevelChannels[id] = struct{}{} | ||||
| 	} else { | ||||
| 		c.findEntry(pid).addChild(id, cn) | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) { | ||||
| 	c.mu.Lock() | ||||
| 	sc.cm = c | ||||
| 	sc.trace.cm = c | ||||
| 	c.subChannels[id] = sc | ||||
| 	c.findEntry(pid).addChild(id, sc) | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64, ref string) { | ||||
| 	c.mu.Lock() | ||||
| 	ls.cm = c | ||||
| 	c.listenSockets[id] = ls | ||||
| 	c.findEntry(pid).addChild(id, ls) | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref string) { | ||||
| 	c.mu.Lock() | ||||
| 	ns.cm = c | ||||
| 	c.normalSockets[id] = ns | ||||
| 	c.findEntry(pid).addChild(id, ns) | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| // removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to | ||||
| // wait on the deletion of its children and until no other entity's channel trace references it. | ||||
| // It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully | ||||
| // shutting down server will lead to the server being also deleted. | ||||
| func (c *channelMap) removeEntry(id int64) { | ||||
| 	c.mu.Lock() | ||||
| 	c.findEntry(id).triggerDelete() | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| // c.mu must be held by the caller | ||||
| func (c *channelMap) decrTraceRefCount(id int64) { | ||||
| 	e := c.findEntry(id) | ||||
| 	if v, ok := e.(tracedChannel); ok { | ||||
| 		v.decrTraceRefCount() | ||||
| 		e.deleteSelfIfReady() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // c.mu must be held by the caller. | ||||
| func (c *channelMap) findEntry(id int64) entry { | ||||
| 	var v entry | ||||
| 	var ok bool | ||||
| 	if v, ok = c.channels[id]; ok { | ||||
| 		return v | ||||
| 	} | ||||
| 	if v, ok = c.subChannels[id]; ok { | ||||
| 		return v | ||||
| 	} | ||||
| 	if v, ok = c.servers[id]; ok { | ||||
| 		return v | ||||
| 	} | ||||
| 	if v, ok = c.listenSockets[id]; ok { | ||||
| 		return v | ||||
| 	} | ||||
| 	if v, ok = c.normalSockets[id]; ok { | ||||
| 		return v | ||||
| 	} | ||||
| 	return &dummyEntry{idNotFound: id} | ||||
| } | ||||
|  | ||||
| // c.mu must be held by the caller | ||||
| // deleteEntry simply deletes an entry from the channelMap. Before calling this | ||||
| // method, caller must check this entry is ready to be deleted, i.e removeEntry() | ||||
| // has been called on it, and no children still exist. | ||||
| // Conditionals are ordered by the expected frequency of deletion of each entity | ||||
| // type, in order to optimize performance. | ||||
| func (c *channelMap) deleteEntry(id int64) { | ||||
| 	var ok bool | ||||
| 	if _, ok = c.normalSockets[id]; ok { | ||||
| 		delete(c.normalSockets, id) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, ok = c.subChannels[id]; ok { | ||||
| 		delete(c.subChannels, id) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, ok = c.channels[id]; ok { | ||||
| 		delete(c.channels, id) | ||||
| 		delete(c.topLevelChannels, id) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, ok = c.listenSockets[id]; ok { | ||||
| 		delete(c.listenSockets, id) | ||||
| 		return | ||||
| 	} | ||||
| 	if _, ok = c.servers[id]; ok { | ||||
| 		delete(c.servers, id) | ||||
| 		return | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) { | ||||
| 	c.mu.Lock() | ||||
| 	child := c.findEntry(id) | ||||
| 	childTC, ok := child.(tracedChannel) | ||||
| 	if !ok { | ||||
| 		c.mu.Unlock() | ||||
| 		return | ||||
| 	} | ||||
| 	childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()}) | ||||
| 	if desc.Parent != nil { | ||||
| 		parent := c.findEntry(child.getParentID()) | ||||
| 		var chanType RefChannelType | ||||
| 		switch child.(type) { | ||||
| 		case *channel: | ||||
| 			chanType = RefChannel | ||||
| 		case *subChannel: | ||||
| 			chanType = RefSubChannel | ||||
| 		} | ||||
| 		if parentTC, ok := parent.(tracedChannel); ok { | ||||
| 			parentTC.getChannelTrace().append(&TraceEvent{ | ||||
| 				Desc:      desc.Parent.Desc, | ||||
| 				Severity:  desc.Parent.Severity, | ||||
| 				Timestamp: time.Now(), | ||||
| 				RefID:     id, | ||||
| 				RefName:   childTC.getRefName(), | ||||
| 				RefType:   chanType, | ||||
| 			}) | ||||
| 			childTC.incrTraceRefCount() | ||||
| 		} | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| type int64Slice []int64 | ||||
|  | ||||
| func (s int64Slice) Len() int           { return len(s) } | ||||
| func (s int64Slice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } | ||||
| func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] } | ||||
|  | ||||
| func copyMap(m map[int64]string) map[int64]string { | ||||
| 	n := make(map[int64]string) | ||||
| 	for k, v := range m { | ||||
| 		n[k] = v | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
|  | ||||
| func min(a, b int64) int64 { | ||||
| 	if a < b { | ||||
| 		return a | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetTopChannels(id int64, maxResults int64) ([]*ChannelMetric, bool) { | ||||
| 	if maxResults <= 0 { | ||||
| 		maxResults = EntryPerPage | ||||
| 	} | ||||
| 	c.mu.RLock() | ||||
| 	l := int64(len(c.topLevelChannels)) | ||||
| 	ids := make([]int64, 0, l) | ||||
| 	cns := make([]*channel, 0, min(l, maxResults)) | ||||
|  | ||||
| 	for k := range c.topLevelChannels { | ||||
| 		ids = append(ids, k) | ||||
| 	} | ||||
| 	sort.Sort(int64Slice(ids)) | ||||
| 	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id }) | ||||
| 	count := int64(0) | ||||
| 	var end bool | ||||
| 	var t []*ChannelMetric | ||||
| 	for i, v := range ids[idx:] { | ||||
| 		if count == maxResults { | ||||
| 			break | ||||
| 		} | ||||
| 		if cn, ok := c.channels[v]; ok { | ||||
| 			cns = append(cns, cn) | ||||
| 			t = append(t, &ChannelMetric{ | ||||
| 				NestedChans: copyMap(cn.nestedChans), | ||||
| 				SubChans:    copyMap(cn.subChans), | ||||
| 			}) | ||||
| 			count++ | ||||
| 		} | ||||
| 		if i == len(ids[idx:])-1 { | ||||
| 			end = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 	if count == 0 { | ||||
| 		end = true | ||||
| 	} | ||||
|  | ||||
| 	for i, cn := range cns { | ||||
| 		t[i].ChannelData = cn.c.ChannelzMetric() | ||||
| 		t[i].ID = cn.id | ||||
| 		t[i].RefName = cn.refName | ||||
| 		t[i].Trace = cn.trace.dumpData() | ||||
| 	} | ||||
| 	return t, end | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetServers(id, maxResults int64) ([]*ServerMetric, bool) { | ||||
| 	if maxResults <= 0 { | ||||
| 		maxResults = EntryPerPage | ||||
| 	} | ||||
| 	c.mu.RLock() | ||||
| 	l := int64(len(c.servers)) | ||||
| 	ids := make([]int64, 0, l) | ||||
| 	ss := make([]*server, 0, min(l, maxResults)) | ||||
| 	for k := range c.servers { | ||||
| 		ids = append(ids, k) | ||||
| 	} | ||||
| 	sort.Sort(int64Slice(ids)) | ||||
| 	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id }) | ||||
| 	count := int64(0) | ||||
| 	var end bool | ||||
| 	var s []*ServerMetric | ||||
| 	for i, v := range ids[idx:] { | ||||
| 		if count == maxResults { | ||||
| 			break | ||||
| 		} | ||||
| 		if svr, ok := c.servers[v]; ok { | ||||
| 			ss = append(ss, svr) | ||||
| 			s = append(s, &ServerMetric{ | ||||
| 				ListenSockets: copyMap(svr.listenSockets), | ||||
| 			}) | ||||
| 			count++ | ||||
| 		} | ||||
| 		if i == len(ids[idx:])-1 { | ||||
| 			end = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 	if count == 0 { | ||||
| 		end = true | ||||
| 	} | ||||
|  | ||||
| 	for i, svr := range ss { | ||||
| 		s[i].ServerData = svr.s.ChannelzMetric() | ||||
| 		s[i].ID = svr.id | ||||
| 		s[i].RefName = svr.refName | ||||
| 	} | ||||
| 	return s, end | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetServerSockets(id int64, startID int64, maxResults int64) ([]*SocketMetric, bool) { | ||||
| 	if maxResults <= 0 { | ||||
| 		maxResults = EntryPerPage | ||||
| 	} | ||||
| 	var svr *server | ||||
| 	var ok bool | ||||
| 	c.mu.RLock() | ||||
| 	if svr, ok = c.servers[id]; !ok { | ||||
| 		// server with id doesn't exist. | ||||
| 		c.mu.RUnlock() | ||||
| 		return nil, true | ||||
| 	} | ||||
| 	svrskts := svr.sockets | ||||
| 	l := int64(len(svrskts)) | ||||
| 	ids := make([]int64, 0, l) | ||||
| 	sks := make([]*normalSocket, 0, min(l, maxResults)) | ||||
| 	for k := range svrskts { | ||||
| 		ids = append(ids, k) | ||||
| 	} | ||||
| 	sort.Sort(int64Slice(ids)) | ||||
| 	idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= startID }) | ||||
| 	count := int64(0) | ||||
| 	var end bool | ||||
| 	for i, v := range ids[idx:] { | ||||
| 		if count == maxResults { | ||||
| 			break | ||||
| 		} | ||||
| 		if ns, ok := c.normalSockets[v]; ok { | ||||
| 			sks = append(sks, ns) | ||||
| 			count++ | ||||
| 		} | ||||
| 		if i == len(ids[idx:])-1 { | ||||
| 			end = true | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 	if count == 0 { | ||||
| 		end = true | ||||
| 	} | ||||
| 	var s []*SocketMetric | ||||
| 	for _, ns := range sks { | ||||
| 		sm := &SocketMetric{} | ||||
| 		sm.SocketData = ns.s.ChannelzMetric() | ||||
| 		sm.ID = ns.id | ||||
| 		sm.RefName = ns.refName | ||||
| 		s = append(s, sm) | ||||
| 	} | ||||
| 	return s, end | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetChannel(id int64) *ChannelMetric { | ||||
| 	cm := &ChannelMetric{} | ||||
| 	var cn *channel | ||||
| 	var ok bool | ||||
| 	c.mu.RLock() | ||||
| 	if cn, ok = c.channels[id]; !ok { | ||||
| 		// channel with id doesn't exist. | ||||
| 		c.mu.RUnlock() | ||||
| 		return nil | ||||
| 	} | ||||
| 	cm.NestedChans = copyMap(cn.nestedChans) | ||||
| 	cm.SubChans = copyMap(cn.subChans) | ||||
| 	// cn.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of cn.c when | ||||
| 	// holding the lock to prevent potential data race. | ||||
| 	chanCopy := cn.c | ||||
| 	c.mu.RUnlock() | ||||
| 	cm.ChannelData = chanCopy.ChannelzMetric() | ||||
| 	cm.ID = cn.id | ||||
| 	cm.RefName = cn.refName | ||||
| 	cm.Trace = cn.trace.dumpData() | ||||
| 	return cm | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric { | ||||
| 	cm := &SubChannelMetric{} | ||||
| 	var sc *subChannel | ||||
| 	var ok bool | ||||
| 	c.mu.RLock() | ||||
| 	if sc, ok = c.subChannels[id]; !ok { | ||||
| 		// subchannel with id doesn't exist. | ||||
| 		c.mu.RUnlock() | ||||
| 		return nil | ||||
| 	} | ||||
| 	cm.Sockets = copyMap(sc.sockets) | ||||
| 	// sc.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of sc.c when | ||||
| 	// holding the lock to prevent potential data race. | ||||
| 	chanCopy := sc.c | ||||
| 	c.mu.RUnlock() | ||||
| 	cm.ChannelData = chanCopy.ChannelzMetric() | ||||
| 	cm.ID = sc.id | ||||
| 	cm.RefName = sc.refName | ||||
| 	cm.Trace = sc.trace.dumpData() | ||||
| 	return cm | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetSocket(id int64) *SocketMetric { | ||||
| 	sm := &SocketMetric{} | ||||
| 	c.mu.RLock() | ||||
| 	if ls, ok := c.listenSockets[id]; ok { | ||||
| 		c.mu.RUnlock() | ||||
| 		sm.SocketData = ls.s.ChannelzMetric() | ||||
| 		sm.ID = ls.id | ||||
| 		sm.RefName = ls.refName | ||||
| 		return sm | ||||
| 	} | ||||
| 	if ns, ok := c.normalSockets[id]; ok { | ||||
| 		c.mu.RUnlock() | ||||
| 		sm.SocketData = ns.s.ChannelzMetric() | ||||
| 		sm.ID = ns.id | ||||
| 		sm.RefName = ns.refName | ||||
| 		return sm | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *channelMap) GetServer(id int64) *ServerMetric { | ||||
| 	sm := &ServerMetric{} | ||||
| 	var svr *server | ||||
| 	var ok bool | ||||
| 	c.mu.RLock() | ||||
| 	if svr, ok = c.servers[id]; !ok { | ||||
| 		c.mu.RUnlock() | ||||
| 		return nil | ||||
| 	} | ||||
| 	sm.ListenSockets = copyMap(svr.listenSockets) | ||||
| 	c.mu.RUnlock() | ||||
| 	sm.ID = svr.id | ||||
| 	sm.RefName = svr.refName | ||||
| 	sm.ServerData = svr.s.ChannelzMetric() | ||||
| 	return sm | ||||
| } | ||||
|  | ||||
| type idGenerator struct { | ||||
| 	id int64 | ||||
| } | ||||
|  | ||||
| func (i *idGenerator) reset() { | ||||
| 	atomic.StoreInt64(&i.id, 0) | ||||
| } | ||||
|  | ||||
| func (i *idGenerator) genID() int64 { | ||||
| 	return atomic.AddInt64(&i.id, 1) | ||||
| } | ||||
							
								
								
									
										702
									
								
								vendor/google.golang.org/grpc/internal/channelz/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										702
									
								
								vendor/google.golang.org/grpc/internal/channelz/types.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,702 @@ | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| package channelz | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | ||||
| 	"google.golang.org/grpc/connectivity" | ||||
| 	"google.golang.org/grpc/credentials" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| ) | ||||
|  | ||||
| // entry represents a node in the channelz database. | ||||
| type entry interface { | ||||
| 	// addChild adds a child e, whose channelz id is id to child list | ||||
| 	addChild(id int64, e entry) | ||||
| 	// deleteChild deletes a child with channelz id to be id from child list | ||||
| 	deleteChild(id int64) | ||||
| 	// triggerDelete tries to delete self from channelz database. However, if child | ||||
| 	// list is not empty, then deletion from the database is on hold until the last | ||||
| 	// child is deleted from database. | ||||
| 	triggerDelete() | ||||
| 	// deleteSelfIfReady check whether triggerDelete() has been called before, and whether child | ||||
| 	// list is now empty. If both conditions are met, then delete self from database. | ||||
| 	deleteSelfIfReady() | ||||
| 	// getParentID returns parent ID of the entry. 0 value parent ID means no parent. | ||||
| 	getParentID() int64 | ||||
| } | ||||
|  | ||||
| // dummyEntry is a fake entry to handle entry not found case. | ||||
| type dummyEntry struct { | ||||
| 	idNotFound int64 | ||||
| } | ||||
|  | ||||
| func (d *dummyEntry) addChild(id int64, e entry) { | ||||
| 	// Note: It is possible for a normal program to reach here under race condition. | ||||
| 	// For example, there could be a race between ClientConn.Close() info being propagated | ||||
| 	// to addrConn and http2Client. ClientConn.Close() cancel the context and result | ||||
| 	// in http2Client to error. The error info is then caught by transport monitor | ||||
| 	// and before addrConn.tearDown() is called in side ClientConn.Close(). Therefore, | ||||
| 	// the addrConn will create a new transport. And when registering the new transport in | ||||
| 	// channelz, its parent addrConn could have already been torn down and deleted | ||||
| 	// from channelz tracking, and thus reach the code here. | ||||
| 	grpclog.Infof("attempt to add child of type %T with id %d to a parent (id=%d) that doesn't currently exist", e, id, d.idNotFound) | ||||
| } | ||||
|  | ||||
| func (d *dummyEntry) deleteChild(id int64) { | ||||
| 	// It is possible for a normal program to reach here under race condition. | ||||
| 	// Refer to the example described in addChild(). | ||||
| 	grpclog.Infof("attempt to delete child with id %d from a parent (id=%d) that doesn't currently exist", id, d.idNotFound) | ||||
| } | ||||
|  | ||||
| func (d *dummyEntry) triggerDelete() { | ||||
| 	grpclog.Warningf("attempt to delete an entry (id=%d) that doesn't currently exist", d.idNotFound) | ||||
| } | ||||
|  | ||||
| func (*dummyEntry) deleteSelfIfReady() { | ||||
| 	// code should not reach here. deleteSelfIfReady is always called on an existing entry. | ||||
| } | ||||
|  | ||||
| func (*dummyEntry) getParentID() int64 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // ChannelMetric defines the info channelz provides for a specific Channel, which | ||||
| // includes ChannelInternalMetric and channelz-specific data, such as channelz id, | ||||
| // child list, etc. | ||||
| type ChannelMetric struct { | ||||
| 	// ID is the channelz id of this channel. | ||||
| 	ID int64 | ||||
| 	// RefName is the human readable reference string of this channel. | ||||
| 	RefName string | ||||
| 	// ChannelData contains channel internal metric reported by the channel through | ||||
| 	// ChannelzMetric(). | ||||
| 	ChannelData *ChannelInternalMetric | ||||
| 	// NestedChans tracks the nested channel type children of this channel in the format of | ||||
| 	// a map from nested channel channelz id to corresponding reference string. | ||||
| 	NestedChans map[int64]string | ||||
| 	// SubChans tracks the subchannel type children of this channel in the format of a | ||||
| 	// map from subchannel channelz id to corresponding reference string. | ||||
| 	SubChans map[int64]string | ||||
| 	// Sockets tracks the socket type children of this channel in the format of a map | ||||
| 	// from socket channelz id to corresponding reference string. | ||||
| 	// Note current grpc implementation doesn't allow channel having sockets directly, | ||||
| 	// therefore, this is field is unused. | ||||
| 	Sockets map[int64]string | ||||
| 	// Trace contains the most recent traced events. | ||||
| 	Trace *ChannelTrace | ||||
| } | ||||
|  | ||||
| // SubChannelMetric defines the info channelz provides for a specific SubChannel, | ||||
| // which includes ChannelInternalMetric and channelz-specific data, such as | ||||
| // channelz id, child list, etc. | ||||
| type SubChannelMetric struct { | ||||
| 	// ID is the channelz id of this subchannel. | ||||
| 	ID int64 | ||||
| 	// RefName is the human readable reference string of this subchannel. | ||||
| 	RefName string | ||||
| 	// ChannelData contains subchannel internal metric reported by the subchannel | ||||
| 	// through ChannelzMetric(). | ||||
| 	ChannelData *ChannelInternalMetric | ||||
| 	// NestedChans tracks the nested channel type children of this subchannel in the format of | ||||
| 	// a map from nested channel channelz id to corresponding reference string. | ||||
| 	// Note current grpc implementation doesn't allow subchannel to have nested channels | ||||
| 	// as children, therefore, this field is unused. | ||||
| 	NestedChans map[int64]string | ||||
| 	// SubChans tracks the subchannel type children of this subchannel in the format of a | ||||
| 	// map from subchannel channelz id to corresponding reference string. | ||||
| 	// Note current grpc implementation doesn't allow subchannel to have subchannels | ||||
| 	// as children, therefore, this field is unused. | ||||
| 	SubChans map[int64]string | ||||
| 	// Sockets tracks the socket type children of this subchannel in the format of a map | ||||
| 	// from socket channelz id to corresponding reference string. | ||||
| 	Sockets map[int64]string | ||||
| 	// Trace contains the most recent traced events. | ||||
| 	Trace *ChannelTrace | ||||
| } | ||||
|  | ||||
| // ChannelInternalMetric defines the struct that the implementor of Channel interface | ||||
| // should return from ChannelzMetric(). | ||||
| type ChannelInternalMetric struct { | ||||
| 	// current connectivity state of the channel. | ||||
| 	State connectivity.State | ||||
| 	// The target this channel originally tried to connect to.  May be absent | ||||
| 	Target string | ||||
| 	// The number of calls started on the channel. | ||||
| 	CallsStarted int64 | ||||
| 	// The number of calls that have completed with an OK status. | ||||
| 	CallsSucceeded int64 | ||||
| 	// The number of calls that have a completed with a non-OK status. | ||||
| 	CallsFailed int64 | ||||
| 	// The last time a call was started on the channel. | ||||
| 	LastCallStartedTimestamp time.Time | ||||
| } | ||||
|  | ||||
| // ChannelTrace stores traced events on a channel/subchannel and related info. | ||||
| type ChannelTrace struct { | ||||
| 	// EventNum is the number of events that ever got traced (i.e. including those that have been deleted) | ||||
| 	EventNum int64 | ||||
| 	// CreationTime is the creation time of the trace. | ||||
| 	CreationTime time.Time | ||||
| 	// Events stores the most recent trace events (up to $maxTraceEntry, newer event will overwrite the | ||||
| 	// oldest one) | ||||
| 	Events []*TraceEvent | ||||
| } | ||||
|  | ||||
| // TraceEvent represent a single trace event | ||||
| type TraceEvent struct { | ||||
| 	// Desc is a simple description of the trace event. | ||||
| 	Desc string | ||||
| 	// Severity states the severity of this trace event. | ||||
| 	Severity Severity | ||||
| 	// Timestamp is the event time. | ||||
| 	Timestamp time.Time | ||||
| 	// RefID is the id of the entity that gets referenced in the event. RefID is 0 if no other entity is | ||||
| 	// involved in this event. | ||||
| 	// e.g. SubChannel (id: 4[]) Created. --> RefID = 4, RefName = "" (inside []) | ||||
| 	RefID int64 | ||||
| 	// RefName is the reference name for the entity that gets referenced in the event. | ||||
| 	RefName string | ||||
| 	// RefType indicates the referenced entity type, i.e Channel or SubChannel. | ||||
| 	RefType RefChannelType | ||||
| } | ||||
|  | ||||
| // Channel is the interface that should be satisfied in order to be tracked by | ||||
| // channelz as Channel or SubChannel. | ||||
| type Channel interface { | ||||
| 	ChannelzMetric() *ChannelInternalMetric | ||||
| } | ||||
|  | ||||
| type dummyChannel struct{} | ||||
|  | ||||
| func (d *dummyChannel) ChannelzMetric() *ChannelInternalMetric { | ||||
| 	return &ChannelInternalMetric{} | ||||
| } | ||||
|  | ||||
| type channel struct { | ||||
| 	refName     string | ||||
| 	c           Channel | ||||
| 	closeCalled bool | ||||
| 	nestedChans map[int64]string | ||||
| 	subChans    map[int64]string | ||||
| 	id          int64 | ||||
| 	pid         int64 | ||||
| 	cm          *channelMap | ||||
| 	trace       *channelTrace | ||||
| 	// traceRefCount is the number of trace events that reference this channel. | ||||
| 	// Non-zero traceRefCount means the trace of this channel cannot be deleted. | ||||
| 	traceRefCount int32 | ||||
| } | ||||
|  | ||||
| func (c *channel) addChild(id int64, e entry) { | ||||
| 	switch v := e.(type) { | ||||
| 	case *subChannel: | ||||
| 		c.subChans[id] = v.refName | ||||
| 	case *channel: | ||||
| 		c.nestedChans[id] = v.refName | ||||
| 	default: | ||||
| 		grpclog.Errorf("cannot add a child (id = %d) of type %T to a channel", id, e) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *channel) deleteChild(id int64) { | ||||
| 	delete(c.subChans, id) | ||||
| 	delete(c.nestedChans, id) | ||||
| 	c.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (c *channel) triggerDelete() { | ||||
| 	c.closeCalled = true | ||||
| 	c.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (c *channel) getParentID() int64 { | ||||
| 	return c.pid | ||||
| } | ||||
|  | ||||
| // deleteSelfFromTree tries to delete the channel from the channelz entry relation tree, which means | ||||
| // deleting the channel reference from its parent's child list. | ||||
| // | ||||
| // In order for a channel to be deleted from the tree, it must meet the criteria that, removal of the | ||||
| // corresponding grpc object has been invoked, and the channel does not have any children left. | ||||
| // | ||||
| // The returned boolean value indicates whether the channel has been successfully deleted from tree. | ||||
| func (c *channel) deleteSelfFromTree() (deleted bool) { | ||||
| 	if !c.closeCalled || len(c.subChans)+len(c.nestedChans) != 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	// not top channel | ||||
| 	if c.pid != 0 { | ||||
| 		c.cm.findEntry(c.pid).deleteChild(c.id) | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // deleteSelfFromMap checks whether it is valid to delete the channel from the map, which means | ||||
| // deleting the channel from channelz's tracking entirely. Users can no longer use id to query the | ||||
| // channel, and its memory will be garbage collected. | ||||
| // | ||||
| // The trace reference count of the channel must be 0 in order to be deleted from the map. This is | ||||
| // specified in the channel tracing gRFC that as long as some other trace has reference to an entity, | ||||
| // the trace of the referenced entity must not be deleted. In order to release the resource allocated | ||||
| // by grpc, the reference to the grpc object is reset to a dummy object. | ||||
| // | ||||
| // deleteSelfFromMap must be called after deleteSelfFromTree returns true. | ||||
| // | ||||
| // It returns a bool to indicate whether the channel can be safely deleted from map. | ||||
| func (c *channel) deleteSelfFromMap() (delete bool) { | ||||
| 	if c.getTraceRefCount() != 0 { | ||||
| 		c.c = &dummyChannel{} | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // deleteSelfIfReady tries to delete the channel itself from the channelz database. | ||||
| // The delete process includes two steps: | ||||
| // 1. delete the channel from the entry relation tree, i.e. delete the channel reference from its | ||||
| //    parent's child list. | ||||
| // 2. delete the channel from the map, i.e. delete the channel entirely from channelz. Lookup by id | ||||
| //    will return entry not found error. | ||||
| func (c *channel) deleteSelfIfReady() { | ||||
| 	if !c.deleteSelfFromTree() { | ||||
| 		return | ||||
| 	} | ||||
| 	if !c.deleteSelfFromMap() { | ||||
| 		return | ||||
| 	} | ||||
| 	c.cm.deleteEntry(c.id) | ||||
| 	c.trace.clear() | ||||
| } | ||||
|  | ||||
| func (c *channel) getChannelTrace() *channelTrace { | ||||
| 	return c.trace | ||||
| } | ||||
|  | ||||
| func (c *channel) incrTraceRefCount() { | ||||
| 	atomic.AddInt32(&c.traceRefCount, 1) | ||||
| } | ||||
|  | ||||
| func (c *channel) decrTraceRefCount() { | ||||
| 	atomic.AddInt32(&c.traceRefCount, -1) | ||||
| } | ||||
|  | ||||
| func (c *channel) getTraceRefCount() int { | ||||
| 	i := atomic.LoadInt32(&c.traceRefCount) | ||||
| 	return int(i) | ||||
| } | ||||
|  | ||||
| func (c *channel) getRefName() string { | ||||
| 	return c.refName | ||||
| } | ||||
|  | ||||
| type subChannel struct { | ||||
| 	refName       string | ||||
| 	c             Channel | ||||
| 	closeCalled   bool | ||||
| 	sockets       map[int64]string | ||||
| 	id            int64 | ||||
| 	pid           int64 | ||||
| 	cm            *channelMap | ||||
| 	trace         *channelTrace | ||||
| 	traceRefCount int32 | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) addChild(id int64, e entry) { | ||||
| 	if v, ok := e.(*normalSocket); ok { | ||||
| 		sc.sockets[id] = v.refName | ||||
| 	} else { | ||||
| 		grpclog.Errorf("cannot add a child (id = %d) of type %T to a subChannel", id, e) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) deleteChild(id int64) { | ||||
| 	delete(sc.sockets, id) | ||||
| 	sc.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) triggerDelete() { | ||||
| 	sc.closeCalled = true | ||||
| 	sc.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) getParentID() int64 { | ||||
| 	return sc.pid | ||||
| } | ||||
|  | ||||
| // deleteSelfFromTree tries to delete the subchannel from the channelz entry relation tree, which | ||||
| // means deleting the subchannel reference from its parent's child list. | ||||
| // | ||||
| // In order for a subchannel to be deleted from the tree, it must meet the criteria that, removal of | ||||
| // the corresponding grpc object has been invoked, and the subchannel does not have any children left. | ||||
| // | ||||
| // The returned boolean value indicates whether the channel has been successfully deleted from tree. | ||||
| func (sc *subChannel) deleteSelfFromTree() (deleted bool) { | ||||
| 	if !sc.closeCalled || len(sc.sockets) != 0 { | ||||
| 		return false | ||||
| 	} | ||||
| 	sc.cm.findEntry(sc.pid).deleteChild(sc.id) | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // deleteSelfFromMap checks whether it is valid to delete the subchannel from the map, which means | ||||
| // deleting the subchannel from channelz's tracking entirely. Users can no longer use id to query | ||||
| // the subchannel, and its memory will be garbage collected. | ||||
| // | ||||
| // The trace reference count of the subchannel must be 0 in order to be deleted from the map. This is | ||||
| // specified in the channel tracing gRFC that as long as some other trace has reference to an entity, | ||||
| // the trace of the referenced entity must not be deleted. In order to release the resource allocated | ||||
| // by grpc, the reference to the grpc object is reset to a dummy object. | ||||
| // | ||||
| // deleteSelfFromMap must be called after deleteSelfFromTree returns true. | ||||
| // | ||||
| // It returns a bool to indicate whether the channel can be safely deleted from map. | ||||
| func (sc *subChannel) deleteSelfFromMap() (delete bool) { | ||||
| 	if sc.getTraceRefCount() != 0 { | ||||
| 		// free the grpc struct (i.e. addrConn) | ||||
| 		sc.c = &dummyChannel{} | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // deleteSelfIfReady tries to delete the subchannel itself from the channelz database. | ||||
| // The delete process includes two steps: | ||||
| // 1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from | ||||
| //    its parent's child list. | ||||
| // 2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup | ||||
| //    by id will return entry not found error. | ||||
| func (sc *subChannel) deleteSelfIfReady() { | ||||
| 	if !sc.deleteSelfFromTree() { | ||||
| 		return | ||||
| 	} | ||||
| 	if !sc.deleteSelfFromMap() { | ||||
| 		return | ||||
| 	} | ||||
| 	sc.cm.deleteEntry(sc.id) | ||||
| 	sc.trace.clear() | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) getChannelTrace() *channelTrace { | ||||
| 	return sc.trace | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) incrTraceRefCount() { | ||||
| 	atomic.AddInt32(&sc.traceRefCount, 1) | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) decrTraceRefCount() { | ||||
| 	atomic.AddInt32(&sc.traceRefCount, -1) | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) getTraceRefCount() int { | ||||
| 	i := atomic.LoadInt32(&sc.traceRefCount) | ||||
| 	return int(i) | ||||
| } | ||||
|  | ||||
| func (sc *subChannel) getRefName() string { | ||||
| 	return sc.refName | ||||
| } | ||||
|  | ||||
| // SocketMetric defines the info channelz provides for a specific Socket, which | ||||
| // includes SocketInternalMetric and channelz-specific data, such as channelz id, etc. | ||||
| type SocketMetric struct { | ||||
| 	// ID is the channelz id of this socket. | ||||
| 	ID int64 | ||||
| 	// RefName is the human readable reference string of this socket. | ||||
| 	RefName string | ||||
| 	// SocketData contains socket internal metric reported by the socket through | ||||
| 	// ChannelzMetric(). | ||||
| 	SocketData *SocketInternalMetric | ||||
| } | ||||
|  | ||||
| // SocketInternalMetric defines the struct that the implementor of Socket interface | ||||
| // should return from ChannelzMetric(). | ||||
| type SocketInternalMetric struct { | ||||
| 	// The number of streams that have been started. | ||||
| 	StreamsStarted int64 | ||||
| 	// The number of streams that have ended successfully: | ||||
| 	// On client side, receiving frame with eos bit set. | ||||
| 	// On server side, sending frame with eos bit set. | ||||
| 	StreamsSucceeded int64 | ||||
| 	// The number of streams that have ended unsuccessfully: | ||||
| 	// On client side, termination without receiving frame with eos bit set. | ||||
| 	// On server side, termination without sending frame with eos bit set. | ||||
| 	StreamsFailed int64 | ||||
| 	// The number of messages successfully sent on this socket. | ||||
| 	MessagesSent     int64 | ||||
| 	MessagesReceived int64 | ||||
| 	// The number of keep alives sent.  This is typically implemented with HTTP/2 | ||||
| 	// ping messages. | ||||
| 	KeepAlivesSent int64 | ||||
| 	// The last time a stream was created by this endpoint.  Usually unset for | ||||
| 	// servers. | ||||
| 	LastLocalStreamCreatedTimestamp time.Time | ||||
| 	// The last time a stream was created by the remote endpoint.  Usually unset | ||||
| 	// for clients. | ||||
| 	LastRemoteStreamCreatedTimestamp time.Time | ||||
| 	// The last time a message was sent by this endpoint. | ||||
| 	LastMessageSentTimestamp time.Time | ||||
| 	// The last time a message was received by this endpoint. | ||||
| 	LastMessageReceivedTimestamp time.Time | ||||
| 	// The amount of window, granted to the local endpoint by the remote endpoint. | ||||
| 	// This may be slightly out of date due to network latency.  This does NOT | ||||
| 	// include stream level or TCP level flow control info. | ||||
| 	LocalFlowControlWindow int64 | ||||
| 	// The amount of window, granted to the remote endpoint by the local endpoint. | ||||
| 	// This may be slightly out of date due to network latency.  This does NOT | ||||
| 	// include stream level or TCP level flow control info. | ||||
| 	RemoteFlowControlWindow int64 | ||||
| 	// The locally bound address. | ||||
| 	LocalAddr net.Addr | ||||
| 	// The remote bound address.  May be absent. | ||||
| 	RemoteAddr net.Addr | ||||
| 	// Optional, represents the name of the remote endpoint, if different than | ||||
| 	// the original target name. | ||||
| 	RemoteName    string | ||||
| 	SocketOptions *SocketOptionData | ||||
| 	Security      credentials.ChannelzSecurityValue | ||||
| } | ||||
|  | ||||
| // Socket is the interface that should be satisfied in order to be tracked by | ||||
| // channelz as Socket. | ||||
| type Socket interface { | ||||
| 	ChannelzMetric() *SocketInternalMetric | ||||
| } | ||||
|  | ||||
| type listenSocket struct { | ||||
| 	refName string | ||||
| 	s       Socket | ||||
| 	id      int64 | ||||
| 	pid     int64 | ||||
| 	cm      *channelMap | ||||
| } | ||||
|  | ||||
| func (ls *listenSocket) addChild(id int64, e entry) { | ||||
| 	grpclog.Errorf("cannot add a child (id = %d) of type %T to a listen socket", id, e) | ||||
| } | ||||
|  | ||||
| func (ls *listenSocket) deleteChild(id int64) { | ||||
| 	grpclog.Errorf("cannot delete a child (id = %d) from a listen socket", id) | ||||
| } | ||||
|  | ||||
| func (ls *listenSocket) triggerDelete() { | ||||
| 	ls.cm.deleteEntry(ls.id) | ||||
| 	ls.cm.findEntry(ls.pid).deleteChild(ls.id) | ||||
| } | ||||
|  | ||||
| func (ls *listenSocket) deleteSelfIfReady() { | ||||
| 	grpclog.Errorf("cannot call deleteSelfIfReady on a listen socket") | ||||
| } | ||||
|  | ||||
| func (ls *listenSocket) getParentID() int64 { | ||||
| 	return ls.pid | ||||
| } | ||||
|  | ||||
| type normalSocket struct { | ||||
| 	refName string | ||||
| 	s       Socket | ||||
| 	id      int64 | ||||
| 	pid     int64 | ||||
| 	cm      *channelMap | ||||
| } | ||||
|  | ||||
| func (ns *normalSocket) addChild(id int64, e entry) { | ||||
| 	grpclog.Errorf("cannot add a child (id = %d) of type %T to a normal socket", id, e) | ||||
| } | ||||
|  | ||||
| func (ns *normalSocket) deleteChild(id int64) { | ||||
| 	grpclog.Errorf("cannot delete a child (id = %d) from a normal socket", id) | ||||
| } | ||||
|  | ||||
| func (ns *normalSocket) triggerDelete() { | ||||
| 	ns.cm.deleteEntry(ns.id) | ||||
| 	ns.cm.findEntry(ns.pid).deleteChild(ns.id) | ||||
| } | ||||
|  | ||||
| func (ns *normalSocket) deleteSelfIfReady() { | ||||
| 	grpclog.Errorf("cannot call deleteSelfIfReady on a normal socket") | ||||
| } | ||||
|  | ||||
| func (ns *normalSocket) getParentID() int64 { | ||||
| 	return ns.pid | ||||
| } | ||||
|  | ||||
| // ServerMetric defines the info channelz provides for a specific Server, which | ||||
| // includes ServerInternalMetric and channelz-specific data, such as channelz id, | ||||
| // child list, etc. | ||||
| type ServerMetric struct { | ||||
| 	// ID is the channelz id of this server. | ||||
| 	ID int64 | ||||
| 	// RefName is the human readable reference string of this server. | ||||
| 	RefName string | ||||
| 	// ServerData contains server internal metric reported by the server through | ||||
| 	// ChannelzMetric(). | ||||
| 	ServerData *ServerInternalMetric | ||||
| 	// ListenSockets tracks the listener socket type children of this server in the | ||||
| 	// format of a map from socket channelz id to corresponding reference string. | ||||
| 	ListenSockets map[int64]string | ||||
| } | ||||
|  | ||||
| // ServerInternalMetric defines the struct that the implementor of Server interface | ||||
| // should return from ChannelzMetric(). | ||||
| type ServerInternalMetric struct { | ||||
| 	// The number of incoming calls started on the server. | ||||
| 	CallsStarted int64 | ||||
| 	// The number of incoming calls that have completed with an OK status. | ||||
| 	CallsSucceeded int64 | ||||
| 	// The number of incoming calls that have a completed with a non-OK status. | ||||
| 	CallsFailed int64 | ||||
| 	// The last time a call was started on the server. | ||||
| 	LastCallStartedTimestamp time.Time | ||||
| } | ||||
|  | ||||
| // Server is the interface to be satisfied in order to be tracked by channelz as | ||||
| // Server. | ||||
| type Server interface { | ||||
| 	ChannelzMetric() *ServerInternalMetric | ||||
| } | ||||
|  | ||||
| type server struct { | ||||
| 	refName       string | ||||
| 	s             Server | ||||
| 	closeCalled   bool | ||||
| 	sockets       map[int64]string | ||||
| 	listenSockets map[int64]string | ||||
| 	id            int64 | ||||
| 	cm            *channelMap | ||||
| } | ||||
|  | ||||
| func (s *server) addChild(id int64, e entry) { | ||||
| 	switch v := e.(type) { | ||||
| 	case *normalSocket: | ||||
| 		s.sockets[id] = v.refName | ||||
| 	case *listenSocket: | ||||
| 		s.listenSockets[id] = v.refName | ||||
| 	default: | ||||
| 		grpclog.Errorf("cannot add a child (id = %d) of type %T to a server", id, e) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *server) deleteChild(id int64) { | ||||
| 	delete(s.sockets, id) | ||||
| 	delete(s.listenSockets, id) | ||||
| 	s.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (s *server) triggerDelete() { | ||||
| 	s.closeCalled = true | ||||
| 	s.deleteSelfIfReady() | ||||
| } | ||||
|  | ||||
| func (s *server) deleteSelfIfReady() { | ||||
| 	if !s.closeCalled || len(s.sockets)+len(s.listenSockets) != 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	s.cm.deleteEntry(s.id) | ||||
| } | ||||
|  | ||||
| func (s *server) getParentID() int64 { | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| type tracedChannel interface { | ||||
| 	getChannelTrace() *channelTrace | ||||
| 	incrTraceRefCount() | ||||
| 	decrTraceRefCount() | ||||
| 	getRefName() string | ||||
| } | ||||
|  | ||||
| type channelTrace struct { | ||||
| 	cm          *channelMap | ||||
| 	createdTime time.Time | ||||
| 	eventCount  int64 | ||||
| 	mu          sync.Mutex | ||||
| 	events      []*TraceEvent | ||||
| } | ||||
|  | ||||
| func (c *channelTrace) append(e *TraceEvent) { | ||||
| 	c.mu.Lock() | ||||
| 	if len(c.events) == getMaxTraceEntry() { | ||||
| 		del := c.events[0] | ||||
| 		c.events = c.events[1:] | ||||
| 		if del.RefID != 0 { | ||||
| 			// start recursive cleanup in a goroutine to not block the call originated from grpc. | ||||
| 			go func() { | ||||
| 				// need to acquire c.cm.mu lock to call the unlocked attemptCleanup func. | ||||
| 				c.cm.mu.Lock() | ||||
| 				c.cm.decrTraceRefCount(del.RefID) | ||||
| 				c.cm.mu.Unlock() | ||||
| 			}() | ||||
| 		} | ||||
| 	} | ||||
| 	e.Timestamp = time.Now() | ||||
| 	c.events = append(c.events, e) | ||||
| 	c.eventCount++ | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| func (c *channelTrace) clear() { | ||||
| 	c.mu.Lock() | ||||
| 	for _, e := range c.events { | ||||
| 		if e.RefID != 0 { | ||||
| 			// caller should have already held the c.cm.mu lock. | ||||
| 			c.cm.decrTraceRefCount(e.RefID) | ||||
| 		} | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
|  | ||||
| // Severity is the severity level of a trace event. | ||||
| // The canonical enumeration of all valid values is here: | ||||
| // https://github.com/grpc/grpc-proto/blob/9b13d199cc0d4703c7ea26c9c330ba695866eb23/grpc/channelz/v1/channelz.proto#L126. | ||||
| type Severity int | ||||
|  | ||||
| const ( | ||||
| 	// CtUNKNOWN indicates unknown severity of a trace event. | ||||
| 	CtUNKNOWN Severity = iota | ||||
| 	// CtINFO indicates info level severity of a trace event. | ||||
| 	CtINFO | ||||
| 	// CtWarning indicates warning level severity of a trace event. | ||||
| 	CtWarning | ||||
| 	// CtError indicates error level severity of a trace event. | ||||
| 	CtError | ||||
| ) | ||||
|  | ||||
| // RefChannelType is the type of the entity being referenced in a trace event. | ||||
| type RefChannelType int | ||||
|  | ||||
| const ( | ||||
| 	// RefChannel indicates the referenced entity is a Channel. | ||||
| 	RefChannel RefChannelType = iota | ||||
| 	// RefSubChannel indicates the referenced entity is a SubChannel. | ||||
| 	RefSubChannel | ||||
| ) | ||||
|  | ||||
| func (c *channelTrace) dumpData() *ChannelTrace { | ||||
| 	c.mu.Lock() | ||||
| 	ct := &ChannelTrace{EventNum: c.eventCount, CreationTime: c.createdTime} | ||||
| 	ct.Events = c.events[:len(c.events)] | ||||
| 	c.mu.Unlock() | ||||
| 	return ct | ||||
| } | ||||
							
								
								
									
										53
									
								
								vendor/google.golang.org/grpc/internal/channelz/types_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								vendor/google.golang.org/grpc/internal/channelz/types_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| // +build !appengine | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| package channelz | ||||
|  | ||||
| import ( | ||||
| 	"syscall" | ||||
|  | ||||
| 	"golang.org/x/sys/unix" | ||||
| ) | ||||
|  | ||||
| // SocketOptionData defines the struct to hold socket option data, and related | ||||
| // getter function to obtain info from fd. | ||||
| type SocketOptionData struct { | ||||
| 	Linger      *unix.Linger | ||||
| 	RecvTimeout *unix.Timeval | ||||
| 	SendTimeout *unix.Timeval | ||||
| 	TCPInfo     *unix.TCPInfo | ||||
| } | ||||
|  | ||||
| // Getsockopt defines the function to get socket options requested by channelz. | ||||
| // It is to be passed to syscall.RawConn.Control(). | ||||
| func (s *SocketOptionData) Getsockopt(fd uintptr) { | ||||
| 	if v, err := unix.GetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER); err == nil { | ||||
| 		s.Linger = v | ||||
| 	} | ||||
| 	if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO); err == nil { | ||||
| 		s.RecvTimeout = v | ||||
| 	} | ||||
| 	if v, err := unix.GetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO); err == nil { | ||||
| 		s.SendTimeout = v | ||||
| 	} | ||||
| 	if v, err := unix.GetsockoptTCPInfo(int(fd), syscall.SOL_TCP, syscall.TCP_INFO); err == nil { | ||||
| 		s.TCPInfo = v | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										44
									
								
								vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/google.golang.org/grpc/internal/channelz/types_nonlinux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // +build !linux appengine | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| package channelz | ||||
|  | ||||
| import ( | ||||
| 	"sync" | ||||
|  | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| ) | ||||
|  | ||||
| var once sync.Once | ||||
|  | ||||
| // SocketOptionData defines the struct to hold socket option data, and related | ||||
| // getter function to obtain info from fd. | ||||
| // Windows OS doesn't support Socket Option | ||||
| type SocketOptionData struct { | ||||
| } | ||||
|  | ||||
| // Getsockopt defines the function to get socket options requested by channelz. | ||||
| // It is to be passed to syscall.RawConn.Control(). | ||||
| // Windows OS doesn't support Socket Option | ||||
| func (s *SocketOptionData) Getsockopt(fd uintptr) { | ||||
| 	once.Do(func() { | ||||
| 		grpclog.Warningln("Channelz: socket options are not supported on non-linux os and appengine.") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										39
									
								
								vendor/google.golang.org/grpc/internal/channelz/util_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/google.golang.org/grpc/internal/channelz/util_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| // +build linux,!appengine | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| package channelz | ||||
|  | ||||
| import ( | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| // GetSocketOption gets the socket option info of the conn. | ||||
| func GetSocketOption(socket interface{}) *SocketOptionData { | ||||
| 	c, ok := socket.(syscall.Conn) | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	data := &SocketOptionData{} | ||||
| 	if rawConn, err := c.SyscallConn(); err == nil { | ||||
| 		rawConn.Control(data.Getsockopt) | ||||
| 		return data | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/google.golang.org/grpc/internal/channelz/util_nonlinux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| // +build !linux appengine | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| package channelz | ||||
|  | ||||
| // GetSocketOption gets the socket option info of the conn. | ||||
| func GetSocketOption(c interface{}) *SocketOptionData { | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Tonis Tiigi
					Tonis Tiigi