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