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