Fix: a shared fastSingle.Do() may cause providers untouched (#2378)

This commit is contained in:
wwqgtxx 2022-11-04 13:11:01 +08:00 committed by GitHub
parent c8bc11d61d
commit 19b7c7f52a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 16 additions and 10 deletions

View file

@ -11,14 +11,19 @@ const (
defaultGetProxiesDuration = time.Second * 5 defaultGetProxiesDuration = time.Second * 5
) )
func touchProviders(providers []provider.ProxyProvider) {
for _, provider := range providers {
provider.Touch()
}
}
func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy { func getProvidersProxies(providers []provider.ProxyProvider, touch bool) []C.Proxy {
proxies := []C.Proxy{} proxies := []C.Proxy{}
for _, provider := range providers { for _, provider := range providers {
if touch { if touch {
proxies = append(proxies, provider.ProxiesWithTouch()...) provider.Touch()
} else {
proxies = append(proxies, provider.Proxies()...)
} }
proxies = append(proxies, provider.Proxies()...)
} }
return proxies return proxies
} }

View file

@ -66,7 +66,7 @@ func (u *URLTest) proxies(touch bool) []C.Proxy {
} }
func (u *URLTest) fast(touch bool) C.Proxy { func (u *URLTest) fast(touch bool) C.Proxy {
elm, _, _ := u.fastSingle.Do(func() (any, error) { elm, _, shared := u.fastSingle.Do(func() (any, error) {
proxies := u.proxies(touch) proxies := u.proxies(touch)
fast := proxies[0] fast := proxies[0]
min := fast.LastDelay() min := fast.LastDelay()
@ -95,6 +95,9 @@ func (u *URLTest) fast(touch bool) C.Proxy {
return u.fastNode, nil return u.fastNode, nil
}) })
if shared && touch { // a shared fastSingle.Do() may cause providers untouched, so we touch them again
touchProviders(u.providers)
}
return elm.(C.Proxy) return elm.(C.Proxy)
} }

View file

@ -78,9 +78,8 @@ func (pp *proxySetProvider) Proxies() []C.Proxy {
return pp.proxies return pp.proxies
} }
func (pp *proxySetProvider) ProxiesWithTouch() []C.Proxy { func (pp *proxySetProvider) Touch() {
pp.healthCheck.touch() pp.healthCheck.touch()
return pp.Proxies()
} }
func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { func (pp *proxySetProvider) setProxies(proxies []C.Proxy) {
@ -205,9 +204,8 @@ func (cp *compatibleProvider) Proxies() []C.Proxy {
return cp.proxies return cp.proxies
} }
func (cp *compatibleProvider) ProxiesWithTouch() []C.Proxy { func (cp *compatibleProvider) Touch() {
cp.healthCheck.touch() cp.healthCheck.touch()
return cp.Proxies()
} }
func stopCompatibleProvider(pd *CompatibleProvider) { func stopCompatibleProvider(pd *CompatibleProvider) {

View file

@ -66,9 +66,9 @@ type Provider interface {
type ProxyProvider interface { type ProxyProvider interface {
Provider Provider
Proxies() []constant.Proxy Proxies() []constant.Proxy
// ProxiesWithTouch is used to inform the provider that the proxy is actually being used while getting the list of proxies. // Touch is used to inform the provider that the proxy is actually being used while getting the list of proxies.
// Commonly used in DialContext and DialPacketConn // Commonly used in DialContext and DialPacketConn
ProxiesWithTouch() []constant.Proxy Touch()
HealthCheck() HealthCheck()
} }