func (r *resolver) resolveAndUpdate(item cacheItem) (cacheItem, error) { ips, err := net.LookupHost(item.host) if err != nil { if r.logger != nil { r.logger.Warnf("resolveAndUpdate %v: %v", item.host, err) } r.cacheLock.Lock() delete(r.cache, item.host) r.cacheLock.Unlock() return cacheItem{err: err}, err } if item.ips == nil || !util.StrSliceEqual(item.ips, ips) { if r.logger != nil { r.logger.Debugf("resolveAndUpdate: %s ips changed %v -> %v", item.host, item.ips, ips) } item.ips = ips item.err = err r.cacheLock.Lock() r.cache[item.host] = item r.cacheLock.Unlock() } return item, nil }
func NewClient(address string, p Protocol, c ClientCodec, connect_timeout, request_timeout time.Duration) *Client { ips, err := dns.LookupHostPort(address) if err != nil { log.Errorf("dns.LookupHostPort() faield: %v", err) // FIXME(antoxa): just reusing existing ips here, which actually sucks // this only works because cli.Call() uses net.Dial() which resolves the name again } canUseClient := func(client *Client) bool { // readLoop() might be modifying this conn // but don't really need to lock for ips comparison, since ips are never modified for existing client client.lk.Lock() defer client.lk.Unlock() // TODO(antoxa): can just use one ip for client and recheck not full equality // but only if new ips contain old ip if !util.StrSliceEqual(client.ips, ips) { return false } if client.closed { return false } return true } const max_tries = 3 // arbitrary limit, i know for done_tries := 0; done_tries < max_tries; done_tries++ { client := Pcm.GetClient(address) if client == nil { break } if !canUseClient(client) { client.closeNoReuse() continue } log.Debugf("reused existing client %p for %s (after %d tries)", client, address, done_tries) return client } log.Debugf("creating new cli for %s", address) return &Client{ address: address, ips: ips, Proto: p, Codec: c, connect_timeout: connect_timeout, request_timeout: request_timeout, } }