subchannel.go

  1/*
  2 *
  3 * Copyright 2024 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
 19package channelz
 20
 21import (
 22	"fmt"
 23	"sync/atomic"
 24)
 25
 26// SubChannel is the channelz representation of a subchannel.
 27type SubChannel struct {
 28	Entity
 29	// ID is the channelz id of this subchannel.
 30	ID int64
 31	// RefName is the human readable reference string of this subchannel.
 32	RefName       string
 33	closeCalled   bool
 34	sockets       map[int64]string
 35	parent        *Channel
 36	trace         *ChannelTrace
 37	traceRefCount int32
 38
 39	ChannelMetrics ChannelMetrics
 40}
 41
 42func (sc *SubChannel) String() string {
 43	return fmt.Sprintf("%s SubChannel #%d", sc.parent, sc.ID)
 44}
 45
 46func (sc *SubChannel) id() int64 {
 47	return sc.ID
 48}
 49
 50// Sockets returns a copy of the sockets map associated with the SubChannel.
 51func (sc *SubChannel) Sockets() map[int64]string {
 52	db.mu.RLock()
 53	defer db.mu.RUnlock()
 54	return copyMap(sc.sockets)
 55}
 56
 57// Trace returns a copy of the ChannelTrace associated with the SubChannel.
 58func (sc *SubChannel) Trace() *ChannelTrace {
 59	db.mu.RLock()
 60	defer db.mu.RUnlock()
 61	return sc.trace.copy()
 62}
 63
 64func (sc *SubChannel) addChild(id int64, e entry) {
 65	if v, ok := e.(*Socket); ok && v.SocketType == SocketTypeNormal {
 66		sc.sockets[id] = v.RefName
 67	} else {
 68		logger.Errorf("cannot add a child (id = %d) of type %T to a subChannel", id, e)
 69	}
 70}
 71
 72func (sc *SubChannel) deleteChild(id int64) {
 73	delete(sc.sockets, id)
 74	sc.deleteSelfIfReady()
 75}
 76
 77func (sc *SubChannel) triggerDelete() {
 78	sc.closeCalled = true
 79	sc.deleteSelfIfReady()
 80}
 81
 82func (sc *SubChannel) getParentID() int64 {
 83	return sc.parent.ID
 84}
 85
 86// deleteSelfFromTree tries to delete the subchannel from the channelz entry relation tree, which
 87// means deleting the subchannel reference from its parent's child list.
 88//
 89// In order for a subchannel to be deleted from the tree, it must meet the criteria that, removal of
 90// the corresponding grpc object has been invoked, and the subchannel does not have any children left.
 91//
 92// The returned boolean value indicates whether the channel has been successfully deleted from tree.
 93func (sc *SubChannel) deleteSelfFromTree() (deleted bool) {
 94	if !sc.closeCalled || len(sc.sockets) != 0 {
 95		return false
 96	}
 97	sc.parent.deleteChild(sc.ID)
 98	return true
 99}
100
101// deleteSelfFromMap checks whether it is valid to delete the subchannel from the map, which means
102// deleting the subchannel from channelz's tracking entirely. Users can no longer use id to query
103// the subchannel, and its memory will be garbage collected.
104//
105// The trace reference count of the subchannel must be 0 in order to be deleted from the map. This is
106// specified in the channel tracing gRFC that as long as some other trace has reference to an entity,
107// the trace of the referenced entity must not be deleted. In order to release the resource allocated
108// by grpc, the reference to the grpc object is reset to a dummy object.
109//
110// deleteSelfFromMap must be called after deleteSelfFromTree returns true.
111//
112// It returns a bool to indicate whether the channel can be safely deleted from map.
113func (sc *SubChannel) deleteSelfFromMap() (delete bool) {
114	return sc.getTraceRefCount() == 0
115}
116
117// deleteSelfIfReady tries to delete the subchannel itself from the channelz database.
118// The delete process includes two steps:
119//  1. delete the subchannel from the entry relation tree, i.e. delete the subchannel reference from
120//     its parent's child list.
121//  2. delete the subchannel from the map, i.e. delete the subchannel entirely from channelz. Lookup
122//     by id will return entry not found error.
123func (sc *SubChannel) deleteSelfIfReady() {
124	if !sc.deleteSelfFromTree() {
125		return
126	}
127	if !sc.deleteSelfFromMap() {
128		return
129	}
130	db.deleteEntry(sc.ID)
131	sc.trace.clear()
132}
133
134func (sc *SubChannel) getChannelTrace() *ChannelTrace {
135	return sc.trace
136}
137
138func (sc *SubChannel) incrTraceRefCount() {
139	atomic.AddInt32(&sc.traceRefCount, 1)
140}
141
142func (sc *SubChannel) decrTraceRefCount() {
143	atomic.AddInt32(&sc.traceRefCount, -1)
144}
145
146func (sc *SubChannel) getTraceRefCount() int {
147	i := atomic.LoadInt32(&sc.traceRefCount)
148	return int(i)
149}
150
151func (sc *SubChannel) getRefName() string {
152	return sc.RefName
153}