Handle invalid connection hash entries (#4362)

If MemoryContextAlloc errors out -e.g. during an OOM-, ConnectionHashEntry->connections
stays as NULL.

With this commit, we add isValid flag to ConnectionHashEntry that should be set to true
right after we allocate & initialize ConnectionHashEntry->connections list properly, and we
check it before accesing to ConnectionHashEntry->connections.
(cherry picked from commit 7f3d1182ed)

 Conflicts:
	src/backend/distributed/connection/connection_management.c
pull/4418/head
Onur Tirtir 2020-11-30 19:44:03 +03:00
parent 221aa1a381
commit 59774b1dd4
2 changed files with 47 additions and 1 deletions

View File

@ -160,6 +160,12 @@ AfterXactConnectionHandling(bool isCommit)
hash_seq_init(&status, ConnectionHash); hash_seq_init(&status, ConnectionHash);
while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0) while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0)
{ {
if (!entry->isValid)
{
/* skip invalid connection hash entries */
continue;
}
AfterXactHostConnectionHandling(entry, isCommit); AfterXactHostConnectionHandling(entry, isCommit);
/* /*
@ -323,11 +329,24 @@ StartNodeUserDatabaseConnection(uint32 flags, const char *hostname, int32 port,
*/ */
ConnectionHashEntry *entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found); ConnectionHashEntry *entry = hash_search(ConnectionHash, &key, HASH_ENTER, &found);
if (!found) if (!found || !entry->isValid)
{ {
/*
* We are just building hash entry or previously it was left in an
* invalid state as we couldn't allocate memory for it.
* So initialize entry->connections list here.
*/
entry->isValid = false;
entry->connections = MemoryContextAlloc(ConnectionContext, entry->connections = MemoryContextAlloc(ConnectionContext,
sizeof(dlist_head)); sizeof(dlist_head));
dlist_init(entry->connections); dlist_init(entry->connections);
/*
* If MemoryContextAlloc errors out -e.g. during an OOM-, entry->connections
* stays as NULL. So entry->isValid should be set to true right after we
* initialize entry->connections properly.
*/
entry->isValid = true;
} }
/* if desired, check whether there's a usable connection */ /* if desired, check whether there's a usable connection */
@ -474,6 +493,12 @@ CloseAllConnectionsAfterTransaction(void)
hash_seq_init(&status, ConnectionHash); hash_seq_init(&status, ConnectionHash);
while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0) while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0)
{ {
if (!entry->isValid)
{
/* skip invalid connection hash entries */
continue;
}
dlist_iter iter; dlist_iter iter;
dlist_head *connections = entry->connections; dlist_head *connections = entry->connections;
@ -502,6 +527,12 @@ CloseNodeConnectionsAfterTransaction(char *nodeName, int nodePort)
hash_seq_init(&status, ConnectionHash); hash_seq_init(&status, ConnectionHash);
while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0) while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != 0)
{ {
if (!entry->isValid)
{
/* skip invalid connection hash entries */
continue;
}
dlist_iter iter; dlist_iter iter;
if (strcmp(entry->key.hostname, nodeName) != 0 || entry->key.port != nodePort) if (strcmp(entry->key.hostname, nodeName) != 0 || entry->key.port != nodePort)
@ -577,6 +608,12 @@ ShutdownAllConnections(void)
hash_seq_init(&status, ConnectionHash); hash_seq_init(&status, ConnectionHash);
while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != NULL) while ((entry = (ConnectionHashEntry *) hash_seq_search(&status)) != NULL)
{ {
if (!entry->isValid)
{
/* skip invalid connection hash entries */
continue;
}
dlist_iter iter; dlist_iter iter;
dlist_foreach(iter, entry->connections) dlist_foreach(iter, entry->connections)
@ -1187,6 +1224,12 @@ FreeConnParamsHashEntryFields(ConnParamsHashEntry *entry)
static void static void
AfterXactHostConnectionHandling(ConnectionHashEntry *entry, bool isCommit) AfterXactHostConnectionHandling(ConnectionHashEntry *entry, bool isCommit)
{ {
if (!entry || !entry->isValid)
{
/* callers only pass valid hash entries but let's be on the safe side */
ereport(ERROR, (errmsg("connection hash entry is NULL or invalid")));
}
dlist_mutable_iter iter; dlist_mutable_iter iter;
int cachedConnectionCount = 0; int cachedConnectionCount = 0;

View File

@ -173,6 +173,9 @@ typedef struct ConnectionHashEntry
{ {
ConnectionHashKey key; ConnectionHashKey key;
dlist_head *connections; dlist_head *connections;
/* connections list is valid or not */
bool isValid;
} ConnectionHashEntry; } ConnectionHashEntry;
/* hash entry for cached connection parameters */ /* hash entry for cached connection parameters */