From 624b4e0789df42bd762d8c07800fea1c398845c8 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Thu, 10 Mar 2022 11:02:19 -0800 Subject: [PATCH 1/8] support adding/removing clients from LBClient --- lbclient.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lbclient.go b/lbclient.go index 46d14b75cb..7dd4b9ab13 100644 --- a/lbclient.go +++ b/lbclient.go @@ -50,6 +50,7 @@ type LBClient struct { cs []*lbClient once sync.Once + mu sync.Mutex } // DefaultLBClientTimeout is the default request timeout used by LBClient @@ -91,6 +92,37 @@ func (cc *LBClient) init() { } } +// AddClient adds a new HostClient to the balanced clients +// returns the new total number of clients +func (cc *LBClient) AddClient(c *HostClient) int { + cc.mu.Lock() + cc.cs = append(cc.cs, &lbClient{ + c: c, + healthCheck: cc.HealthCheck, + }) + cc.mu.Unlock() + return len(cc.cs) +} + +// RemoveClients removes clients using the provided callback +// if rc returns true, the passed client will be removed +// returns the new total number of clients +func (cc *LBClient) RemoveClients(rc func(*HostClient) bool) int { + cc.mu.Lock() + for idx, cs := range cc.cs { + // ignore non HostClient BalancingClients + hc, ok := cs.c.(*HostClient) + if !ok { + continue + } + if rc(hc) { + cc.cs = append(cc.cs[:idx], cc.cs[idx+1]) + } + } + cc.mu.Unlock() + return len(cc.cs) +} + func (cc *LBClient) get() *lbClient { cc.once.Do(cc.init) From d076bac1e433803e5db8b4d0be45eb7acfb2dba7 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Thu, 10 Mar 2022 11:55:10 -0800 Subject: [PATCH 2/8] add/remove BalancingClient to be more flexible --- lbclient.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lbclient.go b/lbclient.go index 7dd4b9ab13..e515c09873 100644 --- a/lbclient.go +++ b/lbclient.go @@ -92,9 +92,9 @@ func (cc *LBClient) init() { } } -// AddClient adds a new HostClient to the balanced clients +// AddClient adds a new client to the balanced clients // returns the new total number of clients -func (cc *LBClient) AddClient(c *HostClient) int { +func (cc *LBClient) AddClient(c BalancingClient) int { cc.mu.Lock() cc.cs = append(cc.cs, &lbClient{ c: c, @@ -107,15 +107,10 @@ func (cc *LBClient) AddClient(c *HostClient) int { // RemoveClients removes clients using the provided callback // if rc returns true, the passed client will be removed // returns the new total number of clients -func (cc *LBClient) RemoveClients(rc func(*HostClient) bool) int { +func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int { cc.mu.Lock() for idx, cs := range cc.cs { - // ignore non HostClient BalancingClients - hc, ok := cs.c.(*HostClient) - if !ok { - continue - } - if rc(hc) { + if rc(cs.c) { cc.cs = append(cc.cs[:idx], cc.cs[idx+1]) } } From f50b0fc584290c1a502c0bcb74119ae32fa6112b Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Mon, 14 Mar 2022 10:35:55 -0700 Subject: [PATCH 3/8] use RwMutex, lock for get --- lbclient.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lbclient.go b/lbclient.go index e515c09873..726b224dea 100644 --- a/lbclient.go +++ b/lbclient.go @@ -50,7 +50,7 @@ type LBClient struct { cs []*lbClient once sync.Once - mu sync.Mutex + mu sync.RWMutex } // DefaultLBClientTimeout is the default request timeout used by LBClient @@ -121,6 +121,7 @@ func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int { func (cc *LBClient) get() *lbClient { cc.once.Do(cc.init) + cc.mu.RLock() cs := cc.cs minC := cs[0] @@ -135,6 +136,7 @@ func (cc *LBClient) get() *lbClient { minT = t } } + cc.mu.RUnlock() return minC } From d25cb404ff901a4a3be1cb11c30de7c5b6cc18a5 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Mon, 14 Mar 2022 10:36:12 -0700 Subject: [PATCH 4/8] lock mutex for init --- lbclient.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lbclient.go b/lbclient.go index 726b224dea..a43a5ae0a7 100644 --- a/lbclient.go +++ b/lbclient.go @@ -81,6 +81,7 @@ func (cc *LBClient) Do(req *Request, resp *Response) error { } func (cc *LBClient) init() { + cc.mu.Lock() if len(cc.Clients) == 0 { panic("BUG: LBClient.Clients cannot be empty") } @@ -90,6 +91,7 @@ func (cc *LBClient) init() { healthCheck: cc.HealthCheck, }) } + cc.mu.Unlock() } // AddClient adds a new client to the balanced clients From 7d55d60124a9def3de71f795dadc172ca5f2ce50 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Tue, 15 Mar 2022 09:29:45 -0700 Subject: [PATCH 5/8] defer unlock for possible panic --- lbclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbclient.go b/lbclient.go index a43a5ae0a7..e0dcba8c37 100644 --- a/lbclient.go +++ b/lbclient.go @@ -82,6 +82,7 @@ func (cc *LBClient) Do(req *Request, resp *Response) error { func (cc *LBClient) init() { cc.mu.Lock() + defer cc.mu.Unlock() if len(cc.Clients) == 0 { panic("BUG: LBClient.Clients cannot be empty") } @@ -91,7 +92,6 @@ func (cc *LBClient) init() { healthCheck: cc.HealthCheck, }) } - cc.mu.Unlock() } // AddClient adds a new client to the balanced clients From fee6920e266c9fe43cb50fb21731dc4a6ab0f865 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Sat, 26 Mar 2022 11:51:38 -0700 Subject: [PATCH 6/8] fix removing client --- lbclient.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lbclient.go b/lbclient.go index e0dcba8c37..f5600567e7 100644 --- a/lbclient.go +++ b/lbclient.go @@ -113,7 +113,7 @@ func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int { cc.mu.Lock() for idx, cs := range cc.cs { if rc(cs.c) { - cc.cs = append(cc.cs[:idx], cc.cs[idx+1]) + cc.cs = append(cc.cs[:idx], cc.cs[idx+1:]...) } } cc.mu.Unlock() From 4b780b3adceda0b301799ef9690f992cb1563f69 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Thu, 31 Mar 2022 08:56:13 -0700 Subject: [PATCH 7/8] fix filtering of slice --- lbclient.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lbclient.go b/lbclient.go index f5600567e7..a54e5dc1a8 100644 --- a/lbclient.go +++ b/lbclient.go @@ -111,11 +111,17 @@ func (cc *LBClient) AddClient(c BalancingClient) int { // returns the new total number of clients func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int { cc.mu.Lock() - for idx, cs := range cc.cs { + n := 0 + for _, cs := range cc.cs { if rc(cs.c) { - cc.cs = append(cc.cs[:idx], cc.cs[idx+1:]...) + cs = nil + continue } + cc.cs[n] = cs + n++ } + cc.cs = cc.cs[:n] + cc.mu.Unlock() return len(cc.cs) } From 176a86ba5262065d17b0e2bc56e93dea0213d6a5 Mon Sep 17 00:00:00 2001 From: Cam Sweeney Date: Fri, 1 Apr 2022 08:43:01 -0700 Subject: [PATCH 8/8] fix removing references to removed items Co-authored-by: Erik Dubbelboer --- lbclient.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lbclient.go b/lbclient.go index a54e5dc1a8..34ff719721 100644 --- a/lbclient.go +++ b/lbclient.go @@ -114,12 +114,14 @@ func (cc *LBClient) RemoveClients(rc func(BalancingClient) bool) int { n := 0 for _, cs := range cc.cs { if rc(cs.c) { - cs = nil continue } cc.cs[n] = cs n++ } + for i := n; i < len(cc.cs); i++ { + cc.cs[i] = nil + } cc.cs = cc.cs[:n] cc.mu.Unlock()