github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/xdsclient/authority.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 xdsclient 19 20 import ( 21 "errors" 22 "fmt" 23 24 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/bootstrap" 25 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/load" 26 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/pubsub" 27 "github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource" 28 ) 29 30 const federationScheme = "xdstp" 31 32 // findAuthority returns the authority for this name. If it doesn't already 33 // exist, one will be created. 34 // 35 // Note that this doesn't always create new authority. authorities with the same 36 // config but different names are shared. 37 // 38 // The returned unref function must be called when the caller is done using this 39 // authority, without holding c.authorityMu. 40 // 41 // Caller must not hold c.authorityMu. 42 func (c *clientImpl) findAuthority(n *xdsresource.Name) (_ *authority, unref func(), _ error) { 43 scheme, authority := n.Scheme, n.Authority 44 45 c.authorityMu.Lock() 46 defer c.authorityMu.Unlock() 47 if c.done.HasFired() { 48 return nil, nil, errors.New("the xds-client is closed") 49 } 50 51 config := c.config.XDSServer 52 if scheme == federationScheme { 53 cfg, ok := c.config.Authorities[authority] 54 if !ok { 55 return nil, nil, fmt.Errorf("xds: failed to find authority %q", authority) 56 } 57 config = cfg.XDSServer 58 } 59 60 a, err := c.newAuthority(config) 61 if err != nil { 62 return nil, nil, fmt.Errorf("xds: failed to connect to the control plane for authority %q: %v", authority, err) 63 } 64 // All returned authority from this function will be used by a watch, 65 // holding the ref here. 66 // 67 // Note that this must be done while c.authorityMu is held, to avoid the 68 // race that an authority is returned, but before the watch starts, the 69 // old last watch is canceled (in another goroutine), causing this 70 // authority to be removed, and then a watch will start on a removed 71 // authority. 72 // 73 // unref() will be done when the watch is canceled. 74 a.ref() 75 return a, func() { c.unrefAuthority(a) }, nil 76 } 77 78 // newAuthority creates a new authority for the config. But before that, it 79 // checks the cache to see if an authority for this config already exists. 80 // 81 // caller must hold c.authorityMu 82 func (c *clientImpl) newAuthority(config *bootstrap.ServerConfig) (_ *authority, retErr error) { 83 // First check if there's already an authority for this config. If found, it 84 // means this authority is used by other watches (could be the same 85 // authority name, or a different authority name but the same server 86 // config). Return it. 87 configStr := config.String() 88 if a, ok := c.authorities[configStr]; ok { 89 return a, nil 90 } 91 // Second check if there's an authority in the idle cache. If found, it 92 // means this authority was created, but moved to the idle cache because the 93 // watch was canceled. Move it from idle cache to the authority cache, and 94 // return. 95 if old, ok := c.idleAuthorities.Remove(configStr); ok { 96 oldA, _ := old.(*authority) 97 if oldA != nil { 98 c.authorities[configStr] = oldA 99 return oldA, nil 100 } 101 } 102 103 // Make a new authority since there's no existing authority for this config. 104 ret := &authority{config: config, pubsub: pubsub.New(c.watchExpiryTimeout, c.logger)} 105 defer func() { 106 if retErr != nil { 107 ret.close() 108 } 109 }() 110 ctr, err := newController(config, ret.pubsub, c.updateValidator, c.logger) 111 if err != nil { 112 return nil, err 113 } 114 ret.controller = ctr 115 // Add it to the cache, so it will be reused. 116 c.authorities[configStr] = ret 117 return ret, nil 118 } 119 120 // unrefAuthority unrefs the authority. It also moves the authority to idle 121 // cache if it's ref count is 0. 122 // 123 // This function doesn't need to called explicitly. It's called by the returned 124 // unref from findAuthority(). 125 // 126 // Caller must not hold c.authorityMu. 127 func (c *clientImpl) unrefAuthority(a *authority) { 128 c.authorityMu.Lock() 129 defer c.authorityMu.Unlock() 130 if a.unref() > 0 { 131 return 132 } 133 configStr := a.config.String() 134 delete(c.authorities, configStr) 135 c.idleAuthorities.Add(configStr, a, func() { 136 a.close() 137 }) 138 } 139 140 // authority is a combination of pubsub and the controller for this authority. 141 // 142 // Note that it might make sense to use one pubsub for all the resources (for 143 // all the controllers). One downside is the handling of StoW APIs (LDS/CDS). 144 // These responses contain all the resources from that control plane, so pubsub 145 // will need to keep lists of resources from each control plane, to know what 146 // are removed. 147 type authority struct { 148 config *bootstrap.ServerConfig 149 pubsub *pubsub.Pubsub 150 controller controllerInterface 151 refCount int 152 } 153 154 // caller must hold parent's authorityMu. 155 func (a *authority) ref() { 156 a.refCount++ 157 } 158 159 // caller must hold parent's authorityMu. 160 func (a *authority) unref() int { 161 a.refCount-- 162 return a.refCount 163 } 164 165 func (a *authority) close() { 166 if a.pubsub != nil { 167 a.pubsub.Close() 168 } 169 if a.controller != nil { 170 a.controller.Close() 171 } 172 } 173 174 func (a *authority) watchListener(serviceName string, cb func(xdsresource.ListenerUpdate, error)) (cancel func()) { 175 first, cancelF := a.pubsub.WatchListener(serviceName, cb) 176 if first { 177 a.controller.AddWatch(xdsresource.ListenerResource, serviceName) 178 } 179 return func() { 180 if cancelF() { 181 a.controller.RemoveWatch(xdsresource.ListenerResource, serviceName) 182 } 183 } 184 } 185 186 func (a *authority) watchRouteConfig(routeName string, cb func(xdsresource.RouteConfigUpdate, error)) (cancel func()) { 187 first, cancelF := a.pubsub.WatchRouteConfig(routeName, cb) 188 if first { 189 a.controller.AddWatch(xdsresource.RouteConfigResource, routeName) 190 } 191 return func() { 192 if cancelF() { 193 a.controller.RemoveWatch(xdsresource.RouteConfigResource, routeName) 194 } 195 } 196 } 197 198 func (a *authority) watchCluster(clusterName string, cb func(xdsresource.ClusterUpdate, error)) (cancel func()) { 199 first, cancelF := a.pubsub.WatchCluster(clusterName, cb) 200 if first { 201 a.controller.AddWatch(xdsresource.ClusterResource, clusterName) 202 } 203 return func() { 204 if cancelF() { 205 a.controller.RemoveWatch(xdsresource.ClusterResource, clusterName) 206 } 207 } 208 } 209 210 func (a *authority) watchEndpoints(clusterName string, cb func(xdsresource.EndpointsUpdate, error)) (cancel func()) { 211 first, cancelF := a.pubsub.WatchEndpoints(clusterName, cb) 212 if first { 213 a.controller.AddWatch(xdsresource.EndpointsResource, clusterName) 214 } 215 return func() { 216 if cancelF() { 217 a.controller.RemoveWatch(xdsresource.EndpointsResource, clusterName) 218 } 219 } 220 } 221 222 func (a *authority) reportLoad(server string) (*load.Store, func()) { 223 return a.controller.ReportLoad(server) 224 } 225 226 func (a *authority) dump(t xdsresource.ResourceType) map[string]xdsresource.UpdateWithMD { 227 return a.pubsub.Dump(t) 228 }