You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-11-06 08:49:29 +02:00
Support for dual stack connections.
The prior code would only connect to the first address provided by getaddrinfo(). Instead try each address in the list. If all connections fail then wait and try them all again until timeout. Currently a round robin approach is used where each connection attempt must fail before the next connection is attempted. This works fine, for example, when an ipv6 address has no route to the host, but will work less well when a host answers but doesn't respond in a timely fashion. We may consider a Happy Eyeballs approach in the future, but since pgBackRest is primarily a background process, it is not clear that slightly improved response time (in the case of failed connections) is worth the extra complexity.
This commit is contained in:
@@ -9,6 +9,7 @@ Socket Client
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/error/retry.h"
|
||||
#include "common/io/client.h"
|
||||
#include "common/io/socket/address.h"
|
||||
#include "common/io/socket/client.h"
|
||||
@@ -72,8 +73,13 @@ sckClientOpen(THIS_VOID)
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
Wait *const wait = waitNew(this->timeoutConnect);
|
||||
ErrorRetry *const errRetry = errRetryNew();
|
||||
bool retry;
|
||||
Wait *wait = waitNew(this->timeoutConnect);
|
||||
|
||||
// Get an address list for the host
|
||||
const AddressInfo *const addrInfo = addrInfoNew(this->host, this->port);
|
||||
unsigned int addrInfoIdx = 0;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -83,8 +89,8 @@ sckClientOpen(THIS_VOID)
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Get an address for the host. We are only going to try the first address returned.
|
||||
const struct addrinfo *const addressFound = addrInfoGet(addrInfoNew(this->host, this->port), 0);
|
||||
// Get next address for the host
|
||||
const struct addrinfo *const addressFound = addrInfoGet(addrInfo, addrInfoIdx);
|
||||
|
||||
// Connect to the host
|
||||
fd = socket(addressFound->ai_family, addressFound->ai_socktype, addressFound->ai_protocol);
|
||||
@@ -106,19 +112,32 @@ sckClientOpen(THIS_VOID)
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
// Close socket
|
||||
close(fd);
|
||||
|
||||
// Retry if wait time has not expired
|
||||
if (waitMore(wait))
|
||||
// Add the error retry info
|
||||
errRetryAdd(errRetry);
|
||||
|
||||
// Increment address info index and reset if the end has been reached. When the end has been reached sleep for a bit
|
||||
// to hopefully have better chance at succeeding, otherwise continue right to the next address as long as there is
|
||||
// some time left.
|
||||
addrInfoIdx++;
|
||||
|
||||
if (addrInfoIdx >= addrInfoSize(addrInfo))
|
||||
{
|
||||
LOG_DEBUG_FMT("retry %s: %s", errorTypeName(errorType()), errorMessage());
|
||||
retry = true;
|
||||
|
||||
statInc(SOCKET_STAT_RETRY_STR);
|
||||
addrInfoIdx = 0;
|
||||
retry = waitMore(wait);
|
||||
}
|
||||
else
|
||||
RETHROW();
|
||||
retry = waitRemaining(wait) > 0;
|
||||
|
||||
// Error when no retries remain
|
||||
if (!retry)
|
||||
THROWP(errRetryType(errRetry), strZ(errRetryMessage(errRetry)));
|
||||
|
||||
// Log retry
|
||||
LOG_DEBUG_FMT("retry %s: %s", errorTypeName(errorType()), errorMessage());
|
||||
statInc(SOCKET_STAT_RETRY_STR);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user