1
0
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:
David Steele
2023-09-12 18:09:58 -04:00
committed by GitHub
parent 9d3a605900
commit 39bb8a0d3a
4 changed files with 58 additions and 15 deletions

View File

@@ -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();
}