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 }