mirror of
https://github.com/DNSCrypt/dnscrypt-proxy.git
synced 2025-03-04 02:14:40 +01:00
xTransport: avoid updating the host->IP map in multiple goroutines
When a goroutine is updating an IP, keep serving the previous IP to other goroutines.
This commit is contained in:
parent
8264b43199
commit
f49196c6e8
1 changed files with 28 additions and 9 deletions
|
@ -40,8 +40,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type CachedIPItem struct {
|
type CachedIPItem struct {
|
||||||
ip net.IP
|
ip net.IP
|
||||||
expiration *time.Time
|
expiration *time.Time
|
||||||
|
updating_until *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type CachedIPs struct {
|
type CachedIPs struct {
|
||||||
|
@ -105,7 +106,7 @@ func ParseIP(ipStr string) net.IP {
|
||||||
// If ttl < 0, never expire
|
// If ttl < 0, never expire
|
||||||
// Otherwise, ttl is set to max(ttl, MinResolverIPTTL)
|
// Otherwise, ttl is set to max(ttl, MinResolverIPTTL)
|
||||||
func (xTransport *XTransport) saveCachedIP(host string, ip net.IP, ttl time.Duration) {
|
func (xTransport *XTransport) saveCachedIP(host string, ip net.IP, ttl time.Duration) {
|
||||||
item := &CachedIPItem{ip: ip, expiration: nil}
|
item := &CachedIPItem{ip: ip, expiration: nil, updating_until: nil}
|
||||||
if ttl >= 0 {
|
if ttl >= 0 {
|
||||||
if ttl < MinResolverIPTTL {
|
if ttl < MinResolverIPTTL {
|
||||||
ttl = MinResolverIPTTL
|
ttl = MinResolverIPTTL
|
||||||
|
@ -118,8 +119,21 @@ func (xTransport *XTransport) saveCachedIP(host string, ip net.IP, ttl time.Dura
|
||||||
xTransport.cachedIPs.Unlock()
|
xTransport.cachedIPs.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (xTransport *XTransport) loadCachedIP(host string) (ip net.IP, expired bool) {
|
// Mark an entry as being updated
|
||||||
ip, expired = nil, false
|
func (xTransport *XTransport) markUpdatingCachedIP(host string) {
|
||||||
|
xTransport.cachedIPs.Lock()
|
||||||
|
item, ok := xTransport.cachedIPs.cache[host]
|
||||||
|
if ok {
|
||||||
|
now := time.Now()
|
||||||
|
until := now.Add(xTransport.timeout)
|
||||||
|
item.updating_until = &until
|
||||||
|
xTransport.cachedIPs.cache[host] = item
|
||||||
|
}
|
||||||
|
xTransport.cachedIPs.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (xTransport *XTransport) loadCachedIP(host string) (ip net.IP, expired bool, updating bool) {
|
||||||
|
ip, expired, updating = nil, false, false
|
||||||
xTransport.cachedIPs.RLock()
|
xTransport.cachedIPs.RLock()
|
||||||
item, ok := xTransport.cachedIPs.cache[host]
|
item, ok := xTransport.cachedIPs.cache[host]
|
||||||
xTransport.cachedIPs.RUnlock()
|
xTransport.cachedIPs.RUnlock()
|
||||||
|
@ -130,6 +144,9 @@ func (xTransport *XTransport) loadCachedIP(host string) (ip net.IP, expired bool
|
||||||
expiration := item.expiration
|
expiration := item.expiration
|
||||||
if expiration != nil && time.Until(*expiration) < 0 {
|
if expiration != nil && time.Until(*expiration) < 0 {
|
||||||
expired = true
|
expired = true
|
||||||
|
if item.updating_until != nil && time.Until(*item.updating_until) > 0 {
|
||||||
|
updating = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -153,7 +170,7 @@ func (xTransport *XTransport) rebuildTransport() {
|
||||||
ipOnly := host
|
ipOnly := host
|
||||||
// resolveAndUpdateCache() is always called in `Fetch()` before the `Dial()`
|
// resolveAndUpdateCache() is always called in `Fetch()` before the `Dial()`
|
||||||
// method is used, so that a cached entry must be present at this point.
|
// method is used, so that a cached entry must be present at this point.
|
||||||
cachedIP, _ := xTransport.loadCachedIP(host)
|
cachedIP, _, _ := xTransport.loadCachedIP(host)
|
||||||
if cachedIP != nil {
|
if cachedIP != nil {
|
||||||
if ipv4 := cachedIP.To4(); ipv4 != nil {
|
if ipv4 := cachedIP.To4(); ipv4 != nil {
|
||||||
ipOnly = ipv4.String()
|
ipOnly = ipv4.String()
|
||||||
|
@ -263,7 +280,7 @@ func (xTransport *XTransport) rebuildTransport() {
|
||||||
dlog.Debugf("Dialing for H3: [%v]", addrStr)
|
dlog.Debugf("Dialing for H3: [%v]", addrStr)
|
||||||
host, port := ExtractHostAndPort(addrStr, stamps.DefaultPort)
|
host, port := ExtractHostAndPort(addrStr, stamps.DefaultPort)
|
||||||
ipOnly := host
|
ipOnly := host
|
||||||
cachedIP, _ := xTransport.loadCachedIP(host)
|
cachedIP, _, _ := xTransport.loadCachedIP(host)
|
||||||
network := "udp4"
|
network := "udp4"
|
||||||
if cachedIP != nil {
|
if cachedIP != nil {
|
||||||
if ipv4 := cachedIP.To4(); ipv4 != nil {
|
if ipv4 := cachedIP.To4(); ipv4 != nil {
|
||||||
|
@ -402,10 +419,12 @@ func (xTransport *XTransport) resolveAndUpdateCache(host string) error {
|
||||||
if ParseIP(host) != nil {
|
if ParseIP(host) != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
cachedIP, expired := xTransport.loadCachedIP(host)
|
cachedIP, expired, updating := xTransport.loadCachedIP(host)
|
||||||
if cachedIP != nil && !expired {
|
if cachedIP != nil && (!expired || updating) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
xTransport.markUpdatingCachedIP(host)
|
||||||
|
|
||||||
var foundIP net.IP
|
var foundIP net.IP
|
||||||
var ttl time.Duration
|
var ttl time.Duration
|
||||||
var err error
|
var err error
|
||||||
|
|
Loading…
Add table
Reference in a new issue