You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2012/12/10 18:03:21 UTC

[1/2] git commit: TS-1422 TS-1307 : Update HostDB for better IPv6 handling.

Updated Branches:
  refs/heads/master 998810c16 -> 043815e7a


TS-1422 TS-1307 : Update HostDB for better IPv6 handling.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/043815e7
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/043815e7
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/043815e7

Branch: refs/heads/master
Commit: 043815e7a7a67b79a2ca6fdc3f6d6751e5150411
Parents: 998810c
Author: Alan M. Carroll <am...@network-geographics.com>
Authored: Mon Dec 10 11:02:42 2012 -0600
Committer: Alan M. Carroll <am...@network-geographics.com>
Committed: Mon Dec 10 11:02:42 2012 -0600

----------------------------------------------------------------------
 CHANGES                               |    5 +
 iocore/dns/DNS.cc                     |  122 +++---
 iocore/dns/I_DNSProcessor.h           |  107 ++++-
 iocore/dns/P_DNSProcessor.h           |    6 +-
 iocore/hostdb/HostDB.cc               |  713 ++++++++++++++++------------
 iocore/hostdb/I_HostDBProcessor.h     |   62 ++-
 iocore/hostdb/P_HostDB.h              |    6 +-
 iocore/hostdb/P_HostDBProcessor.h     |  154 ++++--
 iocore/hostdb/P_MultiCache.h          |    4 +-
 lib/records/I_RecHttp.h               |   13 +
 lib/records/RecHttp.cc                |   64 +++-
 lib/ts/INK_MD5.h                      |    6 +-
 lib/ts/ink_inet.h                     |   43 ++-
 lib/ts/ink_res_init.cc                |   84 ++++
 lib/ts/ink_res_mkquery.cc             |   35 ++
 lib/ts/ink_resolver.h                 |   67 +++
 mgmt/Main.cc                          |    1 +
 mgmt/RecordsConfig.cc                 |    2 +
 proxy/http/HttpAccept.cc              |    1 +
 proxy/http/HttpAccept.h               |   14 +-
 proxy/http/HttpClientSession.cc       |    5 +-
 proxy/http/HttpClientSession.h        |    2 +
 proxy/http/HttpProxyServerMain.cc     |    1 +
 proxy/http/HttpSM.cc                  |   71 ++--
 proxy/http/HttpTransact.cc            |  151 ++++---
 proxy/http/HttpTransact.h             |   21 +-
 proxy/logging/LogCollationClientSM.cc |    2 +-
 27 files changed, 1181 insertions(+), 581 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index d37ae5a..39d0ffb 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 3.3.1
 
