gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/grpc/xds/internal/xdsclient/controller/loadreport.go (about)

     1  /*
     2   *
     3   * Copyright 2021 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  package controller
    19  
    20  import (
    21  	"context"
    22  
    23  	grpc "gitee.com/ks-custle/core-gm/grpc"
    24  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/controller/version"
    25  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/load"
    26  )
    27  
    28  // ReportLoad starts an load reporting stream to the given server. If the server
    29  // is not an empty string, and is different from the management server, a new
    30  // ClientConn will be created.
    31  //
    32  // The same options used for creating the Client will be used (including
    33  // NodeProto, and dial options if necessary).
    34  //
    35  // It returns a Store for the user to report loads, a function to cancel the
    36  // load reporting stream.
    37  //
    38  // TODO: LRS refactor; maybe a new controller should be created for a separate
    39  // server, so that the same stream can be shared by different reporters to the
    40  // same server, even if they originate from different Controllers.
    41  func (c *Controller) ReportLoad(server string) (*load.Store, func()) {
    42  	c.lrsMu.Lock()
    43  	defer c.lrsMu.Unlock()
    44  
    45  	// If there's already a client to this server, use it. Otherwise, create
    46  	// one.
    47  	lrsC, ok := c.lrsClients[server]
    48  	if !ok {
    49  		lrsC = newLRSClient(c, server)
    50  		c.lrsClients[server] = lrsC
    51  	}
    52  
    53  	store := lrsC.ref()
    54  	return store, func() {
    55  		// This is a callback, need to hold lrsMu.
    56  		c.lrsMu.Lock()
    57  		defer c.lrsMu.Unlock()
    58  		if lrsC.unRef() {
    59  			// Delete the lrsClient from map if this is the last reference.
    60  			delete(c.lrsClients, server)
    61  		}
    62  	}
    63  }
    64  
    65  // lrsClient maps to one lrsServer. It contains:
    66  // - a ClientConn to this server (only if it's different from the management
    67  // server)
    68  // - a load.Store that contains loads only for this server
    69  type lrsClient struct {
    70  	parent *Controller
    71  	server string
    72  
    73  	cc           *grpc.ClientConn // nil if the server is same as the management server
    74  	refCount     int
    75  	cancelStream func()
    76  	loadStore    *load.Store
    77  }
    78  
    79  // newLRSClient creates a new LRS stream to the server.
    80  func newLRSClient(parent *Controller, server string) *lrsClient {
    81  	return &lrsClient{
    82  		parent:   parent,
    83  		server:   server,
    84  		refCount: 0,
    85  	}
    86  }
    87  
    88  // ref increments the refCount. If this is the first ref, it starts the LRS stream.
    89  //
    90  // Not thread-safe, caller needs to synchronize.
    91  func (lrsC *lrsClient) ref() *load.Store {
    92  	lrsC.refCount++
    93  	if lrsC.refCount == 1 {
    94  		lrsC.startStream()
    95  	}
    96  	return lrsC.loadStore
    97  }
    98  
    99  // unRef decrements the refCount, and closes the stream if refCount reaches 0
   100  // (and close the cc if cc is not xDS cc). It returns whether refCount reached 0
   101  // after this call.
   102  //
   103  // Not thread-safe, caller needs to synchronize.
   104  func (lrsC *lrsClient) unRef() (closed bool) {
   105  	lrsC.refCount--
   106  	if lrsC.refCount != 0 {
   107  		return false
   108  	}
   109  	lrsC.parent.logger.Infof("Stopping load report to server: %s", lrsC.server)
   110  	lrsC.cancelStream()
   111  	if lrsC.cc != nil {
   112  		lrsC.cc.Close()
   113  	}
   114  	return true
   115  }
   116  
   117  // startStream starts the LRS stream to the server. If server is not the same
   118  // management server from the parent, it also creates a ClientConn.
   119  func (lrsC *lrsClient) startStream() {
   120  	var cc *grpc.ClientConn
   121  
   122  	lrsC.parent.logger.Infof("Starting load report to server: %s", lrsC.server)
   123  	if lrsC.server == "" || lrsC.server == lrsC.parent.config.ServerURI {
   124  		// Reuse the xDS client if server is the same.
   125  		cc = lrsC.parent.cc
   126  	} else {
   127  		lrsC.parent.logger.Infof("LRS server is different from management server, starting a new ClientConn")
   128  		ccNew, err := grpc.Dial(lrsC.server, lrsC.parent.config.Creds)
   129  		if err != nil {
   130  			// An error from a non-blocking dial indicates something serious.
   131  			lrsC.parent.logger.Infof("xds: failed to dial load report server {%s}: %v", lrsC.server, err)
   132  			return
   133  		}
   134  		cc = ccNew
   135  		lrsC.cc = ccNew
   136  	}
   137  
   138  	var ctx context.Context
   139  	ctx, lrsC.cancelStream = context.WithCancel(context.Background())
   140  
   141  	// Create the store and stream.
   142  	lrsC.loadStore = load.NewStore()
   143  	go lrsC.parent.reportLoad(ctx, cc, version.LoadReportingOptions{LoadStore: lrsC.loadStore})
   144  }