subchannel.go raw

   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  
  19  package channelz
  20  
  21  import (
  22  	"fmt"
  23  	"sync/atomic"
  24  )
  25  
  26  // SubChannel is the channelz representation of a subchannel.
  27  type 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  
  42  func (sc *SubChannel) String() string {
  43  	return fmt.Sprintf("%s SubChannel #%d", sc.parent, sc.ID)
  44  }
  45  
  46  func (sc *SubChannel) id() int64 {
  47  	return sc.ID
  48  }
  49  
  50  // Sockets returns a copy of the sockets map associated with the SubChannel.
  51  func (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.
  58  func (sc *SubChannel) Trace() *ChannelTrace {
  59  	db.mu.RLock()
  60  	defer db.mu.RUnlock()
  61  	return sc.trace.copy()
  62  }
  63  
  64  func (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  
  72  func (sc *SubChannel) deleteChild(id int64) {
  73  	delete(sc.sockets, id)
  74  	sc.deleteSelfIfReady()
  75  }
  76  
  77  func (sc *SubChannel) triggerDelete() {
  78  	sc.closeCalled = true
  79  	sc.deleteSelfIfReady()
  80  }
  81  
  82  func (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.
  93  func (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.
 113  func (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.
 123  func (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  
 134  func (sc *SubChannel) getChannelTrace() *ChannelTrace {
 135  	return sc.trace
 136  }
 137  
 138  func (sc *SubChannel) incrTraceRefCount() {
 139  	atomic.AddInt32(&sc.traceRefCount, 1)
 140  }
 141  
 142  func (sc *SubChannel) decrTraceRefCount() {
 143  	atomic.AddInt32(&sc.traceRefCount, -1)
 144  }
 145  
 146  func (sc *SubChannel) getTraceRefCount() int {
 147  	i := atomic.LoadInt32(&sc.traceRefCount)
 148  	return int(i)
 149  }
 150  
 151  func (sc *SubChannel) getRefName() string {
 152  	return sc.RefName
 153  }
 154