+  *) [TS-1307] [TS-1422] Changed HostDB handling of IPv4 and
+   IPv6. Address resolution preferences can be configured globally and
+   per HTTP proxy port. Transparent connections can now fail over even
+   if use_client_target_addr is set.
+
   *) [TS-1616] authorization proxy plugin
 
   *) [TS-1615] Some spelling errors in source code

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/dns/DNS.cc
----------------------------------------------------------------------
diff --git a/iocore/dns/DNS.cc b/iocore/dns/DNS.cc
index 63f638f..31dda7a 100644
--- a/iocore/dns/DNS.cc
+++ b/iocore/dns/DNS.cc
@@ -57,20 +57,12 @@ char *dns_local_ipv4 = NULL;
 int dns_thread = 0;
 int dns_prefer_ipv6 = 0;
 namespace {
-  inline bool prefer_ipv6_p() { return 0 != dns_prefer_ipv6; }
-  inline int preferred_query_type() { return prefer_ipv6_p() ? T_AAAA : T_A; }
   // Currently only used for A and AAAA.
   inline char const* QtypeName(int qtype) {
     return T_AAAA == qtype ? "AAAA" : T_A == qtype ? "A" : "*";
   }
-  inline void set_loopback(sockaddr* addr) {
-    if (prefer_ipv6_p())
-      ats_ip6_set(addr, in6addr_loopback, htons(DOMAIN_SERVICE_PORT));
-    else
-      ats_ip4_set(addr, htonl(INADDR_LOOPBACK), htons(DOMAIN_SERVICE_PORT));
-  }
-  inline void set_loopback(IpEndpoint* ip) {
-    set_loopback(&ip->sa);
+  inline bool is_addr_query(int qtype) {
+    return qtype == T_A || qtype == T_AAAA;
   }
 }
 
@@ -116,10 +108,6 @@ void HostEnt::free() {
   dnsBufAllocator.free(this);
 }
 
-inline bool is_addr_type_reply(int qtype) {
-  return qtype == T_A || qtype == T_AAAA;
-}
-
 void
 make_ipv4_ptr(in_addr_t addr, char *buffer)
 {
@@ -193,7 +181,6 @@ DNSProcessor::start(int) {
   IOCORE_ReadConfigStringAlloc(dns_local_ipv6, "proxy.config.dns.local_ipv6");
   IOCORE_ReadConfigStringAlloc(dns_resolv_conf, "proxy.config.dns.resolv_conf");
   IOCORE_EstablishStaticConfigInt32(dns_thread, "proxy.config.dns.dedicated_thread");
-  IOCORE_EstablishStaticConfigInt32(dns_prefer_ipv6, "proxy.config.dns.prefer_ipv6");
 
   if (dns_thread > 0) {
     ET_DNS = eventProcessor.spawn_event_threads(1, "ET_DNS"); // TODO: Hmmm, should we just get a single thread some other way?
@@ -353,23 +340,34 @@ ink_dn_expand(const u_char *msg, const u_char *eom, const u_char *comp_dn, u_cha
 DNSProcessor::DNSProcessor()
   : thread(NULL), handler(NULL)
 {
-  memset(&l_res, 0, sizeof(l_res));
-  memset(&local_ipv6, 0, sizeof local_ipv6);
-  memset(&local_ipv4, 0, sizeof local_ipv4);
+  ink_zero(l_res);
+  ink_zero(local_ipv6);
+  ink_zero(local_ipv4);
 }
 
 void
-DNSEntry::init(const char *x, int len, int qtype_arg,
-               Continuation *acont, DNSHandler *adnsH, int dns_lookup_timeout)
+DNSEntry::init(const char *x, int len, int qtype_arg, Continuation* acont,
+               DNSProcessor::Options const& opt)
 {
   qtype = qtype_arg;
+  host_res_style = opt.host_res_style;
+  if (is_addr_query(qtype)) {
+      // adjust things based on family preference.
+      if (HOST_RES_IPV4 == host_res_style ||
+          HOST_RES_IPV4_ONLY == host_res_style) {
+          qtype = T_A;
+      } else if (HOST_RES_IPV6 == host_res_style ||
+                 HOST_RES_IPV6_ONLY == host_res_style) {
+          qtype = T_AAAA;
+      }
+  }
   submit_time = ink_get_hrtime();
   action = acont;
   submit_thread = acont->mutex->thread_holding;
 
 #ifdef SPLIT_DNS
   if (SplitDNSConfig::gsplit_dns_enabled) {
-    dnsH = adnsH ? adnsH : dnsProcessor.handler;
+    dnsH = opt.handler ? opt.handler : dnsProcessor.handler;
   } else {
     dnsH = dnsProcessor.handler;
   }
@@ -378,11 +376,11 @@ DNSEntry::init(const char *x, int len, int qtype_arg,
   dnsH = dnsProcessor.handler;
 #endif // SPLIT_DNS
 
-  dnsH->txn_lookup_timeout = dns_lookup_timeout;
+  dnsH->txn_lookup_timeout = opt.timeout;
 
   mutex = dnsH->mutex;
 
-  if (is_addr_type_reply(qtype) || qtype == T_SRV) {
+  if (is_addr_query(qtype) || qtype == T_SRV) {
     if (len) {
       len = len > (MAXDNAME - 1) ? (MAXDNAME - 1) : len;
       memcpy(qname, x, len);
@@ -393,11 +391,11 @@ DNSEntry::init(const char *x, int len, int qtype_arg,
       qname_len = strlen(qname);
     }
   } else {                    //T_PTR
-    sockaddr const* ip = reinterpret_cast<sockaddr const*>(x);
-    if (ats_is_ip6(ip))
-      make_ipv6_ptr(&ats_ip6_addr_cast(ip), qname);
-    else if (ats_is_ip4(ip))
-      make_ipv4_ptr(ats_ip4_addr_cast(ip), qname);
+    IpAddr const* ip = reinterpret_cast<IpAddr const*>(x);
+    if (ip->isIp6())
+      make_ipv6_ptr(&ip->_addr._ip6, qname);
+    else if (ip->isIp4())
+      make_ipv4_ptr(ip->_addr._ip4, qname);
     else
       ink_assert(!"T_PTR query to DNS must be IP address.");
   }
@@ -459,14 +457,12 @@ DNSHandler::open_con(sockaddr const* target, bool failed, int icon)
 
 void
 DNSHandler::validate_ip() {
-  if (!ats_is_ip(&ip.sa)) {
+  if (!ip.isValid()) {
     // Invalid, switch to default.
     // seems that res_init always sets m_res.nscount to at least 1!
     if (!m_res->nscount || !ats_ip_copy(&ip.sa, &m_res->nsaddr_list[0].sa)) {
-      Warning("bad nameserver config, fallback to %s loopback",
-        prefer_ipv6_p() ? "IPv6" : "IPv4"
-      );
-      set_loopback(&ip);
+      Warning("bad nameserver config, fallback to loopback");
+      ip.setToLoopback(AF_INET);
     }
   }
 }
@@ -572,7 +568,7 @@ DNSHandler::retry_named(int ndx, ink_hrtime t, bool reopen)
 
   char buffer[MAX_DNS_PACKET_LEN];
   Debug("dns", "trying to resolve '%s' from DNS connection, ndx %d", try_server_names[try_servers], ndx);
-  int r = _ink_res_mkquery(m_res, try_server_names[try_servers], preferred_query_type(), buffer);
+  int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer);
   try_servers = (try_servers + 1) % SIZE(try_server_names);
   ink_assert(r >= 0);
   if (r >= 0) {                 // looking for a bounce
@@ -595,7 +591,7 @@ DNSHandler::try_primary_named(bool reopen)
 
     last_primary_retry = t;
     Debug("dns", "trying to resolve '%s' from primary DNS connection", try_server_names[try_servers]);
-    int r = _ink_res_mkquery(m_res, try_server_names[try_servers], preferred_query_type(), buffer);
+    int r = _ink_res_mkquery(m_res, try_server_names[try_servers], T_A, buffer);
     // if try_server_names[] is not full, round-robin within the
     // filled entries.
     if (local_num_entries < DEFAULT_NUM_TRY_SERVER)
@@ -647,7 +643,7 @@ DNSHandler::failover()
       ats_ip_ntop(&target.sa, buff2, sizeof(buff2))
     );
 
-    if (!ats_is_ip(&target.sa)) set_loopback(&target.sa);
+    if (!target.isValid()) target.setToLoopback(AF_INET);
 
     open_con(&target.sa, true, name_server);
     if (n_con <= name_server)
@@ -876,7 +872,7 @@ get_entry(DNSHandler *h, char *qname, int qtype)
 {
   for (DNSEntry *e = h->entries.head; e; e = (DNSEntry *) e->link.next) {
     if (e->qtype == qtype) {
-      if (is_addr_type_reply(qtype)) {
+      if (is_addr_query(qtype)) {
         if (!strcmp(qname, e->qname))
           return e;
       } else if (0 == memcmp(qname, e->qname, e->qname_len))
@@ -1091,14 +1087,15 @@ DNSEntry::mainEvent(int event, Event *e)
 }
 
 Action *
-DNSProcessor::getby(const char *x, int len, int type, Continuation *cont, DNSHandler *adnsH, int timeout) {
-  Debug("dns", "received query %s type = %d, timeout = %d", x, type, timeout);
+DNSProcessor::getby(const char *x, int len, int type, Continuation *cont, Options const& opt)
+{
+  Debug("dns", "received query %s type = %d, timeout = %d", x, type, opt.timeout);
   if (type == T_SRV) {
-    Debug("dns_srv", "DNSProcessor::getby attempting an SRV lookup for %s, timeout = %d", x, timeout);
+    Debug("dns_srv", "DNSProcessor::getby attempting an SRV lookup for %s, timeout = %d", x, opt.timeout);
   }
   DNSEntry *e = dnsEntryAllocator.alloc();
   e->retries = dns_retries;
-  e->init(x, len, type, cont, adnsH, timeout);
+  e->init(x, len, type, cont, opt);
   MUTEX_TRY_LOCK(lock, e->mutex, this_ethread());
   if (!lock)
     thread->schedule_imm(e);
@@ -1126,18 +1123,6 @@ dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry) {
       --(e->retries);
       write_dns(h);
       return;
-    } else if (prefer_ipv6_p() && e->qtype == T_AAAA) {
-      Debug("dns", "Trying A after AAAA failure for %s", e->qname);
-      e->retries = dns_retries;
-      e->qtype = T_A;
-      write_dns(h);
-      return;
-    } else if (!prefer_ipv6_p() && e->qtype == T_A) {
-      Debug("dns", "Trying AAAA after A failure for %s", e->qname);
-      e->retries = dns_retries;
-      e->qtype = T_AAAA;
-      write_dns(h);
-      return;
     } else if (e->domains && *e->domains) {
       do {
         Debug("dns", "domain extending %s", e->qname);
@@ -1196,15 +1181,20 @@ dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry) {
   }
   h->entries.remove(e);
 
-  if (is_addr_type_reply(e->qtype)) {
-    ip_text_buffer buff;
-    char const* ptr = "<none>";
-    if (ent) ptr = inet_ntop(e->qtype == T_AAAA ? AF_INET6 : AF_INET, ent->ent.h_addr_list[0], buff, sizeof(buff));
-    Debug("dns", "%s result for %s = %s retry %d",
-      ent ? "SUCCESS" : "FAIL", e->qname, ptr, retry);
-  } else {
-    Debug("dns", "%s result for %s = %s retry %d",
-          ent ? "SUCCESS" : "FAIL", e->qname, (ent != NULL ? ent->ent.h_name : "<not found>"), retry);
+  if (is_debug_tag_set("dns")) {
+    if (is_addr_query(e->qtype)) {
+      ip_text_buffer buff;
+      char const* ptr = "<none>";
+      char const* result = "FAIL";
+      if (ent) {
+        result = "SUCCESS";
+        ptr = inet_ntop(e->qtype == T_AAAA ? AF_INET6 : AF_INET, ent->ent.h_addr_list[0], buff, sizeof(buff));
+      }
+      Debug("dns", "%s result for %s = %s retry %d", result, e->qname, ptr, retry);
+    } else {
+      Debug("dns", "%s result for %s = %s af=%d retry %d",
+            ent ? "SUCCESS" : "FAIL", e->qname, (ent != NULL ? ent->ent.h_name : "<not found>"), ent->ent.h_addrtype, retry);
+    }
   }
 
   if (ent) {
@@ -1398,7 +1388,7 @@ dns_process(DNSHandler *handler, HostEnt *buf, int len)
     }
 
     cp += n + QFIXEDSZ;
-    if (is_addr_type_reply(e->qtype)) {
+    if (is_addr_query(e->qtype)) {
       if (-1 == rname_len)
         n = strlen((char *)bp) + 1;
       else
@@ -1473,7 +1463,7 @@ dns_process(DNSHandler *handler, HostEnt *buf, int len)
       //
       // Decode cname
       //
-      if (is_addr_type_reply(e->qtype) && type == T_CNAME) {
+      if (is_addr_query(e->qtype) && type == T_CNAME) {
         if (ap >= &buf->host_aliases[DNS_MAX_ALIASES - 1])
           continue;
         n = ink_dn_expand((u_char *) h, eom, cp, tbuf, sizeof(tbuf));
@@ -1551,7 +1541,7 @@ dns_process(DNSHandler *handler, HostEnt *buf, int len)
 
         buf->srv_hosts.insert(s);
         ++num_srv;
-      } else if (is_addr_type_reply(type)) {
+      } else if (is_addr_query(type)) {
         if (answer) {
           if (n != buf->ent.h_length) {
             cp += n;
@@ -1700,7 +1690,7 @@ struct DNSRegressionContinuation: public Continuation
       }
     }
     if (i < hosts) {
-      dnsProcessor.gethostbyname(this, hostnames[i]);
+        dnsProcessor.gethostbyname(this, hostnames[i], DNSProcessor::Options().setHostResStyle(HOST_RES_IPV4_ONLY));
       ++i;
       return EVENT_CONT;
     } else {

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/dns/I_DNSProcessor.h
----------------------------------------------------------------------
diff --git a/iocore/dns/I_DNSProcessor.h b/iocore/dns/I_DNSProcessor.h
index 2375178..28c13a5 100644
--- a/iocore/dns/I_DNSProcessor.h
+++ b/iocore/dns/I_DNSProcessor.h
@@ -68,17 +68,50 @@ struct DNSProcessor: public Processor
   // Public Interface
   //
 
+  /// Options for host name resolution.
+  struct Options {
+    typedef Options self; ///< Self reference type.
+
+    /// Query handler to use.
+    /// Default: single threaded handler.
+    DNSHandler* handler;
+    /// Query timeout value.
+    /// Default: @c DEFAULT_DNS_TIMEOUT (or as set in records.config)
+    int timeout; ///< Timeout value for request.
+    /// Host resolution style.
+    /// Default: IPv4, IPv6 ( @c HOST_RES_IPV4 )
+    HostResStyle host_res_style;
+
+    /// Default constructor.
+    Options();
+
+    /// Set @a handler option.
+    /// @return This object.
+    self& setHandler(DNSHandler* handler);
+
+    /// Set @a timeout option.
+    /// @return This object.
+    self& setTimeout(int timeout);
+
+    /// Set host query @a style option.
+    /// @return This object.
+    self& setHostResStyle(HostResStyle style);
+
+    /// Reset to default constructed values.
+    /// @return This object.
+    self& reset();
+  };
+
   // DNS lookup
   //   calls: cont->handleEvent( DNS_EVENT_LOOKUP, HostEnt *ent) on success
   //          cont->handleEvent( DNS_EVENT_LOOKUP, NULL) on failure
   // NOTE: the HostEnt *block is freed when the function returns
   //
 
-  Action *gethostbyname(Continuation *cont, const char *name, DNSHandler *adnsH = 0, int timeout = 0);
-  Action *getSRVbyname(Continuation *cont, const char *name, DNSHandler *adnsH = 0, int timeout = 0);
-  Action *gethostbyname(Continuation *cont, const char *name, int len, int timeout = 0);
-  Action *gethostbyaddr(Continuation *cont, in_addr_t ip, int timeout = 0);
-  Action *gethostbyaddr(Continuation *cont, sockaddr const* ip, int timeout = 0);
+  Action *gethostbyname(Continuation *cont, const char *name, Options const& opt);
+  Action *getSRVbyname(Continuation *cont, const char *name, Options const& opt);
+  Action *gethostbyname(Continuation *cont, const char *name, int len, Options const& opt);
+  Action *gethostbyaddr(Continuation *cont, IpAddr const* ip, Options const& opt);
 
 
   // Processor API
@@ -100,7 +133,16 @@ struct DNSProcessor: public Processor
   ts_imp_res_state l_res;
   IpEndpoint local_ipv6;
   IpEndpoint local_ipv4;
-  Action *getby(const char *x, int len, int type, Continuation *cont, DNSHandler *adnsH = NULL, int timeout = 0);
+
+  /** Internal implementation for all getXbyY methods.
+      For host resolution queries pass @c T_A for @a type. It will be adjusted
+      as needed based on @a opt.host_res_style.
+
+      For address resolution ( @a type is @c T_PTR ), @a x should be a
+      @c sockaddr cast to  @c char @c const* .
+   */
+  Action *getby(const char *x, int len, int type, Continuation *cont, Options const& opt);
+
   void dns_init();
 };
 
@@ -115,35 +157,62 @@ extern DNSProcessor dnsProcessor;
 //
 
 inline Action *
-DNSProcessor::getSRVbyname(Continuation *cont, const char *name, DNSHandler *adnsH, int timeout)
+DNSProcessor::getSRVbyname(Continuation *cont, const char *name, Options const& opt)
 {
-  return getby(name, 0, T_SRV, cont, adnsH, timeout);
+  return getby(name, 0, T_SRV, cont, opt);
 }
 
 inline Action *
-DNSProcessor::gethostbyname(Continuation *cont, const char *name, DNSHandler *adnsH, int timeout)
+DNSProcessor::gethostbyname(Continuation *cont, const char *name, Options const& opt)
 {
-  return getby(name, 0, T_A, cont, adnsH, timeout);
+  return getby(name, 0, T_A, cont, opt);
 }
 
 inline Action *
-DNSProcessor::gethostbyname(Continuation *cont, const char *name, int len, int timeout)
+DNSProcessor::gethostbyname(Continuation *cont, const char *name, int len, Options const& opt)
 {
-  return getby(name, len, T_A, cont, NULL, timeout);
+  return getby(name, len, T_A, cont, opt);
 }
 
 inline Action *
-DNSProcessor::gethostbyaddr(Continuation *cont, in_addr_t addr, int timeout)
+DNSProcessor::gethostbyaddr(Continuation *cont, IpAddr const* addr, Options const& opt)
 {
-  sockaddr_in ip;
-  ats_ip4_set(&ip, addr);
-  return getby(reinterpret_cast<char const*>(&ip), 0, T_PTR, cont, NULL, timeout);
+  return getby(reinterpret_cast<char const*>(addr), 0, T_PTR, cont, opt);
 }
 
-inline Action *
-DNSProcessor::gethostbyaddr(Continuation *cont, sockaddr const* addr, int timeout)
+inline DNSProcessor::Options::Options()
+                    : handler(0)
+                    , timeout(0)
+                    , host_res_style(HOST_RES_IPV4)
+{
+}
+
+inline DNSProcessor::Options&
+DNSProcessor::Options::setHandler(DNSHandler* h)
+{
+  handler = h;
+  return *this;
+}
+
+inline DNSProcessor::Options&
+DNSProcessor::Options::setTimeout(int t)
+{
+  timeout = t;
+  return *this;
+}
+
+inline DNSProcessor::Options&
+DNSProcessor::Options::setHostResStyle(HostResStyle style)
+{
+  host_res_style = style;
+  return *this;
+}
+
+inline DNSProcessor::Options&
+DNSProcessor::Options::reset()
 {
-  return getby(reinterpret_cast<char const*>(addr), 0, T_PTR, cont, NULL, timeout);
+  *this = Options();
+  return *this;
 }
 
 void ink_dns_init(ModuleVersion version);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/dns/P_DNSProcessor.h
----------------------------------------------------------------------
diff --git a/iocore/dns/P_DNSProcessor.h b/iocore/dns/P_DNSProcessor.h
index 3f74082..e5b79f8 100644
--- a/iocore/dns/P_DNSProcessor.h
+++ b/iocore/dns/P_DNSProcessor.h
@@ -148,7 +148,8 @@ extern RecRawStatBlock *dns_rsb;
 struct DNSEntry: public Continuation
 {
   int id[MAX_DNS_RETRIES];
-  int qtype;
+  int qtype; ///< Type of query to send.
+  HostResStyle host_res_style; ///< Preferred IP address family.
   int retries;
   int which_ns;
   ink_hrtime submit_time;
@@ -171,11 +172,12 @@ struct DNSEntry: public Continuation
   int delayEvent(int event, Event *e);
   int post(DNSHandler *h, HostEnt *ent);
   int postEvent(int event, Event *e);
-  void init(const char *x, int len, int qtype_arg, Continuation *acont, DNSHandler *adnsH, int timeout);
+  void init(const char *x, int len, int qtype_arg, Continuation *acont, DNSProcessor::Options const& opt);
 
    DNSEntry()
      : Continuation(NULL),
        qtype(0),
+       host_res_style(HOST_RES_NONE),
        retries(DEFAULT_DNS_RETRIES),
        which_ns(NO_NAMESERVER_SELECTED), submit_time(0), send_time(0), qname_len(0), domains(0),
        timeout(0), result_ent(0), dnsH(0), written_flag(false), once_written_flag(false), last(false)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/hostdb/HostDB.cc
----------------------------------------------------------------------
diff --git a/iocore/hostdb/HostDB.cc b/iocore/hostdb/HostDB.cc
index b05b4f7..418a2ff 100644
--- a/iocore/hostdb/HostDB.cc
+++ b/iocore/hostdb/HostDB.cc
@@ -47,6 +47,8 @@
 HostDBProcessor hostDBProcessor;
 int HostDBProcessor::hostdb_strict_round_robin = 0;
 int HostDBProcessor::hostdb_timed_round_robin = 0;
+HostDBProcessor::Options const HostDBProcessor::DEFAULT_OPTIONS;
+HostDBContinuation::Options const HostDBContinuation::DEFAULT_OPTIONS;
 int hostdb_enable = true;
 int hostdb_migrate_on_demand = true;
 int hostdb_cluster = false;
@@ -70,8 +72,7 @@ ClassAllocator<HostDBContinuation> hostDBContAllocator("hostDBContAllocator");
 
 // Static configuration information
 
-HostDBCache
-  hostDB;
+HostDBCache hostDB;
 
 #ifdef NON_MODULAR
 static  Queue <HostDBContinuation > remoteHostDBQueue[MULTI_CACHE_PARTITIONS];
@@ -109,6 +110,20 @@ ip_addr_set(
   else ats_ip_invalidate(ip);
 }
 
+static inline void
+ip_addr_set(
+  IpAddr& ip, ///< Target storage.
+  uint8_t af, ///< Address format.
+  void* ptr ///< Raw address data
+) {
+  if (AF_INET6 == af)
+    ip = *static_cast<in6_addr*>(ptr);
+  else if (AF_INET == af)
+    ip = *static_cast<in_addr_t*>(ptr);
+  else
+    ip.invalidate();
+}
+
 inline void
 hostdb_cont_free(HostDBContinuation * cont)
 {
@@ -119,6 +134,29 @@ hostdb_cont_free(HostDBContinuation * cont)
   hostDBContAllocator.free(cont);
 }
 
+/* Check whether a resolution fail should lead to a retry.
+   The @a mark argument is updated if appropriate.
+   @return @c true if @a mark was updated, @c false if no retry should be done.
+*/
+static inline bool
+check_for_retry(HostDBMark& mark, HostResStyle style) {
+  bool zret = true;
+  if (HOSTDB_MARK_IPV4 == mark && HOST_RES_IPV4 == style)
+    mark = HOSTDB_MARK_IPV6;
+  else if (HOSTDB_MARK_IPV6 == mark && HOST_RES_IPV6 == style)
+    mark = HOSTDB_MARK_IPV4;
+  else
+    zret = false;
+  return zret;
+}
+
+char const*
+string_for(HostDBMark mark) {
+  static char const* STRING[] = {
+    "Generic", "IPv4", "IPv6", "SRV"
+  };
+  return STRING[mark];
+}
 
 //
 // Function Prototypes
@@ -128,6 +166,29 @@ static Action *
 register_ShowHostDB(Continuation * c, HTTPHdr * h);
 #endif
 
+void
+HostDBMD5::refresh() {
+  if (host_name) {
+    char const* server_line = dns_server ? dns_server->x_dns_ip_line : 0;
+    make_md5(hash, host_name, host_len, port, server_line, db_mark);
+  } else {
+    // INK_MD5 the ip, pad on both sizes with 0's
+    // so that it does not intersect the string space
+    //
+    uint8_t buff[TS_IP6_SIZE+4];
+    int n = ip.isIp6() ? sizeof(in6_addr) : sizeof(in_addr_t);
+    memset(buff, 0, 2);
+    memcpy(buff+2, ip._addr._byte, n);
+    memset(buff + 2 + n , 0, 2);
+    hash.encodeBuffer(buff, n+4);
+  }
+}
+
+HostDBMD5::HostDBMD5()
+  : host_name(0), host_len(0), port(0),
+    dns_server(0), db_mark(HOSTDB_MARK_GENERIC)
+{
+} 
 
 HostDBCache::HostDBCache()
 {
@@ -231,7 +292,7 @@ struct HostDBTestRR: public Continuation
       else {
         *end = 0;
         outstanding++;
-        hostDBProcessor.getbyname_re(this, b);
+        hostDBProcessor.getbyname_re(this, b, 0);
         nb -= ((end + 1) - b);
         memcpy(b, end + 1, nb);
         if (!nb)
@@ -432,34 +493,45 @@ HostDBProcessor::start(int)
 
 
 void
-HostDBContinuation::init(
-  const char *hostname, int len,
-  sockaddr const* aip,
-  INK_MD5 & amd5, Continuation * cont, void *pDS, bool is_srv, int timeout
-) {
-  if (hostname) {
-    memcpy(name, hostname, len);
-    name[len] = 0;
-  } else
-    name[0] = 0;
-  dns_lookup_timeout = timeout;
-  namelen = len;
-  is_srv_lookup = is_srv;
-  ats_ip_copy(&ip.sa, aip);
-  md5 = amd5;
-  mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
-  m_pDS = pDS;
-  if (cont) {
-    action = cont;
+HostDBContinuation::init(HostDBMD5 const& the_md5, Options const& opt)
+{
+  md5 = the_md5;
+  if (md5.host_name) {
+    // copy to backing store.
+    if (md5.host_len > static_cast<int>(sizeof(md5_host_name_store)-1))
+      md5.host_len = sizeof(md5_host_name_store)-1;
+    memcpy(md5_host_name_store, md5.host_name, md5.host_len);
+  } else {
+    md5.host_len = 0;
+  }
+  md5_host_name_store[md5.host_len] = 0;
+  md5.host_name = md5_host_name_store;
+
+  host_res_style = opt.host_res_style;
+  dns_lookup_timeout = opt.timeout;
+  mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
+  if (opt.cont) {
+    action = opt.cont;
   } else {
     //ink_assert(!"this sucks");
     action.mutex = mutex;
   }
 }
 
+void
+HostDBContinuation::refresh_MD5() {
+  ProxyMutex* old_bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
+  // We're not pending DNS anymore.
+  remove_trigger_pending_dns();
+  md5.refresh();
+  // Update the mutex if it's from the bucket.
+  // Some call sites modify this after calling @c init so need to check.
+  if (old_bucket_mutex == mutex)
+    mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
+}
 
 void
-make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char *pDNSServers, int srv)
+make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char const* pDNSServers, HostDBMark mark)
 {
 #ifdef USE_MMH
   MMH_CTX ctx;
@@ -468,7 +540,8 @@ make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char *pDNSServe
   unsigned short p = port;
   p = htons(p);
   ink_code_incr_MMH_update(&ctx, (char *) &p, 2);
-  ink_code_incr_MMH_update(&ctx, (char *) &srv, 4);     /* FIXME: check this */
+  uint8_t m = static_cast<uint8_t>(mark);
+  ink_code_incr_MMH_update(&ctx, (char *) &m, sizeof(m));     /* FIXME: check this */
   if (pDNSServers)
     ink_code_incr_MMH_update(&ctx, pDNSServers, strlen(pDNSServers));
   ink_code_incr_MMH_final((char *) &md5, &ctx);
@@ -479,7 +552,8 @@ make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char *pDNSServe
   unsigned short p = port;
   p = htons(p);
   ink_code_incr_md5_update(&ctx, (char *) &p, 2);
-  ink_code_incr_MMH_update(&ctx, (char *) &srv, 4);     /* FIXME: check this */
+  uint8_t m = static_cast<uint8_t>(mark);
+  ink_code_incr_md5_update(&ctx, (char *) &m, sizeof(m));     /* FIXME: check this */
   if (pDNSServers)
     ink_code_incr_md5_update(&ctx, pDNSServers, strlen(pDNSServers));
   ink_code_incr_md5_final((char *) &md5, &ctx);
@@ -549,17 +623,44 @@ Ldelete:
   return false;
 }
 
+inline HostResStyle
+host_res_style_for(sockaddr const* ip) {
+  return ats_is_ip6(ip) ? HOST_RES_IPV6_ONLY : HOST_RES_IPV4_ONLY;
+}
+
+inline HostResStyle
+host_res_style_for(HostDBMark mark) {
+  return HOSTDB_MARK_IPV4 == mark ? HOST_RES_IPV4_ONLY
+    : HOSTDB_MARK_IPV6 == mark ? HOST_RES_IPV6_ONLY
+    : HOST_RES_NONE
+    ;
+}
+
+inline HostDBMark
+db_mark_for(HostResStyle style) {
+  HostDBMark zret = HOSTDB_MARK_GENERIC;
+  if (HOST_RES_IPV4 == style || HOST_RES_IPV4_ONLY == style)
+    zret = HOSTDB_MARK_IPV4;
+  else if (HOST_RES_IPV6 == style || HOST_RES_IPV6_ONLY == style)
+    zret = HOSTDB_MARK_IPV6;
+  return zret;
+}
+
+inline HostDBMark
+db_mark_for(sockaddr const* ip) {
+  return ats_is_ip6(ip) ? HOSTDB_MARK_IPV6 : HOSTDB_MARK_IPV4;
+}
 
 HostDBInfo *
-probe(ProxyMutex *mutex, INK_MD5 & md5, const char *hostname, int len, sockaddr const* ip, void *pDS, bool ignore_timeout,
-      bool is_srv_lookup)
+probe(ProxyMutex *mutex, HostDBMD5 const& md5, bool ignore_timeout)
 {
-  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
+  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets))->thread_holding);
   if (hostdb_enable) {
-    uint64_t folded_md5 = fold_md5(md5);
+    uint64_t folded_md5 = fold_md5(md5.hash);
     HostDBInfo *r = hostDB.lookup_block(folded_md5, hostDB.levels);
-    Debug("hostdb", "probe %s %" PRIx64" %d [ignore_timeout = %d]", hostname, folded_md5, !!r, ignore_timeout);
-    if (r && md5[1] == r->md5_high) {
+    Debug("hostdb", "probe %.*s %" PRIx64 " %d [ignore_timeout = %d]",
+          md5.host_len, md5.host_name, folded_md5, !!r, ignore_timeout);
+    if (r && md5.hash[1] == r->md5_high) {
 
       // Check for timeout (fail probe)
       //
@@ -567,7 +668,7 @@ probe(ProxyMutex *mutex, INK_MD5 & md5, const char *hostname, int len, sockaddr
         Debug("hostdb", "HostDB entry was set as deleted");
         return NULL;
       } else if (r->failed()) {
-        Debug("hostdb", "%s failed", hostname);
+        Debug("hostdb", "'%.*s' failed", md5.host_len, md5.host_name);
         if (r->is_ip_fail_timeout()) {
           Debug("hostdb", "fail timeout %u", r->ip_interval());
           return NULL;
@@ -593,15 +694,17 @@ probe(ProxyMutex *mutex, INK_MD5 & md5, const char *hostname, int len, sockaddr
       // we are beyond our TTL but we choose to serve for another N seconds [hostdb_serve_stale_but_revalidate seconds]
       if ((!ignore_timeout && r->is_ip_stale()
 #ifdef NON_MODULAR
-           && !cluster_machine_at_depth(master_hash(md5))
+           && !cluster_machine_at_depth(master_hash(md5.hash))
 #endif
            && !r->reverse_dns) || (r->is_ip_timeout() && r->serve_stale_but_revalidate())) {
         Debug("hostdb", "stale %u %u %u, using it and refreshing it", r->ip_interval(),
               r->ip_timestamp, r->ip_timeout_interval);
         r->refresh_ip();
-        if (!is_dotted_form_hostname(hostname)) {
+        if (!is_dotted_form_hostname(md5.host_name)) {
           HostDBContinuation *c = hostDBContAllocator.alloc();
-          c->init(hostname, len, ip, md5, NULL, pDS, is_srv_lookup, 0);
+          HostDBContinuation::Options copt;
+          copt.host_res_style = host_res_style_for(r->ip());
+          c->init(md5, copt);
           c->do_dns();
         }
       }
@@ -623,20 +726,21 @@ probe(ProxyMutex *mutex, INK_MD5 & md5, const char *hostname, int len, sockaddr
 HostDBInfo *
 HostDBContinuation::insert(unsigned int attl)
 {
-  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
-  uint64_t folded_md5 = fold_md5(md5);
+  uint64_t folded_md5 = fold_md5(md5.hash);
+  int bucket = folded_md5 % hostDB.buckets;
+
+  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(bucket)->thread_holding);
   // remove the old one to prevent buildup
   HostDBInfo *old_r = hostDB.lookup_block(folded_md5, 3);
   if (old_r)
     hostDB.delete_block(old_r);
   HostDBInfo *r = hostDB.insert_block(folded_md5, NULL, 0);
-  Debug("hostdb_insert", "inserting in bucket %d", (int) (folded_md5 % hostDB.buckets));
-  r->md5_high = md5[1];
+  r->md5_high = md5.hash[1];
   if (attl > HOST_DB_MAX_TTL)
     attl = HOST_DB_MAX_TTL;
   r->ip_timeout_interval = attl;
   r->ip_timestamp = hostdb_current_interval;
-  Debug("hostdb", "inserting for: %s: (md5: %" PRIx64") now: %u timeout: %u ttl: %u", name, folded_md5, r->ip_timestamp,
+  Debug("hostdb", "inserting for: %.*s: (md5: %" PRIx64 ") bucket: %d now: %u timeout: %u ttl: %u", md5.host_len, md5.host_name, folded_md5, bucket, r->ip_timestamp,
         r->ip_timeout_interval, attl);
   return r;
 }
@@ -647,14 +751,11 @@ HostDBContinuation::insert(unsigned int attl)
 //
 Action *
 HostDBProcessor::getby(Continuation * cont,
-                       const char *hostname, int len, sockaddr const* ip, bool aforce_dns, int dns_lookup_timeout)
+                       const char *hostname, int len, sockaddr const* ip, bool aforce_dns, HostResStyle host_res_style, int dns_lookup_timeout)
 {
-  INK_MD5 md5;
-  char *pServerLine = 0;
-  void *pDS = 0;
+  HostDBMD5 md5;
   EThread *thread = this_ethread();
   ProxyMutex *mutex = thread->mutex;
-  unsigned short port = ats_ip_port_host_order(ip);
   ip_text_buffer ipb;
 
   HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
@@ -666,68 +767,62 @@ HostDBProcessor::getby(Continuation * cont,
     cont->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
     return ACTION_RESULT_DONE;
   }
+
+  // Load the MD5 data.
+  md5.host_name = hostname;
+  md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
+  md5.ip.assign(ip);
+  md5.port = ip ? ats_ip_port_host_order(ip) : 0;
+  md5.db_mark = db_mark_for(host_res_style);
 #ifdef SPLIT_DNS
   if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
     const char *scan = hostname;
+    // Is this a check for IPv4 address? Add check for IPv6?
     for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
     if ('\0' != *scan) {
-      void *pSD = (void *) SplitDNSConfig::acquire();
-      if (0 != pSD) {
-        pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
-
-        if (0 != pDS) {
-          pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
-        }
-      }
-      SplitDNSConfig::release((SplitDNS *) pSD);
+      SplitDNS* pSD = SplitDNSConfig::acquire();
+      if (0 != pSD)
+        md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
+      SplitDNSConfig::release(pSD);
     }
   }
 #endif // SPLIT_DNS
-
-  // if it is by name, INK_MD5 the name
-  //
-  if (hostname) {
-    if (!len)
-      len = strlen(hostname);
-    make_md5(md5, hostname, len, port, pServerLine);
-  } else {
-    // INK_MD5 the ip, pad on both sizes with 0's
-    // so that it does not intersect the string space
-    //
-    uint8_t buff[TS_IP6_SIZE+4];
-    memset(buff, 0, sizeof(buff));
-    if (ats_is_ip4(ip))
-      memcpy(buff+2, &ats_ip4_addr_cast(ip), sizeof(in_addr_t));
-    else if (ats_is_ip6(ip))
-      memcpy(buff+2, &ats_ip6_addr_cast(ip), sizeof(in6_addr));
-    md5.encodeBuffer(buff, sizeof buff);
-  }
+  md5.refresh();
 
   // Attempt to find the result in-line, for level 1 hits
   //
   if (!aforce_dns) {
-    // find the partition lock
-    //
-    // TODO: Could we reuse the "mutex" above safely? I think so, but not sure.
-    ProxyMutex *bmutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
-    MUTEX_TRY_LOCK(lock, bmutex, thread);
-    MUTEX_TRY_LOCK(lock2, cont->mutex, thread);
-
-    // If we can get the lock and a level 1 probe succeeds, return
-    //
-    if (lock && lock2) {
-      HostDBInfo *r = probe(bmutex, md5, hostname, len, ip, pDS);
-      if (r) {
-        Debug("hostdb", "immediate answer for %s",
-          hostname ? hostname 
-          : ats_is_ip(ip) ? ats_ip_ntop(ip, ipb, sizeof ipb)
-          : "<null>"
-        );
-        HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
-        reply_to_cont(cont, r);
-        return ACTION_RESULT_DONE;
+    bool loop;
+    do {
+      loop = false; // Only loop on explicit set for retry.
+      // find the partition lock
+      //
+      // TODO: Could we reuse the "mutex" above safely? I think so but not sure.
+      ProxyMutex *bmutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
+      MUTEX_TRY_LOCK(lock, bmutex, thread);
+      MUTEX_TRY_LOCK(lock2, cont->mutex, thread);
+
+      if (lock && lock2) {
+        // If we can get the lock and a level 1 probe succeeds, return
+        HostDBInfo *r = probe(bmutex, md5, aforce_dns);
+        if (r) {
+          if (r->failed() && hostname)
+            loop = check_for_retry(md5.db_mark, host_res_style);
+          if (!loop) {
+            // No retry -> final result. Return it.
+            Debug("hostdb", "immediate answer for %s",
+                  hostname ? hostname 
+                  : ats_is_ip(ip) ? ats_ip_ntop(ip, ipb, sizeof ipb)
+                  : "<null>"
+              );
+            HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
+            reply_to_cont(cont, r);
+            return ACTION_RESULT_DONE;
+          }
+          md5.refresh();
+        }
       }
-    }
+    } while (loop);
   }
   Debug("hostdb", "delaying force %d answer for %s", aforce_dns,
     hostname ? hostname 
@@ -739,9 +834,12 @@ Lretry:
   // Otherwise, create a continuation to do a deeper probe in the background
   //
   HostDBContinuation *c = hostDBContAllocator.alloc();
-  c->init(hostname, len, ip, md5, cont, pDS, false, dns_lookup_timeout);
-  c->action = cont;
-  c->force_dns = aforce_dns;
+  HostDBContinuation::Options opt;
+  opt.timeout = dns_lookup_timeout;
+  opt.force_dns = aforce_dns;
+  opt.cont = cont;
+  opt.host_res_style = host_res_style;
+  c->init(md5, opt);
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 
   // Since ProxyMutexPtr has a cast operator, gcc-3.x get upset
@@ -760,46 +858,42 @@ Lretry:
 // Wrapper from getbyname to getby
 //
 Action *
-HostDBProcessor::getbyname_re(Continuation * cont, const char *ahostname, int len, int port, int flags)
+HostDBProcessor::getbyname_re(Continuation * cont, const char *ahostname, int len, Options const& opt)
 {
   bool force_dns = false;
   EThread *thread = this_ethread();
   ProxyMutex *mutex = thread->mutex;
-  sockaddr_in ip;
-
-  ats_ip4_set(&ip, INADDR_ANY, htons(port));
 
-  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
+  if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
     force_dns = true;
-  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
+  else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
     force_dns = (hostdb_re_dns_on_reload ? true : false);
     if (force_dns)
       HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
   }
-  return getby(cont, ahostname, len, ats_ip_sa_cast(&ip), force_dns);
+  return getby(cont, ahostname, len, 0, force_dns, opt.host_res_style, opt.timeout);
 }
 
 
 /* Support SRV records */
 Action *
 HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info,
-                                  const char *hostname, int len, int port, int flags, int dns_lookup_timeout)
+                                  const char *hostname, int len, Options const& opt)
 {
   ink_debug_assert(cont->mutex->thread_holding == this_ethread());
   bool force_dns = false;
   EThread *thread = cont->mutex->thread_holding;
   ProxyMutex *mutex = thread->mutex;
 
-  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
+  if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
     force_dns = true;
-  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
+  else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
     force_dns = (hostdb_re_dns_on_reload ? true : false);
     if (force_dns)
       HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
   }
 
-  INK_MD5 md5;
-  void *pDS = 0;
+  HostDBMD5 md5;
 
   HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
 
@@ -808,23 +902,21 @@ HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn proc
     return ACTION_RESULT_DONE;
   }
 
-  sockaddr_in ip;
-  ats_ip4_set(&ip, INADDR_ANY, htons(port));
-
-  if (!len)
-    len = strlen(hostname);
-
-  make_md5(md5, hostname, len, port, 0, 1);
+  md5.host_name = hostname;
+  md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
+  md5.port = opt.port;
+  md5.db_mark = HOSTDB_MARK_SRV;
+  md5.refresh();
 
   // Attempt to find the result in-line, for level 1 hits
   if (!force_dns) {
     // find the partition lock
-    ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
+    ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
     MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
 
     // If we can get the lock and a level 1 probe succeeds, return
     if (lock) {
-      HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, ats_ip_sa_cast(&ip), pDS, false, true);
+      HostDBInfo *r = probe(bucket_mutex, md5, false);
       if (r) {
         Debug("hostdb", "immediate SRV answer for %s from hostdb", hostname);
         Debug("dns_srv", "immediate SRV answer for %s from hostdb", hostname);
@@ -835,12 +927,15 @@ HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn proc
     }
   }
 
-  Debug("dns_srv", "delaying (force=%d) SRV answer for %s [timeout = %d]", force_dns, hostname, dns_lookup_timeout);
+  Debug("dns_srv", "delaying (force=%d) SRV answer for %.*s [timeout = %d]", force_dns, md5.host_len, md5.host_name, opt.timeout);
 
   // Otherwise, create a continuation to do a deeper probe in the background
   HostDBContinuation *c = hostDBContAllocator.alloc();
-  c->init(hostname, len, ats_ip_sa_cast(&ip), md5, cont, pDS, true, dns_lookup_timeout);
-  c->force_dns = force_dns;
+  HostDBContinuation::Options copt;
+  copt.timeout = opt.timeout;
+  copt.cont = cont;
+  copt.force_dns = force_dns;
+  c->init(md5, copt);
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 
   if (thread->mutex == cont->mutex) {
@@ -857,26 +952,22 @@ HostDBProcessor::getSRVbyname_imm(Continuation * cont, process_srv_info_pfn proc
 //
 Action *
 HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info,
-                               const char *hostname, int len, int port, int flags, int dns_lookup_timeout)
+                               const char *hostname, int len, Options const& opt)
 {
   ink_debug_assert(cont->mutex->thread_holding == this_ethread());
   bool force_dns = false;
   EThread *thread = cont->mutex->thread_holding;
   ProxyMutex *mutex = thread->mutex;
-  sockaddr_in ip_store;
-  sockaddr* ip = ats_ip_sa_cast(&ip_store);
-  ats_ip4_set(ip, INADDR_ANY, htons(port));
+  HostDBMD5 md5;
 
-  if (flags & HOSTDB_FORCE_DNS_ALWAYS)
+  if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
     force_dns = true;
-  else if (flags & HOSTDB_FORCE_DNS_RELOAD) {
+  else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
     force_dns = (hostdb_re_dns_on_reload ? true : false);
     if (force_dns)
       HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
   }
 
-  INK_MD5 md5;
-  void *pDS = 0;
   HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);
 
   if (!hostdb_enable || !*hostname) {
@@ -884,54 +975,62 @@ HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn proc
     return ACTION_RESULT_DONE;
   }
 
-  if (!len)
-    len = strlen(hostname);
-
+  md5.host_name = hostname;
+  md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
+  md5.port = opt.port;
+  md5.db_mark = db_mark_for(opt.host_res_style);
 #ifdef SPLIT_DNS
   if (SplitDNSConfig::isSplitDNSEnabled()) {
     const char *scan = hostname;
-    char *pServerLine = 0;
     for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
     if ('\0' != *scan) {
-      void *pSD = (void *) SplitDNSConfig::acquire();
-      if (0 != pSD) {
-        pDS = ((SplitDNS *) pSD)->getDNSRecord(hostname);
-
-        if (0 != pDS) {
-          pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
-        }
-      }
-      SplitDNSConfig::release((SplitDNS *) pSD);
+      SplitDNS* pSD = SplitDNSConfig::acquire();
+      if (0 != pSD)
+        md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(md5.host_name));
+      SplitDNSConfig::release(pSD);
     }
-    make_md5(md5, hostname, len, port, pServerLine);
-  } else
+  }
 #endif // SPLIT_DNS
-    make_md5(md5, hostname, len, port, 0);
+  md5.refresh();
 
   // Attempt to find the result in-line, for level 1 hits
   if (!force_dns) {
-    // find the partition lock
-    ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
-    MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
-
-    // If we can get the lock and a level 1 probe succeeds, return
-    if (lock) {
-      HostDBInfo *r = probe(bucket_mutex, md5, hostname, len, ip, pDS);
-      if (r) {
-        Debug("hostdb", "immediate answer for %s", hostname ? hostname : "<addr>");
-        HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
-        (cont->*process_hostdb_info) (r);
-        return ACTION_RESULT_DONE;
+    bool loop;
+    do {
+      loop = false; // loop only on explicit set for retry
+      // find the partition lock
+      ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
+      MUTEX_TRY_LOCK(lock, bucket_mutex, thread);
+
+      if (lock) {
+        // If we can get the lock do a level 1 probe for immediate result.
+        HostDBInfo *r = probe(bucket_mutex, md5, false);
+        if (r) {
+          if (r->failed()) // fail, see if we should retry with alternate
+            loop = check_for_retry(md5.db_mark, opt.host_res_style);
+          if (!loop) {
+            // No retry -> final result. Return it.
+            Debug("hostdb", "immediate answer for %.*s", md5.host_len, md5.host_name);
+            HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
+            (cont->*process_hostdb_info) (r);
+            return ACTION_RESULT_DONE;
+          }
+          md5.refresh(); // Update for retry.
+        }
       }
-    }
+    } while (loop);
   }
 
-  Debug("hostdb", "delaying force %d answer for %s [timeout %d]", force_dns, hostname, dns_lookup_timeout);
+  Debug("hostdb", "delaying force %d answer for %.*s [timeout %d]", force_dns, md5.host_len, md5.host_name, opt.timeout);
 
   // Otherwise, create a continuation to do a deeper probe in the background
   HostDBContinuation *c = hostDBContAllocator.alloc();
-  c->init(hostname, len, ip, md5, cont, pDS, false, dns_lookup_timeout);
-  c->force_dns = force_dns;
+  HostDBContinuation::Options copt;
+  copt.cont = cont;
+  copt.force_dns = force_dns;
+  copt.timeout = opt.timeout;
+  copt.host_res_style = opt.host_res_style;
+  c->init(md5, copt);
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 
   thread->schedule_in(c, MUTEX_RETRY_DELAY);
@@ -941,14 +1040,14 @@ HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn proc
 
 
 static void
-do_setby(HostDBInfo * r, HostDBApplicationInfo * app, const char *hostname, sockaddr const* ip)
+do_setby(HostDBInfo * r, HostDBApplicationInfo * app, const char *hostname, IpAddr const& ip)
 {
   HostDBRoundRobin *rr = r->rr();
 
   if (rr) {
     ink_assert(hostname);
     for (int i = 0; i < rr->n; i++) {
-      if (0 == ats_ip_addr_cmp(rr->info[i].ip(), ip)) {
+      if (rr->info[i].ip() == ip) {
         Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
         rr->info[i].app.allotment.application1 = app->allotment.application1;
         rr->info[i].app.allotment.application2 = app->allotment.application2;
@@ -956,7 +1055,7 @@ do_setby(HostDBInfo * r, HostDBApplicationInfo * app, const char *hostname, sock
       }
     }
   } else {
-    if (r->reverse_dns || (!r->round_robin && ats_ip_addr_eq(r->ip(), ip))) {
+    if (r->reverse_dns || (!r->round_robin && ip == r->ip())) {
       Debug("hostdb", "immediate setby for %s", hostname ? hostname : "<addr>");
       r->app.allotment.application1 = app->allotment.application1;
       r->app.allotment.application2 = app->allotment.application2;
@@ -971,44 +1070,30 @@ HostDBProcessor::setby(const char *hostname, int len, sockaddr const* ip, HostDB
   if (!hostdb_enable)
     return;
 
-  INK_MD5 md5;
-  unsigned short port = ats_ip_port_host_order(ip);
-
-  // if it is by name, INK_MD5 the name
-  //
-  if (hostname) {
-    if (!len)
-      len = strlen(hostname);
-    make_md5(md5, hostname, len, port);
-  } else {
-    // INK_MD5 the ip, pad on both sizes with 0's
-    // so that it does not intersect the string space
-    //
-    uint8_t buff[TS_IP6_SIZE+4];
-    memset(buff, 0, sizeof(buff));
-    if (ats_is_ip4(ip))
-      memcpy(buff+2, &ats_ip4_addr_cast(ip), sizeof(in_addr_t));
-    else if (ats_is_ip6(ip))
-      memcpy(buff+2, &ats_ip6_addr_cast(ip), sizeof(in6_addr));
-    md5.encodeBuffer(buff, sizeof buff);
-  }
+  HostDBMD5 md5;
+  md5.host_name = hostname;
+  md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
+  md5.ip.assign(ip);
+  md5.port = ip ? ats_ip_port_host_order(ip) : 0;
+  md5.db_mark = db_mark_for(ip);
+  md5.refresh();
 
   // Attempt to find the result in-line, for level 1 hits
 
-  ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
+  ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
   EThread *thread = this_ethread();
   MUTEX_TRY_LOCK(lock, mutex, thread);
 
   if (lock) {
-    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, 0);
+    HostDBInfo *r = probe(mutex, md5, false);
     if (r)
-      do_setby(r, app, hostname, ip);
+      do_setby(r, app, hostname, md5.ip);
     return;
   }
   // Create a continuation to do a deaper probe in the background
 
   HostDBContinuation *c = hostDBContAllocator.alloc();
-  c->init(hostname, len, ip, md5, NULL);
+  c->init(md5);
   c->app.allotment.application1 = app->allotment.application1;
   c->app.allotment.application2 = app->allotment.application2;
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::setbyEvent);
@@ -1021,17 +1106,18 @@ HostDBContinuation::setbyEvent(int event, Event * e)
 {
   NOWARN_UNUSED(event);
   NOWARN_UNUSED(e);
-  HostDBInfo *r = probe(mutex, md5, name, namelen, &ip.sa, 0);
+  HostDBInfo *r = probe(mutex, md5, false);
 
   if (r)
-    do_setby(r, &app, name, &ip.sa);
+    do_setby(r, &app, md5.host_name, md5.ip);
+
   hostdb_cont_free(this);
   return EVENT_DONE;
 }
 
 
 static int
-remove_round_robin(HostDBInfo * r, const char *hostname, sockaddr const* ip)
+remove_round_robin(HostDBInfo * r, const char *hostname, IpAddr const& ip)
 {
   if (r) {
     if (!r->round_robin)
@@ -1040,12 +1126,9 @@ remove_round_robin(HostDBInfo * r, const char *hostname, sockaddr const* ip)
     if (!rr)
       return false;
     for (int i = 0; i < rr->good; i++) {
-      if (0 == ats_ip_addr_cmp(rr->info[i].ip(), ip)) {
+      if (ip == rr->info[i].ip()) {
         ip_text_buffer b;
-        Debug("hostdb", "Deleting %s from '%s' round robin DNS entry",
-          ats_ip_ntop(ip, b, sizeof b),
-          hostname
-        );
+        Debug("hostdb", "Deleting %s from '%s' round robin DNS entry", ip.toString(b, sizeof b), hostname);
         HostDBInfo tmp = rr->info[i];
         rr->info[i] = rr->info[rr->good - 1];
         rr->info[rr->good - 1] = tmp;
@@ -1074,55 +1157,52 @@ remove_round_robin(HostDBInfo * r, const char *hostname, sockaddr const* ip)
   return false;
 }
 
-
+# if 0
 Action *
 HostDBProcessor::failed_connect_on_ip_for_name(Continuation * cont, sockaddr const* ip, const char *hostname, int len)
 {
-  INK_MD5 md5;
-  char *pServerLine = 0;
-  void *pDS = 0;
-  unsigned short port = ats_ip_port_host_order(ip);
-
+  HostDBMD5 md5;
+  md5.host_name = hostname;
+  md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
+  md5.ip.assign(ip);
+  md5.port = ip ? ats_ip_port_host_order(ip) : 0;
+  md5.db_mark = db_mark_for(ip);
 #ifdef SPLIT_DNS
   SplitDNS *pSD = 0;
   if (hostname && SplitDNSConfig::isSplitDNSEnabled()) {
     pSD = SplitDNSConfig::acquire();
 
-    if (0 != pSD) {
-      pDS = pSD->getDNSRecord(hostname);
-      pServerLine = ((DNSServer *) pDS)->x_dns_ip_line;
-    }
+    if (0 != pSD)
+      md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
     SplitDNSConfig::release(pSD);
   }
 #endif // SPLIT_DNS
+  md5.refresh();
 
-  make_md5(md5, hostname, len, port, pServerLine);
-  ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets));
+  ProxyMutex *mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
   EThread *thread = this_ethread();
   MUTEX_TRY_LOCK(lock, mutex, thread);
   if (lock) {
-    if (!hostdb_enable || NULL == pDS) {
+    if (!hostdb_enable || NULL == md5.dns_server) {
       if (cont)
         cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
       return ACTION_RESULT_DONE;
     }
-#ifdef SPLIT_DNS
-    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, pDS);
-#else
-    HostDBInfo *r = probe(mutex, md5, hostname, len, ip, 0);
-#endif
+    HostDBInfo *r = probe(mutex, md5, false);
     bool res = (remove_round_robin(r, hostname, ip) ? true : false);
     if (cont)
       cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, res ? (void *) ip : (void *) NULL);
     return ACTION_RESULT_DONE;
   }
   HostDBContinuation *c = hostDBContAllocator.alloc();
-  c->init(hostname, len, ip, md5, cont, pDS);
+  HostDBContinuation::Options copt;
+  copt.cont = cont;
+  c->init(md5, copt);
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::removeEvent);
   thread->schedule_in(c, MUTEX_RETRY_DELAY);
   return &c->action;
 }
-
+#endif
 
 int
 HostDBContinuation::removeEvent(int event, Event * e)
@@ -1140,12 +1220,12 @@ HostDBContinuation::removeEvent(int event, Event * e)
       if (cont)
         cont->handleEvent(EVENT_HOST_DB_IP_REMOVED, (void *) NULL);
     } else {
-      HostDBInfo *r = probe(mutex, md5, name, namelen, &ip.sa, m_pDS);
-      bool res = (remove_round_robin(r, name, &ip.sa) ? true : false);
+      HostDBInfo *r = probe(mutex, md5, false);
+      bool res = (remove_round_robin(r, md5.host_name, md5.ip) ? true : false);
       if (cont)
         cont->handleEvent(
           EVENT_HOST_DB_IP_REMOVED,
-          res ? static_cast<void *>(&ip) : static_cast<void *>(NULL)
+          res ? static_cast<void *>(&md5.ip) : static_cast<void *>(NULL)
         );
     }
   }
@@ -1158,23 +1238,24 @@ HostDBContinuation::removeEvent(int event, Event * e)
 // calling continuation or to the calling cluster node.
 //
 HostDBInfo *
-HostDBContinuation::lookup_done(sockaddr const* aip, char *aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv)
+HostDBContinuation::lookup_done(IpAddr const& ip, char const* aname, bool around_robin, unsigned int ttl_seconds, SRVHosts * srv)
 {
   HostDBInfo *i = NULL;
 
-  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5) % hostDB.buckets))->thread_holding);
-  if (!aip || !ats_is_ip(aip) || !aname || !aname[0]) {
+  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets))->thread_holding);
+  if (!ip.isValid() || !aname || !aname[0]) {
     if (is_byname()) {
-      Debug("hostdb", "lookup_done() failed for '%s'", name);
+      Debug("hostdb", "lookup_done() failed for '%.*s'", md5.host_len, md5.host_name);
     } else if (is_srv()) {
-      Debug("dns_srv", "SRV failed for '%s'", name);
+      Debug("dns_srv", "SRV failed for '%.*s'", md5.host_len, md5.host_name);
     } else {
       ip_text_buffer b;
-      Debug("hostdb", "failed for %s", ats_ip_ntop(&ip.sa, b, sizeof b));
+      Debug("hostdb", "failed for %s", md5.ip.toString(b, sizeof b));
     }
     i = insert(hostdb_ip_fail_timeout_interval);        // currently ... 0
     i->round_robin = false;
     i->reverse_dns = !is_byname() && !is_srv();
+    i->set_failed();
   } else {
     switch (hostdb_ttl_mode) {
     default:
@@ -1199,18 +1280,16 @@ HostDBContinuation::lookup_done(sockaddr const* aip, char *aname, bool around_ro
     i = insert(ttl_seconds);
     if (is_byname()) {
       ip_text_buffer b;
-      Debug("hostdb", "done %s TTL %d", ats_ip_ntop(aip, b, sizeof b), ttl_seconds);
-      ats_ip_copy(i->ip(), aip);
+      Debug("hostdb", "done %s TTL %d", ip.toString(b, sizeof b), ttl_seconds);
+      ats_ip_set(i->ip(), ip);
       i->round_robin = around_robin;
       i->reverse_dns = false;
-      if (name != aname) {
-        ink_strlcpy(name, aname, sizeof(name));
+      if (md5.host_name != aname) {
+        ink_strlcpy(md5_host_name_store, aname, sizeof(md5_host_name_store));
       }
       i->is_srv = false;
     } else if (is_srv()) {
-
-      ats_ip_copy(i->ip(), aip);  /* this doesnt matter w. srv records -- setting to 1 so Md5 works */
-
+      ats_ip_set(i->ip(), ip);
       i->reverse_dns = false;
 
       if (srv) {                //failed case: srv == NULL
@@ -1227,8 +1306,8 @@ HostDBContinuation::lookup_done(sockaddr const* aip, char *aname, bool around_ro
 
       i->is_srv = true;
 
-      if (name != aname) {
-        ink_strlcpy(name, aname, sizeof(name));
+      if (md5.host_name != aname) {
+        ink_strlcpy(md5_host_name_store, aname, sizeof(md5_host_name_store));
       }
 
     } else {
@@ -1260,7 +1339,7 @@ HostDBContinuation::lookup_done(sockaddr const* aip, char *aname, bool around_ro
 int
 HostDBContinuation::dnsPendingEvent(int event, Event * e)
 {
-  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
+  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5.hash) % hostDB.buckets)->thread_holding);
   if (timeout) {
     timeout->cancel(this);
     timeout = NULL;
@@ -1274,7 +1353,7 @@ HostDBContinuation::dnsPendingEvent(int event, Event * e)
     }
     if (!action.cancelled && action.continuation)
       action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
-    hostDB.pending_dns_for_hash(md5).remove(this);
+    hostDB.pending_dns_for_hash(md5.hash).remove(this);
     hostdb_cont_free(this);
     return EVENT_DONE;
   } else {
@@ -1306,7 +1385,7 @@ restore_info(HostDBInfo * r, HostDBInfo * old_r, HostDBInfo & old_info, HostDBRo
 int
 HostDBContinuation::dnsEvent(int event, HostEnt * e)
 {
-  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5) % hostDB.buckets)->thread_holding);
+  ink_debug_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5.hash) % hostDB.buckets)->thread_holding);
   if (timeout) {
     timeout->cancel(this);
     timeout = NULL;
@@ -1324,6 +1403,10 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
       timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
       return EVENT_CONT;
     }
+    // [amc] Callback to client to indicate a failure due to timeout.
+    // We don't try a different family here because a timeout indicates
+    // a server issue that won't be fixed by asking for a different
+    // address family.
     if (!action.cancelled && action.continuation)
       action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
     action = NULL;
@@ -1333,18 +1416,20 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
   } else {
     bool failed = !e;
 
-    bool rr;
+    bool rr = false;
+    pending_action = NULL;
+
     if (is_srv()) {
       rr = !failed && (e->srv_hosts.getCount() > 0);
-    } else
-      rr = !failed && e->ent.h_addr_list[1];
-
-    pending_action = NULL;
+    } else if (!failed) {
+      rr = 0 != e->ent.h_addr_list[1];
+    } else {
+    }
 
     ttl = failed ? 0 : e->ttl / 60;
-    int ttl_seconds = failed ? 0 : e->ttl;      //ebalsa: moving to second accuracy
+    int ttl_seconds = failed ? 0 : e->ttl; //ebalsa: moving to second accuracy
 
-    HostDBInfo *old_r = probe(mutex, md5, name, namelen, &ip.sa, m_pDS, true);
+    HostDBInfo *old_r = probe(mutex, md5, true);
     HostDBInfo old_info;
     if (old_r)
       old_info = *old_r;
@@ -1352,9 +1437,8 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
 
     int n = 0, nn = 0;
     void* first = 0;
-    uint8_t af = e ? e->ent.h_addrtype : AF_UNSPEC;
+    uint8_t af = e ? e->ent.h_addrtype : AF_UNSPEC; // address family
     if (rr) {
-      af = e->ent.h_addrtype;
       if (is_srv() && !failed) {
         n = e->srv_hosts.getCount();
       } else {
@@ -1368,7 +1452,7 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
             if (! first) first = ptr;
             ++n;
           } else {
-            Warning("Zero address removed from round-robin list for '%s'", name);
+            Warning("Zero address removed from round-robin list for '%s'", md5.host_name);
           }
           // what's the point of @a n? Should there be something like
           // if (n != nn) e->ent.h_addr_list[n] = e->ent->h_addr_list[nn];
@@ -1384,21 +1468,23 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
     } // else first is 0.
 
     HostDBInfo *r = NULL;
-    sockaddr_storage tip; // temporary IP data.
-    sockaddr* tip_ptr = ats_ip_sa_cast(&tip);
-    ats_ip_invalidate(tip_ptr);
-    if (first) ip_addr_set(tip_ptr, af, first);
-
-    if (is_byname())
-      r = lookup_done(tip_ptr, name, rr, ttl_seconds, failed ? 0 : &e->srv_hosts);
-    else if (is_srv())
-      r = lookup_done(tip_ptr,  /* junk: FIXME: is the code in lookup_done() wrong to NEED this? */
-                      name,     /* hostname */
+    IpAddr tip; // temp storage if needed.
+
+    if (is_byname()) {
+      if (first) ip_addr_set(tip, af, first);
+      r = lookup_done(tip, md5.host_name, rr, ttl_seconds, failed ? 0 : &e->srv_hosts);
+    } else if (is_srv()) {
+      if (first) ip_addr_set(tip, af, first);
+      r = lookup_done(tip,  /* junk: FIXME: is the code in lookup_done() wrong to NEED this? */
+                      md5.host_name,     /* hostname */
                       rr,       /* is round robin, doesnt matter for SRV since we recheck getCount() inside lookup_done() */
                       ttl_seconds,      /* ttl in seconds */
                       failed ? 0 : &e->srv_hosts);
-    else
-      r = lookup_done(tip_ptr, failed ? name : e->ent.h_name, false, ttl_seconds, failed ? 0 : &e->srv_hosts);
+    } else if (failed) {
+      r = lookup_done(tip, md5.host_name, false, ttl_seconds, 0);
+    } else {
+      r = lookup_done(md5.ip, e->ent.h_name, false, ttl_seconds, &e->srv_hosts);
+    }
 
     if (rr) {
       int s = HostDBRoundRobin::size(n, is_srv());
@@ -1469,11 +1555,18 @@ HostDBContinuation::dnsEvent(int event, HostEnt * e)
 #ifdef NON_MODULAR
     // if we are not the owner, put on the owner
     //
-    ClusterMachine *m = cluster_machine_at_depth(master_hash(md5));
+    ClusterMachine *m = cluster_machine_at_depth(master_hash(md5.hash));
     if (m)
       do_put_response(m, r, NULL);
 #endif
 
+    // Check for IP family failover
+    if (failed && check_for_retry(md5.db_mark, host_res_style)) {
+      this->refresh_MD5();
+      SET_CONTINUATION_HANDLER(this, (HostDBContHandler) & HostDBContinuation::probeEvent);
+      thread->schedule_in(this, MUTEX_RETRY_DELAY);
+      return EVENT_CONT;
+    }
     // try to callback the user
     //
     if (action.continuation) {
@@ -1521,15 +1614,15 @@ HostDBContinuation::make_get_message(char *buf, int size)
   ink_assert(size >= (int) sizeof(HostDB_get_message));
 
   HostDB_get_message *msg = reinterpret_cast<HostDB_get_message *>(buf);
-  msg->md5 = md5;
-  ats_ip_copy(&msg->ip.sa, &ip.sa);
+  msg->md5 = md5.hash;
+  ats_ip_set(&msg->ip.sa, md5.ip, htons(md5.port));
   msg->cont = this;
 
   // name
-  ink_strlcpy(msg->name, name, sizeof(msg->name));
+  ink_strlcpy(msg->name, md5.host_name, sizeof(msg->name));
 
   // length
-  int len = sizeof(HostDB_get_message) - MAXDNAME + strlen(name) + 1;
+  int len = sizeof(HostDB_get_message) - MAXDNAME + md5.host_len + 1;
 
   return len;
 }
@@ -1550,11 +1643,11 @@ bool HostDBContinuation::do_get_response(Event * e)
     m = NULL;
 
   if (hostdb_migrate_on_demand)
-    m = cluster_machine_at_depth(master_hash(md5), &probe_depth, past_probes);
+    m = cluster_machine_at_depth(master_hash(md5.hash), &probe_depth, past_probes);
   else {
     if (probe_depth)
       return false;
-    m = cluster_machine_at_depth(master_hash(md5));
+    m = cluster_machine_at_depth(master_hash(md5.hash));
     probe_depth = 1;
   }
 
@@ -1613,7 +1706,7 @@ HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf
   HostDB_put_message *msg = reinterpret_cast<HostDB_put_message *>(buf);
   memset(msg, 0, sizeof(HostDB_put_message));
 
-  msg->md5 = md5;
+  msg->md5 = md5.hash;
   msg->cont = c;
   if (r) {
     ats_ip_copy(&msg->ip.sa, r->ip());
@@ -1627,10 +1720,10 @@ HostDBContinuation::make_put_message(HostDBInfo * r, Continuation * c, char *buf
   }
 
   // name
-  ink_strlcpy(msg->name, name, sizeof(msg->name));
+  ink_strlcpy(msg->name, md5.host_name, sizeof(msg->name));
 
   // length
-  int len = sizeof(HostDB_put_message) - MAXDNAME + strlen(name) + 1;
+  int len = sizeof(HostDB_put_message) - MAXDNAME + md5.host_len + 1;
 
   return len;
 }
@@ -1677,7 +1770,7 @@ HostDBContinuation::probeEvent(int event, Event * e)
     return EVENT_DONE;
   }
 
-  if (!hostdb_enable || (!*name && !ats_is_ip(&ip.sa))) {
+  if (!hostdb_enable || (!*md5.host_name && !md5.ip.isValid())) {
     if (action.continuation)
       action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
 #ifdef NON_MODULAR
@@ -1692,7 +1785,7 @@ HostDBContinuation::probeEvent(int event, Event * e)
 
     // Do the probe
     //
-    HostDBInfo *r = probe(mutex, md5, name, namelen, &ip.sa, m_pDS);
+    HostDBInfo *r = probe(mutex, md5, false);
 
     if (r)
       HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
@@ -1730,10 +1823,10 @@ HostDBContinuation::probeEvent(int event, Event * e)
 int
 HostDBContinuation::set_check_pending_dns()
 {
-  Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5);
+  Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5.hash);
   HostDBContinuation *c = q.head;
   for (; c; c = (HostDBContinuation *) c->link.next) {
-    if (md5 == c->md5) {
+    if (md5.hash == c->md5.hash) {
       Debug("hostdb", "enqueuing additional request");
       q.enqueue(this);
       return false;
@@ -1747,13 +1840,13 @@ HostDBContinuation::set_check_pending_dns()
 void
 HostDBContinuation::remove_trigger_pending_dns()
 {
-  Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5);
+  Queue<HostDBContinuation> &q = hostDB.pending_dns_for_hash(md5.hash);
   q.remove(this);
   HostDBContinuation *c = q.head;
   Queue<HostDBContinuation> qq;
   while (c) {
     HostDBContinuation *n = (HostDBContinuation *) c->link.next;
-    if (md5 == c->md5) {
+    if (md5.hash == c->md5.hash) {
       Debug("hostdb", "dequeuing additional request");
       q.remove(c);
       qq.enqueue(c);
@@ -1773,12 +1866,12 @@ HostDBContinuation::do_dns()
 {
   ink_assert(!action.cancelled);
   if (is_byname()) {
-    Debug("hostdb", "DNS %s", name);
-    IpEndpoint tip;
-    if (0 == ats_ip_pton(name, &tip.sa)) {
+    Debug("hostdb", "DNS %s", md5.host_name);
+    IpAddr tip;
+    if (0 == tip.load(md5.host_name)) {
       // check 127.0.0.1 format // What the heck does that mean? - AMC
       if (action.continuation) {
-        HostDBInfo *r = lookup_done(&tip.sa, name, false, HOST_DB_MAX_TTL, NULL);
+        HostDBInfo *r = lookup_done(tip, md5.host_name, false, HOST_DB_MAX_TTL, NULL);
         reply_to_cont(action.continuation, r);
       }
       hostdb_cont_free(this);
@@ -1790,22 +1883,21 @@ HostDBContinuation::do_dns()
   else
     timeout = NULL;
   if (set_check_pending_dns()) {
+    DNSProcessor::Options opt;
+    opt.timeout = dns_lookup_timeout;
+    opt.host_res_style = host_res_style_for(md5.db_mark);
     SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent);
     if (is_byname()) {
-      DNSHandler *dnsH = 0;
-#ifdef SPLIT_DNS
-      if (m_pDS)
-        dnsH = static_cast<DNSServer *>(m_pDS)->x_dnsH;
-#endif
-      pending_action = dnsProcessor.gethostbyname(this, name, dnsH, dns_lookup_timeout);
+      if (md5.dns_server)
+        opt.handler = md5.dns_server->x_dnsH;
+      pending_action = dnsProcessor.gethostbyname(this, md5.host_name, opt);
     } else if (is_srv()) {
-      DNSHandler *dnsH = 0;
-      Debug("dns_srv", "SRV lookup of %s", name);
-      pending_action = dnsProcessor.getSRVbyname(this, name, dnsH, dns_lookup_timeout);
+      Debug("dns_srv", "SRV lookup of %s", md5.host_name);
+      pending_action = dnsProcessor.getSRVbyname(this, md5.host_name, opt);
     } else {
       ip_text_buffer ipb;
-      Debug("hostdb", "DNS IP %s", ats_ip_ntop(&ip.sa, ipb, sizeof ipb));
-      pending_action = dnsProcessor.gethostbyaddr(this, &ip.sa, dns_lookup_timeout);
+      Debug("hostdb", "DNS IP %s", md5.ip.toString(ipb, sizeof ipb));
+      pending_action = dnsProcessor.gethostbyaddr(this, &md5.ip, opt);
     }
   } else {
     SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent);
@@ -1846,7 +1938,7 @@ HostDBContinuation::clusterResponseEvent(int event, Event * e)
     action = 0;
     // just a remote fill
     ink_assert(!missing);
-    lookup_done(&ip.sa, name, false, ttl, NULL);
+    lookup_done(md5.ip, md5.host_name, false, ttl, NULL);
   }
   hostdb_cont_free(this);
   return EVENT_DONE;
@@ -1878,7 +1970,7 @@ HostDBContinuation::clusterEvent(int event, Event * e)
     }
     if (e) {
       HostDBContinuation *c = (HostDBContinuation *) e;
-      HostDBInfo *r = lookup_done(&c->ip.sa, c->name, false, c->ttl, NULL);
+      HostDBInfo *r = lookup_done(md5.ip, c->md5.host_name, false, c->ttl, NULL);
       r->app.allotment.application1 = c->app.allotment.application1;
       r->app.allotment.application2 = c->app.allotment.application2;
 
@@ -1890,7 +1982,7 @@ HostDBContinuation::clusterEvent(int event, Event * e)
           // fill the owner
           //
           if (hostdb_migrate_on_demand) {
-            ClusterMachine *m = cluster_machine_at_depth(master_hash(md5));
+            ClusterMachine *m = cluster_machine_at_depth(master_hash(md5.hash));
             if (m && m != c->from)
               do_put_response(m, r, NULL);
           }
@@ -1938,9 +2030,15 @@ void
 get_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int len)
 {
   NOWARN_UNUSED(len);
-  void *pDS = 0;
+  HostDBMD5 md5;
   HostDB_get_message *msg = (HostDB_get_message *) data;
 
+  md5.host_name = msg->name;
+  md5.host_len = msg->namelen;
+  md5.ip.assign(&msg->ip.sa);
+  md5.port = ats_ip_port_host_order(&msg->ip.sa);
+  md5.hash = msg->md5;
+  md5.db_mark = db_mark_for(&msg->ip.sa);
 #ifdef SPLIT_DNS
   SplitDNS *pSD = 0;
   char *hostname = msg->name;
@@ -1948,13 +2046,14 @@ get_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int len)
     pSD = SplitDNSConfig::acquire();
 
     if (0 != pSD) {
-      pDS = pSD->getDNSRecord(hostname);
+      md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(hostname));
     }
     SplitDNSConfig::release(pSD);
   }
 #endif // SPLIT_DNS
 
   HostDBContinuation *c = hostDBContAllocator.alloc();
+  HostDBContinuation::Options copt;
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
   c->from = ch->machine;
   c->from_cont = msg->cont;
@@ -1966,8 +2065,8 @@ get_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int len)
      DNS servers
      ----------------------------------------- */
 
-
-  c->init(msg->name, msg->namelen, &msg->ip.sa, msg->md5, NULL, pDS);
+  copt.host_res_style = host_res_style_for(&msg->ip.sa);
+  c->init(md5, copt);
   c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
   c->action.mutex = c->mutex;
   dnsProcessor.thread->schedule_imm(c);
@@ -1980,9 +2079,18 @@ put_hostinfo_ClusterFunction(ClusterHandler *ch, void *data, int len)
   NOWARN_UNUSED(len);
   HostDB_put_message *msg = (HostDB_put_message *) data;
   HostDBContinuation *c = hostDBContAllocator.alloc();
+  HostDBContinuation::Options copt;
+  HostDBMD5 md5;
 
   SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::clusterResponseEvent);
-  c->init(msg->name, msg->namelen, &msg->ip.sa, msg->md5, NULL);
+  md5.host_name = msg->name;
+  md5.host_len = msg->namelen;
+  md5.ip.assign(&msg->ip.sa);
+  md5.port = ats_ip_port_host_order(&msg->ip.sa);
+  md5.hash = msg->md5;
+  md5.db_mark = db_mark_for(&msg->ip.sa);
+  copt.host_res_style = host_res_style_for(&msg->ip.sa);
+  c->init(md5, copt);
   c->mutex = hostDB.lock_for_bucket(fold_md5(msg->md5) % hostDB.buckets);
   c->from_cont = msg->cont;     // cannot use action if cont freed due to timeout
   c->missing = msg->missing;
@@ -2096,11 +2204,10 @@ HostDBInfo::heap_offset_ptr()
 ClusterMachine *
 HostDBContinuation::master_machine(ClusterConfiguration * cc)
 {
-  return cc->machine_hash((int) (md5[1] >> 32));
+  return cc->machine_hash((int) (md5.hash[1] >> 32));
 }
 #endif // NON_MODULAR
 
-
 #ifdef NON_MODULAR
 struct ShowHostDB;
 typedef int (ShowHostDB::*ShowHostDBEventHandler) (int event, Event * data);
@@ -2134,7 +2241,7 @@ struct ShowHostDB: public ShowCont
     NOWARN_UNUSED(e);
     SET_HANDLER(&ShowHostDB::showLookupDone);
     if (name)
-      hostDBProcessor.getbyname_re(this, name, 0, force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0);
+      hostDBProcessor.getbyname_re(this, name, 0, HostDBProcessor::Options().setFlags(force ? HostDBProcessor::HOSTDB_FORCE_DNS_ALWAYS : 0));
     else
       hostDBProcessor.getbyaddr_re(this, &ip.sa);
     return EVENT_CONT;
@@ -2363,4 +2470,6 @@ ink_hostdb_init(ModuleVersion v)
 
   RecRegisterRawStat(hostdb_rsb, RECT_PROCESS,
                      "proxy.process.hostdb.bytes", RECD_INT, RECP_NULL, (int) hostdb_bytes_stat, RecRawStatSyncCount);
+
+  ts_host_res_global_init();
 }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/hostdb/I_HostDBProcessor.h
----------------------------------------------------------------------
diff --git a/iocore/hostdb/I_HostDBProcessor.h b/iocore/hostdb/I_HostDBProcessor.h
index 5f65a55..cf8aa19 100644
--- a/iocore/hostdb/I_HostDBProcessor.h
+++ b/iocore/hostdb/I_HostDBProcessor.h
@@ -371,22 +371,18 @@ struct HostDBRoundRobin
     }
   }
 
+  /** Find the index of @a addr in member @a info.
+      @return The index if found, -1 if not found.
+  */
+  int index_of(sockaddr const* addr);
   HostDBInfo *find_ip(sockaddr const* addr);
-  HostDBInfo *select_best(sockaddr const* client_ip, HostDBInfo * r = NULL);
+  /** Select the next entry after @a addr.
+      @note If @a addr isn't an address in the round robin nothing is updated.
+      @return The selected entry or @c NULL if @a addr wasn't present.
+   */
+  HostDBInfo* select_next(sockaddr const* addr);
   HostDBInfo *select_best_http(sockaddr const* client_ip, ink_time_t now, int32_t fail_window);
 
-  HostDBInfo *increment_round_robin()
-  {
-    bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
-
-    if (bad) {
-      ink_assert(!"bad round robin size");
-      return NULL;
-    }
-    current++;
-    return NULL;
-  }
-
   HostDBRoundRobin()
     : n(0), good(0), current(0), timed_rr_ctime(0)
   { }
@@ -404,6 +400,7 @@ typedef void (Continuation::*process_srv_info_pfn) (HostDBInfo * r);
 /** The Host Databse access interface. */
 struct HostDBProcessor: public Processor
 {
+  friend struct HostDBSyncer;
   // Public Interface
 
   // Lookup Hostinfo by name
@@ -422,33 +419,47 @@ struct HostDBProcessor: public Processor
     HOSTDB_DO_NOT_ROUND_ROBIN = 4
   };
 
+  /// Optional parameters for getby...
+  struct Options {
+    typedef Options self; ///< Self reference type.
+    int port; ///< Target service port (default 0 -> don't care)
+    int flags; ///< Processing flags (default HOSTDB_DO_NOT_FORCE_DNS)
+    int timeout; ///< Timeout value (default 0 -> default timeout)
+    HostResStyle host_res_style; ///< How to query host (default HOST_RES_IPV4)
+
+    Options() : port(0), flags(HOSTDB_DO_NOT_FORCE_DNS), timeout(0), host_res_style(HOST_RES_IPV4)
+    { }
+
+    /// Set the flags.
+    self& setFlags(int f) { flags = f; return *this; }
+  };
+
+  /// Default options.
+  static Options const DEFAULT_OPTIONS;
+
   HostDBProcessor()
   { }
 
-  inkcoreapi Action *getbyname_re(Continuation * cont, const char *hostname, int len = 0, int port = 0,
-                                  int flags = HOSTDB_DO_NOT_FORCE_DNS);
+  inkcoreapi Action *getbyname_re(Continuation * cont, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
 
-  Action *getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, const char *hostname, int len = 0,
-                           int port = 0, int flags = HOSTDB_DO_NOT_FORCE_DNS, int timeout = 0);
+  Action *getSRVbyname_imm(Continuation * cont, process_srv_info_pfn process_srv_info, const char *hostname, int len, Options const& opt = DEFAULT_OPTIONS);
 
   Action *getbyname_imm(
     Continuation * cont,
     process_hostdb_info_pfn process_hostdb_info,
     const char *hostname,
-    int len = 0,
-    int port = 0,
-    int flags = HOSTDB_DO_NOT_FORCE_DNS,
-    int timeout = 0
+    int len,
+    Options const& opt = DEFAULT_OPTIONS
   );
 
 
   /** Lookup Hostinfo by addr */
   Action *getbyaddr_re(Continuation * cont, sockaddr const* aip)
   {
-    return getby(cont, NULL, 0, aip, false);
+    return getby(cont, NULL, 0, aip, false, HOST_RES_NONE, 0);
   }
 
-
+#if 0
   /**
     If you were unable to connect to an IP address associated with a
     particular hostname, call this function and that IP address will
@@ -461,6 +472,7 @@ struct HostDBProcessor: public Processor
     sockaddr const* aip,
     const char *hostname, int len = 0
   );
+#endif
 
   /** Set the application information (fire-and-forget). */
   void setbyname_appinfo(char *hostname, int len, int port, HostDBApplicationInfo * app)
@@ -493,12 +505,14 @@ struct HostDBProcessor: public Processor
 
   // Private
   HostDBCache *cache();
+private:
   Action *getby(
     Continuation * cont,
     const char *hostname, int len,
     sockaddr const* ip,
-    bool aforce_dns, int timeout = 0
+    bool aforce_dns, HostResStyle host_res_style, int timeout
   );
+public:
   /** Set something.
       @a aip can carry address and / or port information. If setting just
       by a port value, the address should be set to INADDR_ANY which is of

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/hostdb/P_HostDB.h
----------------------------------------------------------------------
diff --git a/iocore/hostdb/P_HostDB.h b/iocore/hostdb/P_HostDB.h
index d543495..548226b 100644
--- a/iocore/hostdb/P_HostDB.h
+++ b/iocore/hostdb/P_HostDB.h
@@ -58,9 +58,7 @@
                                     HOSTDB_MODULE_MAJOR_VERSION, \
                                     HOSTDB_MODULE_MINOR_VERSION, \
                                     PRIVATE_MODULE_HEADER)
-HostDBInfo *probe(ProxyMutex * mutex,
-                  INK_MD5 & md5, const char *hostname, int len,
-                  sockaddr const* addr, void *pDS, bool ignore_timeout = false, bool is_srv_lookup = false);
+HostDBInfo *probe(ProxyMutex * mutex, HostDBMD5 const& md5, bool ignore_timeout);
 
-void make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char *pDNSServers = 0, int srv = 0);
+void make_md5(INK_MD5 & md5, const char *hostname, int len, int port, char const*pDNSServers, HostDBMark mark);
 #endif

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/hostdb/P_HostDBProcessor.h
----------------------------------------------------------------------
diff --git a/iocore/hostdb/P_HostDBProcessor.h b/iocore/hostdb/P_HostDBProcessor.h
index b7961ea..06a3d44 100644
--- a/iocore/hostdb/P_HostDBProcessor.h
+++ b/iocore/hostdb/P_HostDBProcessor.h
@@ -30,6 +30,23 @@
 
 #include "I_HostDBProcessor.h"
 
+/** Host DB record mark.
+
+    The records in the host DB are de facto segregated by roughly the
+    DNS query type. We use an intermediate type to provide a little flexibility
+    although the type is presumed to be a single byte.
+ */
+enum HostDBMark {
+  HOSTDB_MARK_GENERIC, ///< Anything that's not one of the other types.
+  HOSTDB_MARK_IPV4, ///< IPv4 / T_A
+  HOSTDB_MARK_IPV6, ///< IPv6 / T_AAAA
+  HOSTDB_MARK_SRV, ///< Service / T_SRV
+};
+/** Convert a HostDB @a mark to a string.
+    @return A static string.
+ */
+extern char const* string_for(HostDBMark mark);
+
 inline unsigned int HOSTDB_CLIENT_IP_HASH(
   sockaddr const* lhs,
   sockaddr const* rhs
@@ -62,8 +79,8 @@ inline unsigned int HOSTDB_CLIENT_IP_HASH(
 
 // Bump this any time hostdb format is changed
 #define HOST_DB_CACHE_MAJOR_VERSION         2
-#define HOST_DB_CACHE_MINOR_VERSION         1
-// 2.1 : IPv6
+#define HOST_DB_CACHE_MINOR_VERSION         2
+// 2.2: IP family split 2.1 : IPv6
 
 #define DEFAULT_HOST_DB_FILENAME             "host.db"
 #define DEFAULT_HOST_DB_SIZE                 (1<<14)
@@ -165,48 +182,40 @@ struct HostDBCache: public MultiCache<HostDBInfo>
   HostDBCache();
 };
 
-inline HostDBInfo*
-HostDBRoundRobin::find_ip(sockaddr const* ip) {
+inline int
+HostDBRoundRobin::index_of(sockaddr const* ip) {
   bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
   if (bad) {
     ink_assert(!"bad round robin size");
-    return NULL;
+    return -1;
   }
 
   for (int i = 0; i < good; i++) {
     if (ats_ip_addr_eq(ip, info[i].ip())) {
-      return &info[i];
+      return i;
     }
   }
 
-  return NULL;
+  return -1;
 }
 
-inline HostDBInfo *
-HostDBRoundRobin::select_best(sockaddr const* client_ip, HostDBInfo * r)
-{
-  (void) r;
-  bool bad = (n <= 0 || n > HOST_DB_MAX_ROUND_ROBIN_INFO || good <= 0 || good > HOST_DB_MAX_ROUND_ROBIN_INFO);
-  if (bad) {
-    ink_assert(!"bad round robin size");
-    return NULL;
-  }
-  int best = 0;
-  if (HostDBProcessor::hostdb_strict_round_robin) {
-    best = current++ % good;
-  } else {
-    sockaddr const* ip = info[0].ip();
-    unsigned int best_hash = HOSTDB_CLIENT_IP_HASH(client_ip, ip);
-    for (int i = 1; i < good; i++) {
-      ip = info[i].ip();
-      unsigned int h = HOSTDB_CLIENT_IP_HASH(client_ip, ip);
-      if (best_hash < h) {
-        best = i;
-        best_hash = h;
-      }
+inline HostDBInfo*
+HostDBRoundRobin::find_ip(sockaddr const* ip) {
+  int idx = this->index_of(ip);
+  return idx < 0 ? NULL : &info[idx];
+}
+
+inline HostDBInfo*
+HostDBRoundRobin::select_next(sockaddr const* ip) {
+  HostDBInfo* zret = 0;
+  if (good > 1) {
+    int idx = this->index_of(ip);
+    if (idx >= 0) {
+      idx = (idx+1)%good;
+      zret = &info[idx];
     }
   }
-  return &info[best];
+  return zret;
 }
 
 inline HostDBInfo *
@@ -290,6 +299,30 @@ HostDBRoundRobin::select_best_http(sockaddr const* client_ip, ink_time_t now, in
 // Types
 //
 
+/** Container for an MD5 hash and its dependent data.
+    This handles both the host name and raw address cases.
+*/
+struct HostDBMD5 {
+  typedef HostDBMD5 self; ///< Self reference type.
+
+  INK_MD5 hash; ///< The hash value.
+
+  char const* host_name; ///< Host name.
+  int host_len; ///< Length of @a _host_name
+  IpAddr ip; ///< IP address.
+  int port; ///< IP port (host order).
+  /// DNS server. Not strictly part of the MD5 data but
+  /// it's both used by @c HostDBContinuation and provides access to
+  /// MD5 data. It's just handier to store it here for both uses.
+  DNSServer* dns_server;
+  HostDBMark db_mark; ///< Mark / type of record.
+
+  /// Default constructor.
+  HostDBMD5();
+  /// Recompute and update the MD5 hash.
+  void refresh();
+};
+
 //
 // Handles a HostDB lookup request
 //
@@ -299,19 +332,25 @@ typedef int (HostDBContinuation::*HostDBContHandler) (int, void *);
 struct HostDBContinuation: public Continuation
 {
   Action action;
-  IpEndpoint ip;
+  HostDBMD5 md5;
+  //  IpEndpoint ip;
   unsigned int ttl;
-  bool is_srv_lookup;
+  //  HostDBMark db_mark; ///< Target type.
+  /// Original IP address family style. Note this will disagree with
+  /// @a md5.db_mark when doing a retry on an alternate family. The retry
+  /// logic depends on it to avoid looping.
+  HostResStyle host_res_style; ///< Address family priority.
   int dns_lookup_timeout;
-  INK_MD5 md5;
+  //  INK_MD5 md5;
   Event *timeout;
   ClusterMachine *from;
   Continuation *from_cont;
   HostDBApplicationInfo app;
   int probe_depth;
   ClusterMachine *past_probes[CONFIGURATION_HISTORY_PROBE_DEPTH];
-  int namelen;
-  char name[MAXDNAME];
+  //  char name[MAXDNAME];
+  //  int namelen;
+  char md5_host_name_store[MAXDNAME+1]; // used as backing store for @a md5
   void *m_pDS;
   Action *pending_action;
 
@@ -329,16 +368,18 @@ struct HostDBContinuation: public Continuation
   int removeEvent(int event, Event * e);
   int setbyEvent(int event, Event * e);
 
+  /// Recompute the MD5 and update ancillary values.
+  void refresh_MD5();
   void do_dns();
   bool is_byname()
   {
-    return ((*name && !is_srv_lookup) ? true : false);
+    return *md5.host_name && md5.db_mark != HOSTDB_MARK_SRV;
   }
   bool is_srv()
   {
-    return ((*name && is_srv_lookup) ? true : false);
+    return *md5.host_name && md5.db_mark == HOSTDB_MARK_SRV;
   }
-  HostDBInfo *lookup_done(sockaddr const* aip, char *aname, bool round_robin, unsigned int attl, SRVHosts * s = NULL);
+  HostDBInfo *lookup_done(IpAddr const& ip, char const* aname, bool round_robin, unsigned int attl, SRVHosts * s = NULL);
   bool do_get_response(Event * e);
   void do_put_response(ClusterMachine * m, HostDBInfo * r, Continuation * cont);
   int failed_cluster_request(Event * e);
@@ -350,20 +391,35 @@ struct HostDBContinuation: public Continuation
 
   HostDBInfo *insert(unsigned int attl);
 
-  void init(const char *hostname, int len, sockaddr const* ip, INK_MD5 & amd5,
-            Continuation * cont, void *pDS = 0, bool is_srv = false, int timeout = 0);
+  /** Optional values for @c init.
+   */
+  struct Options {
+    typedef Options self; ///< Self reference type.
+
+    int timeout; ///< Timeout value. Default 0
+    HostResStyle host_res_style; ///< IP address family fallback. Default @c HOST_RES_NONE
+    bool force_dns; ///< Force DNS lookup. Default @c false
+    Continuation* cont; ///< Continuation / action. Default @c NULL (none)
+
+    Options()
+      : timeout(0), host_res_style(HOST_RES_NONE), force_dns(false), cont(0)
+    { }
+  };
+  static const Options DEFAULT_OPTIONS; ///< Default defaults.
+  void init(HostDBMD5 const& md5,
+            Options const& opt = DEFAULT_OPTIONS);
   int make_get_message(char *buf, int len);
   int make_put_message(HostDBInfo * r, Continuation * c, char *buf, int len);
 
 HostDBContinuation():
   Continuation(NULL), ttl(0),
-    is_srv_lookup(false), dns_lookup_timeout(0),
+    host_res_style(DEFAULT_OPTIONS.host_res_style),
+    dns_lookup_timeout(DEFAULT_OPTIONS.timeout),
     timeout(0), from(0),
-    from_cont(0), probe_depth(0), namelen(0), missing(false), force_dns(false), round_robin(false) {
-    memset(&ip, 0, sizeof ip);
-    memset(name, 0, MAXDNAME);
-    md5.b[0] = 0;
-    md5.b[1] = 0;
+    from_cont(0), probe_depth(0), missing(false),
+    force_dns(DEFAULT_OPTIONS.force_dns), round_robin(false) {
+    ink_zero(md5_host_name_store);
+    ink_zero(md5.hash);
     SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
   }
 };
@@ -402,9 +458,9 @@ extern HostDBCache hostDB;
 //extern Queue<HostDBContinuation>  remoteHostDBQueue[MULTI_CACHE_PARTITIONS];
 
 inline unsigned int
-master_hash(INK_MD5 & md5)
+master_hash(INK_MD5 const& md5)
 {
-  return (int) (md5[1] >> 32);
+  return static_cast<int>(md5[1] >> 32);
 }
 
 inline bool
@@ -422,7 +478,7 @@ HostDBCache::pending_dns_for_hash(INK_MD5 & md5)
 inline int
 HostDBContinuation::key_partition()
 {
-  return hostDB.partition_of_bucket(fold_md5(md5) % hostDB.buckets);
+  return hostDB.partition_of_bucket(fold_md5(md5.hash) % hostDB.buckets);
 }
 
 #endif /* _P_HostDBProcessor_h_ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/043815e7/iocore/hostdb/P_MultiCache.h
----------------------------------------------------------------------
diff --git a/iocore/hostdb/P_MultiCache.h b/iocore/hostdb/P_MultiCache.h
index b37ac83..f2ab823 100644
--- a/iocore/hostdb/P_MultiCache.h
+++ b/iocore/hostdb/P_MultiCache.h
@@ -447,9 +447,9 @@ template<class C> struct MultiCache: public MultiCacheBase
 };
 
 inline uint64_t
-fold_md5(INK_MD5 & md5)
+fold_md5(INK_MD5 const& md5)
 {
-  return (md5.fold());
+  return md5.fold();
 }
 
 template<class C> inline int MultiCache<C>::level_of_block(C * b)


Re: [1/2] git commit: TS-1422 TS-1307 : Update HostDB for better IPv6 handling.

Posted by Igor Galić <i....@brainsware.org>.
Failing Regressions arfter this update.

FATAL: /home/igalic/src/asf/trafficserver/iocore/dns/DNS.cc:400: failed assert `!"T_PTR query to DNS must be IP address."`
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server - STACK TRACE: 
/tmp/org.apache.trafficserver.14892/dst/lib/libtsutil.so.3(ink_fatal+0xa3)[0x7f81f0c08f48]
/tmp/org.apache.trafficserver.14892/dst/lib/libtsutil.so.3(ink_get_rand()+0x0)[0x7f81f0c07c4c]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(DNSEntry::init(char const*, int, int, Continuation*, DNSProcessor::Options const&)+0x2a1)[0x7f81f12d5f7d]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(DNSProcessor::getby(char const*, int, int, Continuation*, DNSProcessor::Options const&)+0x161)[0x7f81f12d97c7]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(DNSProcessor::gethostbyaddr(Continuation*, IpAddr const*, DNSProcessor::Options const&)+0x40)[0x7f81f12cb78c]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(HostDBContinuation::do_dns()+0x483)[0x7f81f12c9bb9]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(HostDBContinuation::probeEvent(int, Event*)+0x308)[0x7f81f12c9484]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(Continuation::handleEvent(int, void*)+0x72)[0x7f81f116a0c8]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(EThread::process_event(Event*, int)+0x12c)[0x7f81f138c9a4]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(EThread::execute()+0x27c)[0x7f81f138cdc0]
/tmp/org.apache.trafficserver.14892/dst/bin/traffic_server(+0x32fb69)[0x7f81f138bb69]
/lib/x86_64-linux-gnu/libpthread.so.0(+0x7e9a)[0x7f81f09d6e9a]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x6d)[0x7f81ee8e1cbd]
[1]    18400 abort (core dumped)  /tmp/org.apache.trafficserver.14892/dst/bin/traffic_server -R 1


-- i