@@ -40,8 +40,9 @@ const (
4040)
4141
4242type CachedIPItem struct {
43- ip net.IP
44- expiration * time.Time
43+ ip net.IP
44+ expiration * time.Time
45+ updating_until * time.Time
4546}
4647
4748type CachedIPs struct {
@@ -105,7 +106,7 @@ func ParseIP(ipStr string) net.IP {
105106// If ttl < 0, never expire
106107// Otherwise, ttl is set to max(ttl, MinResolverIPTTL)
107108func (xTransport * XTransport ) saveCachedIP (host string , ip net.IP , ttl time.Duration ) {
108- item := & CachedIPItem {ip : ip , expiration : nil }
109+ item := & CachedIPItem {ip : ip , expiration : nil , updating_until : nil }
109110 if ttl >= 0 {
110111 if ttl < MinResolverIPTTL {
111112 ttl = MinResolverIPTTL
@@ -118,8 +119,21 @@ func (xTransport *XTransport) saveCachedIP(host string, ip net.IP, ttl time.Dura
118119 xTransport .cachedIPs .Unlock ()
119120}
120121
121- func (xTransport * XTransport ) loadCachedIP (host string ) (ip net.IP , expired bool ) {
122- ip , expired = nil , false
122+ // Mark an entry as being updated
123+ func (xTransport * XTransport ) markUpdatingCachedIP (host string ) {
124+ xTransport .cachedIPs .Lock ()
125+ item , ok := xTransport .cachedIPs .cache [host ]
126+ if ok {
127+ now := time .Now ()
128+ until := now .Add (xTransport .timeout )
129+ item .updating_until = & until
130+ xTransport .cachedIPs .cache [host ] = item
131+ }
132+ xTransport .cachedIPs .Unlock ()
133+ }
134+
135+ func (xTransport * XTransport ) loadCachedIP (host string ) (ip net.IP , expired bool , updating bool ) {
136+ ip , expired , updating = nil , false , false
123137 xTransport .cachedIPs .RLock ()
124138 item , ok := xTransport .cachedIPs .cache [host ]
125139 xTransport .cachedIPs .RUnlock ()
@@ -130,6 +144,9 @@ func (xTransport *XTransport) loadCachedIP(host string) (ip net.IP, expired bool
130144 expiration := item .expiration
131145 if expiration != nil && time .Until (* expiration ) < 0 {
132146 expired = true
147+ if item .updating_until != nil && time .Until (* item .updating_until ) > 0 {
148+ updating = true
149+ }
133150 }
134151 return
135152}
@@ -153,7 +170,7 @@ func (xTransport *XTransport) rebuildTransport() {
153170 ipOnly := host
154171 // resolveAndUpdateCache() is always called in `Fetch()` before the `Dial()`
155172 // method is used, so that a cached entry must be present at this point.
156- cachedIP , _ := xTransport .loadCachedIP (host )
173+ cachedIP , _ , _ := xTransport .loadCachedIP (host )
157174 if cachedIP != nil {
158175 if ipv4 := cachedIP .To4 (); ipv4 != nil {
159176 ipOnly = ipv4 .String ()
@@ -263,7 +280,7 @@ func (xTransport *XTransport) rebuildTransport() {
263280 dlog .Debugf ("Dialing for H3: [%v]" , addrStr )
264281 host , port := ExtractHostAndPort (addrStr , stamps .DefaultPort )
265282 ipOnly := host
266- cachedIP , _ := xTransport .loadCachedIP (host )
283+ cachedIP , _ , _ := xTransport .loadCachedIP (host )
267284 network := "udp4"
268285 if cachedIP != nil {
269286 if ipv4 := cachedIP .To4 (); ipv4 != nil {
@@ -402,10 +419,12 @@ func (xTransport *XTransport) resolveAndUpdateCache(host string) error {
402419 if ParseIP (host ) != nil {
403420 return nil
404421 }
405- cachedIP , expired := xTransport .loadCachedIP (host )
406- if cachedIP != nil && ! expired {
422+ cachedIP , expired , updating := xTransport .loadCachedIP (host )
423+ if cachedIP != nil && ( ! expired || updating ) {
407424 return nil
408425 }
426+ xTransport .markUpdatingCachedIP (host )
427+
409428 var foundIP net.IP
410429 var ttl time.Duration
411430 var err error
0 commit comments