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 }