From c1678424b67bda775e1728ceb20a440ca1292196 Mon Sep 17 00:00:00 2001
From: Ian Luo <ian.luo@gmail.com>
Date: Wed, 19 Aug 2020 13:28:27 +0800
Subject: [PATCH] avoid of copying and comparing invokers as much as possible

---
 cluster/router/chain/chain.go | 26 ++++++++++++++++++++------
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/cluster/router/chain/chain.go b/cluster/router/chain/chain.go
index a7f139b23..b15b845cf 100644
--- a/cluster/router/chain/chain.go
+++ b/cluster/router/chain/chain.go
@@ -167,21 +167,35 @@ func (c *RouterChain) loadCache() *InvokerCache {
 	return v.(*InvokerCache)
 }
 
+// copyInvokerIfNecessary compares chain's invokers copy and cache's invokers copy, to avoid copy as much as possible
+func (c *RouterChain) copyInvokerIfNecessary(cache *InvokerCache) []protocol.Invoker {
+	var invokers []protocol.Invoker
+	if cache != nil {
+		invokers = cache.invokers
+	}
+
+	c.mutex.RLock()
+	defer c.mutex.RUnlock()
+	if isInvokersChanged(invokers, c.invokers) {
+		invokers = c.copyInvokers()
+	}
+	return invokers
+}
+
 // buildCache builds address cache with the new invokers for all poolable routers.
 func (c *RouterChain) buildCache() {
-	invokers := c.copyInvokers()
-	if invokers == nil || len(c.invokers) == 0 {
+	origin := c.loadCache()
+	invokers := c.copyInvokerIfNecessary(origin)
+	if invokers == nil || len(invokers) == 0 {
 		return
 	}
 
-	cache := BuildCache(invokers)
-	origin := c.loadCache()
-
 	var (
 		mutex sync.Mutex
 		wg    sync.WaitGroup
 	)
 
+	cache := BuildCache(invokers)
 	for _, r := range c.copyRouters() {
 		if p, ok := r.(router.Poolable); ok {
 			wg.Add(1)
@@ -246,7 +260,7 @@ func NewRouterChain(url *common.URL) (*RouterChain, error) {
 // rule doesn't change), and the address list doesn't change, then the existing data will be re-used.
 func poolRouter(p router.Poolable, origin *InvokerCache, invokers []protocol.Invoker) (router.AddrPool, router.AddrMetadata) {
 	name := p.Name()
-	if isCacheMiss(origin, name) || p.ShouldPool() || isInvokersChanged(origin.invokers, invokers) {
+	if isCacheMiss(origin, name) || p.ShouldPool() || &(origin.invokers) != &invokers {
 		logger.Debugf("build address cache for router %q", name)
 		return p.Pool(invokers)
 	}
-- 
GitLab