github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/xds/internal/server/rds_handler.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  
    19  package server
    20  
    21  import (
    22  	"sync"
    23  
    24  	"github.com/hxx258456/ccgo/grpc/xds/internal/xdsclient/xdsresource"
    25  )
    26  
    27  // rdsHandlerUpdate wraps the full RouteConfigUpdate that are dynamically
    28  // queried for a given server side listener.
    29  type rdsHandlerUpdate struct {
    30  	updates map[string]xdsresource.RouteConfigUpdate
    31  	err     error
    32  }
    33  
    34  // rdsHandler handles any RDS queries that need to be started for a given server
    35  // side listeners Filter Chains (i.e. not inline).
    36  type rdsHandler struct {
    37  	xdsC XDSClient
    38  
    39  	mu      sync.Mutex
    40  	updates map[string]xdsresource.RouteConfigUpdate
    41  	cancels map[string]func()
    42  
    43  	// For a rdsHandler update, the only update wrapped listener cares about is
    44  	// most recent one, so this channel will be opportunistically drained before
    45  	// sending any new updates.
    46  	updateChannel chan rdsHandlerUpdate
    47  }
    48  
    49  // newRDSHandler creates a new rdsHandler to watch for RDS resources.
    50  // listenerWrapper updates the list of route names to watch by calling
    51  // updateRouteNamesToWatch() upon receipt of new Listener configuration.
    52  func newRDSHandler(xdsC XDSClient, ch chan rdsHandlerUpdate) *rdsHandler {
    53  	return &rdsHandler{
    54  		xdsC:          xdsC,
    55  		updateChannel: ch,
    56  		updates:       make(map[string]xdsresource.RouteConfigUpdate),
    57  		cancels:       make(map[string]func()),
    58  	}
    59  }
    60  
    61  // updateRouteNamesToWatch handles a list of route names to watch for a given
    62  // server side listener (if a filter chain specifies dynamic RDS configuration).
    63  // This function handles all the logic with respect to any routes that may have
    64  // been added or deleted as compared to what was previously present.
    65  func (rh *rdsHandler) updateRouteNamesToWatch(routeNamesToWatch map[string]bool) {
    66  	rh.mu.Lock()
    67  	defer rh.mu.Unlock()
    68  	// Add and start watches for any routes for any new routes in
    69  	// routeNamesToWatch.
    70  	for routeName := range routeNamesToWatch {
    71  		if _, ok := rh.cancels[routeName]; !ok {
    72  			func(routeName string) {
    73  				rh.cancels[routeName] = rh.xdsC.WatchRouteConfig(routeName, func(update xdsresource.RouteConfigUpdate, err error) {
    74  					rh.handleRouteUpdate(routeName, update, err)
    75  				})
    76  			}(routeName)
    77  		}
    78  	}
    79  
    80  	// Delete and cancel watches for any routes from persisted routeNamesToWatch
    81  	// that are no longer present.
    82  	for routeName := range rh.cancels {
    83  		if _, ok := routeNamesToWatch[routeName]; !ok {
    84  			rh.cancels[routeName]()
    85  			delete(rh.cancels, routeName)
    86  			delete(rh.updates, routeName)
    87  		}
    88  	}
    89  
    90  	// If the full list (determined by length) of updates are now successfully
    91  	// updated, the listener is ready to be updated.
    92  	if len(rh.updates) == len(rh.cancels) && len(routeNamesToWatch) != 0 {
    93  		drainAndPush(rh.updateChannel, rdsHandlerUpdate{updates: rh.updates})
    94  	}
    95  }
    96  
    97  // handleRouteUpdate persists the route config for a given route name, and also
    98  // sends an update to the Listener Wrapper on an error received or if the rds
    99  // handler has a full collection of updates.
   100  func (rh *rdsHandler) handleRouteUpdate(routeName string, update xdsresource.RouteConfigUpdate, err error) {
   101  	if err != nil {
   102  		drainAndPush(rh.updateChannel, rdsHandlerUpdate{err: err})
   103  		return
   104  	}
   105  	rh.mu.Lock()
   106  	defer rh.mu.Unlock()
   107  	rh.updates[routeName] = update
   108  
   109  	// If the full list (determined by length) of updates have successfully
   110  	// updated, the listener is ready to be updated.
   111  	if len(rh.updates) == len(rh.cancels) {
   112  		drainAndPush(rh.updateChannel, rdsHandlerUpdate{updates: rh.updates})
   113  	}
   114  }
   115  
   116  func drainAndPush(ch chan rdsHandlerUpdate, update rdsHandlerUpdate) {
   117  	select {
   118  	case <-ch:
   119  	default:
   120  	}
   121  	ch <- update
   122  }
   123  
   124  // close() is meant to be called by wrapped listener when the wrapped listener
   125  // is closed, and it cleans up resources by canceling all the active RDS
   126  // watches.
   127  func (rh *rdsHandler) close() {
   128  	rh.mu.Lock()
   129  	defer rh.mu.Unlock()
   130  	for _, cancel := range rh.cancels {
   131  		cancel()
   132  	}
   133  }