Use async name resolving to improve net thread responsiveness

In the LookupIntern(), things changed are:

  1. Call getaddrinfo_a() instead of getaddrinfo() if available, the former is a sync version of the latter;
  2. Try using inet_pton()/inet_addr() to convert the input text to a network addr structure at first, if success the extra name resolving thread inside getaddrinfo_a() could be avoided;
  3.  An interruption point added in the waiting loop for return from getaddrinfo_a(), which completes the improve for thread responsiveness.

A easy way to see the effect is to kick off a 'bitcoind stop' immediately after 'bitcoind -daemon', before the change it would take several, or even tens of, minutes on a bad network situation to wait for the running bitcoind to exit, now it costs only seconds.

Signed-off-by: Huang Le <4tarhl@gmail.com>
This commit is contained in:
Huang Le 2014-06-27 02:55:39 +08:00
parent 236ae8665e
commit caf6150e97
2 changed files with 61 additions and 1 deletions

View File

@ -369,6 +369,8 @@ if test x$TARGET_OS = xdarwin; then
fi fi
AC_CHECK_HEADERS([endian.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h]) AC_CHECK_HEADERS([endian.h stdio.h stdlib.h unistd.h strings.h sys/types.h sys/stat.h sys/select.h])
AC_SEARCH_LIBS([getaddrinfo_a], [anl], [AC_DEFINE(HAVE_GETADDRINFO_A, 1, [Define this symbol if you have getaddrinfo_a])])
AC_SEARCH_LIBS([inet_pton], [nsl resolv], [AC_DEFINE(HAVE_INET_PTON, 1, [Define this symbol if you have inet_pton])])
AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,, AC_CHECK_DECLS([le32toh, le64toh, htole32, htole64, be32toh, be64toh, htobe32, htobe64],,,
[#if HAVE_ENDIAN_H [#if HAVE_ENDIAN_H

View File

@ -3,6 +3,18 @@
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifdef HAVE_CONFIG_H
#include "bitcoin-config.h"
#endif
#ifdef HAVE_INET_PTON
#include <arpa/inet.h>
#endif
#ifdef HAVE_GETADDRINFO_A
#include <netdb.h>
#endif
#include "netbase.h" #include "netbase.h"
#include "hash.h" #include "hash.h"
@ -71,9 +83,30 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
} }
} }
#ifdef HAVE_GETADDRINFO_A
struct in_addr ipv4_addr;
#ifdef HAVE_INET_PTON
if (inet_pton(AF_INET, pszName, &ipv4_addr) > 0) {
vIP.push_back(CNetAddr(ipv4_addr));
return true;
}
struct in6_addr ipv6_addr;
if (inet_pton(AF_INET6, pszName, &ipv6_addr) > 0) {
vIP.push_back(CNetAddr(ipv6_addr));
return true;
}
#else
ipv4_addr.s_addr = inet_addr(pszName);
if (ipv4_addr.s_addr != INADDR_NONE) {
vIP.push_back(CNetAddr(ipv4_addr));
return true;
}
#endif
#endif
struct addrinfo aiHint; struct addrinfo aiHint;
memset(&aiHint, 0, sizeof(struct addrinfo)); memset(&aiHint, 0, sizeof(struct addrinfo));
aiHint.ai_socktype = SOCK_STREAM; aiHint.ai_socktype = SOCK_STREAM;
aiHint.ai_protocol = IPPROTO_TCP; aiHint.ai_protocol = IPPROTO_TCP;
aiHint.ai_family = AF_UNSPEC; aiHint.ai_family = AF_UNSPEC;
@ -82,8 +115,33 @@ bool static LookupIntern(const char *pszName, std::vector<CNetAddr>& vIP, unsign
#else #else
aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST; aiHint.ai_flags = fAllowLookup ? AI_ADDRCONFIG : AI_NUMERICHOST;
#endif #endif
struct addrinfo *aiRes = NULL; struct addrinfo *aiRes = NULL;
#ifdef HAVE_GETADDRINFO_A
struct gaicb gcb, *query = &gcb;
memset(query, 0, sizeof(struct gaicb));
gcb.ar_name = pszName;
gcb.ar_request = &aiHint;
int nErr = getaddrinfo_a(GAI_NOWAIT, &query, 1, NULL);
if (nErr)
return false;
do {
// Should set the timeout limit to a resonable value to avoid
// generating unnecessary checking call during the polling loop,
// while it can still response to stop request quick enough.
// 2 seconds looks fine in our situation.
struct timespec ts = { 2, 0 };
gai_suspend(&query, 1, &ts);
boost::this_thread::interruption_point();
nErr = gai_error(query);
if (0 == nErr)
aiRes = query->ar_result;
} while (nErr == EAI_INPROGRESS);
#else
int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes); int nErr = getaddrinfo(pszName, NULL, &aiHint, &aiRes);
#endif
if (nErr) if (nErr)
return false; return false;