gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/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  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/bootstrap"
    25  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/load"
    26  	"gitee.com/ks-custle/core-gm/grpc/xds/internal/xdsclient/pubsub"
    27  	"gitee.com/ks-custle/core-gm/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  }