1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-04 09:43:08 +02:00

Retry socket bind.

In the case of a rapid restart it is possible that the socket may not be immediately available, so retry until it becomes available.

This is particularly useful for testing where sockets are bound and released very rapidly.
This commit is contained in:
David Steele 2024-10-12 10:06:40 +03:00
parent ed72c6f9a1
commit 65dfe2407d
2 changed files with 43 additions and 3 deletions

View File

@ -186,9 +186,17 @@ sckServerNew(const String *const address, const unsigned int port, const TimeMSe
strCat(this->name, addrInfoToName(this->address, this->port, addressFound));
// Bind the address
THROW_ON_SYS_ERROR(
bind(this->socket, addressFound->ai_addr, addressFound->ai_addrlen) == -1, FileOpenError,
"unable to bind socket");
Wait *const wait = waitNew(timeout);
int result;
do
{
result = bind(this->socket, addressFound->ai_addr, addressFound->ai_addrlen);
if (result == -1 && !waitMore(wait))
THROW_SYS_ERROR(FileOpenError, "unable to bind socket");
}
while (result == -1);
// Listen for client connections. It might be a good idea to make the backlog configurable but this value seems OK for now.
THROW_ON_SYS_ERROR(listen(this->socket, 100) == -1, FileOpenError, "unable to listen on socket");

View File

@ -565,6 +565,38 @@ testRun(void)
HRN_FORK_PARENT_END();
}
HRN_FORK_END();
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("sckServerNew() retries bind()");
HRN_FORK_BEGIN(.timeout = 5000)
{
const unsigned int testPort = hrnServerPortNext();
HRN_FORK_CHILD_BEGIN(.prefix = "server")
{
// Bind port and notify parent
IoServer *server = sckServerNew(STRDEF("127.0.0.1"), testPort, 5000);
HRN_FORK_CHILD_NOTIFY_PUT();
// Sleep 1000ms then close port
sleepMSec(1000);
objFree(server);
}
HRN_FORK_CHILD_END();
HRN_FORK_PARENT_BEGIN(.prefix = "client")
{
// Wait for parent to bind port before attempting to bind
HRN_FORK_PARENT_NOTIFY_GET(0);
TEST_ERROR(
sckServerNew(STRDEF("127.0.0.1"), testPort, 100), FileOpenError,
"unable to bind socket: [98] Address already in use");
TEST_RESULT_VOID(sckServerNew(STRDEF("127.0.0.1"), testPort, 5000), "bind succeeds with enough retries");
}
HRN_FORK_PARENT_END();
}
HRN_FORK_END();
}
// Additional coverage not provided by testing with actual certificates