dubbo.apache.org/dubbo-go/v3@v3.1.1/cluster/router/chain/chain.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 package chain 19 20 import ( 21 "sort" 22 "sync" 23 ) 24 25 import ( 26 "github.com/dubbogo/gost/log/logger" 27 28 perrors "github.com/pkg/errors" 29 30 "go.uber.org/atomic" 31 ) 32 33 import ( 34 "dubbo.apache.org/dubbo-go/v3/cluster/router" 35 "dubbo.apache.org/dubbo-go/v3/common" 36 "dubbo.apache.org/dubbo-go/v3/common/extension" 37 "dubbo.apache.org/dubbo-go/v3/protocol" 38 ) 39 40 // RouterChain Router chain 41 type RouterChain struct { 42 // Full list of addresses from registry, classified by method name. 43 invokers []protocol.Invoker 44 // Containing all routers, reconstruct every time 'route://' urls change. 45 routers []router.PriorityRouter 46 // Fixed router instances: ConfigConditionRouter, TagRouter, e.g., the rule for each instance may change but the 47 // instance will never delete or recreate. 48 builtinRouters []router.PriorityRouter 49 50 mutex sync.RWMutex 51 } 52 53 // Route Loop routers in RouterChain and call Route method to determine the target invokers list. 54 func (c *RouterChain) Route(url *common.URL, invocation protocol.Invocation) []protocol.Invoker { 55 finalInvokers := make([]protocol.Invoker, 0, len(c.invokers)) 56 // multiple invoker may include different methods, find correct invoker otherwise 57 // will return the invoker without methods 58 for _, invoker := range c.invokers { 59 if invoker.GetURL().ServiceKey() == url.ServiceKey() { 60 finalInvokers = append(finalInvokers, invoker) 61 } 62 } 63 64 if len(finalInvokers) == 0 { 65 finalInvokers = c.invokers 66 } 67 68 for _, r := range c.copyRouters() { 69 finalInvokers = r.Route(finalInvokers, url, invocation) 70 } 71 return finalInvokers 72 } 73 74 // AddRouters Add routers to router chain 75 // New a array add builtinRouters which is not sorted in RouterChain and routers 76 // Sort the array 77 // Replace router array in RouterChain 78 func (c *RouterChain) AddRouters(routers []router.PriorityRouter) { 79 newRouters := make([]router.PriorityRouter, 0, len(c.builtinRouters)+len(routers)) 80 newRouters = append(newRouters, c.builtinRouters...) 81 newRouters = append(newRouters, routers...) 82 sortRouter(newRouters) 83 c.mutex.Lock() 84 defer c.mutex.Unlock() 85 c.routers = newRouters 86 } 87 88 // SetInvokers receives updated invokers from registry center. If the times of notification exceeds countThreshold and 89 // time interval exceeds timeThreshold since last cache update, then notify to update the cache. 90 func (c *RouterChain) SetInvokers(invokers []protocol.Invoker) { 91 c.mutex.Lock() 92 defer c.mutex.Unlock() 93 c.invokers = invokers 94 for _, v := range c.routers { 95 v.Notify(c.invokers) 96 } 97 } 98 99 // copyRouters make a snapshot copy from RouterChain's router list. 100 func (c *RouterChain) copyRouters() []router.PriorityRouter { 101 c.mutex.RLock() 102 defer c.mutex.RUnlock() 103 ret := make([]router.PriorityRouter, 0, len(c.routers)) 104 ret = append(ret, c.routers...) 105 return ret 106 } 107 108 // copyInvokers copies a snapshot of the received invokers. 109 func (c *RouterChain) copyInvokers() []protocol.Invoker { 110 c.mutex.RLock() 111 defer c.mutex.RUnlock() 112 if c.invokers == nil || len(c.invokers) == 0 { 113 return nil 114 } 115 ret := make([]protocol.Invoker, 0, len(c.invokers)) 116 ret = append(ret, c.invokers...) 117 return ret 118 } 119 120 // NewRouterChain init router chain 121 // Loop routerFactories and call NewRouter method 122 func NewRouterChain() (*RouterChain, error) { 123 routerFactories := extension.GetRouterFactories() 124 if len(routerFactories) == 0 { 125 return nil, perrors.Errorf("No routerFactory exits , create one please") 126 } 127 128 routers := make([]router.PriorityRouter, 0, len(routerFactories)) 129 130 for key, routerFactory := range routerFactories { 131 r, err := routerFactory().NewPriorityRouter() 132 if err != nil { 133 logger.Errorf("Build router chain failed with routerFactories key:%s and error:%v", key, err) 134 continue 135 } else if r == nil { 136 continue 137 } 138 routers = append(routers, r) 139 } 140 141 newRouters := make([]router.PriorityRouter, len(routers)) 142 copy(newRouters, routers) 143 144 sortRouter(newRouters) 145 146 routerNeedsUpdateInit := atomic.Bool{} 147 routerNeedsUpdateInit.Store(false) 148 149 chain := &RouterChain{ 150 routers: newRouters, 151 builtinRouters: routers, 152 } 153 154 return chain, nil 155 } 156 157 // sortRouter Sort router instance by priority with stable algorithm 158 func sortRouter(routers []router.PriorityRouter) { 159 sort.Stable(byPriority(routers)) 160 } 161 162 // byPriority Sort by priority 163 type byPriority []router.PriorityRouter 164 165 func (a byPriority) Len() int { return len(a) } 166 func (a byPriority) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 167 func (a byPriority) Less(i, j int) bool { return a[i].Priority() < a[j].Priority() }