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() }