aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/postgres_fdw/expected/postgres_fdw.out7
-rw-r--r--contrib/postgres_fdw/sql/postgres_fdw.sql6
-rw-r--r--src/backend/executor/nodeAppend.c5
-rw-r--r--src/backend/libpq/pqcomm.c2
-rw-r--r--src/backend/postmaster/postmaster.c2
-rw-r--r--src/backend/postmaster/syslogger.c2
-rw-r--r--src/backend/storage/ipc/latch.c68
-rw-r--r--src/include/storage/latch.h4
-rw-r--r--src/include/utils/resowner.h1
9 files changed, 84 insertions, 13 deletions
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 64bcc66b8dd..22cae37a1eb 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -10809,6 +10809,13 @@ SELECT * FROM result_tbl ORDER BY a;
(2 rows)
DELETE FROM result_tbl;
+-- Test error handling, if accessing one of the foreign partitions errors out
+CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
+ SERVER loopback OPTIONS (table_name 'non_existent_table');
+SELECT * FROM async_pt;
+ERROR: relation "public.non_existent_table" does not exist
+CONTEXT: remote SQL command: SELECT a, b, c FROM public.non_existent_table
+DROP FOREIGN TABLE async_p_broken;
-- Check case where multiple partitions use the same connection
CREATE TABLE base_tbl3 (a int, b int, c text);
CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 2d14eeadb57..075da4ff867 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -3607,6 +3607,12 @@ INSERT INTO result_tbl SELECT a, b, 'AAA' || c FROM async_pt WHERE b === 505;
SELECT * FROM result_tbl ORDER BY a;
DELETE FROM result_tbl;
+-- Test error handling, if accessing one of the foreign partitions errors out
+CREATE FOREIGN TABLE async_p_broken PARTITION OF async_pt FOR VALUES FROM (10000) TO (10001)
+ SERVER loopback OPTIONS (table_name 'non_existent_table');
+SELECT * FROM async_pt;
+DROP FOREIGN TABLE async_p_broken;
+
-- Check case where multiple partitions use the same connection
CREATE TABLE base_tbl3 (a int, b int, c text);
CREATE FOREIGN TABLE async_p3 PARTITION OF async_pt FOR VALUES FROM (3000) TO (4000)
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 609df6b9e62..af8e37205f2 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -1025,7 +1025,8 @@ ExecAppendAsyncEventWait(AppendState *node)
/* We should never be called when there are no valid async subplans. */
Assert(node->as_nasyncremain > 0);
- node->as_eventset = CreateWaitEventSet(CurrentMemoryContext, nevents);
+ Assert(node->as_eventset == NULL);
+ node->as_eventset = CreateWaitEventSet(CurrentResourceOwner, nevents);
AddWaitEventToSet(node->as_eventset, WL_EXIT_ON_PM_DEATH, PGINVALID_SOCKET,
NULL, NULL);
@@ -1050,7 +1051,7 @@ ExecAppendAsyncEventWait(AppendState *node)
return;
}
- /* We wait on at most EVENT_BUFFER_SIZE events. */
+ /* Return at most EVENT_BUFFER_SIZE events in one call. */
if (nevents > EVENT_BUFFER_SIZE)
nevents = EVENT_BUFFER_SIZE;
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 522584e5978..2802efc63fc 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -207,7 +207,7 @@ pq_init(void)
elog(FATAL, "fcntl(F_SETFD) failed on socket: %m");
#endif
- FeBeWaitSet = CreateWaitEventSet(TopMemoryContext, FeBeWaitSetNEvents);
+ FeBeWaitSet = CreateWaitEventSet(NULL, FeBeWaitSetNEvents);
socket_pos = AddWaitEventToSet(FeBeWaitSet, WL_SOCKET_WRITEABLE,
MyProcPort->sock, NULL, NULL);
latch_pos = AddWaitEventToSet(FeBeWaitSet, WL_LATCH_SET, PGINVALID_SOCKET,
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7b6b613c4a3..7a5cd06c5c9 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1695,7 +1695,7 @@ ConfigurePostmasterWaitSet(bool accept_connections)
FreeWaitEventSet(pm_wait_set);
pm_wait_set = NULL;
- pm_wait_set = CreateWaitEventSet(CurrentMemoryContext,
+ pm_wait_set = CreateWaitEventSet(NULL,
accept_connections ? (1 + NumListenSockets) : 1);
AddWaitEventToSet(pm_wait_set, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch,
NULL);
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 858a2f6b2b9..96dd03d9e06 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -311,7 +311,7 @@ SysLoggerMain(int argc, char *argv[])
* syslog pipe, which implies that all other backends have exited
* (including the postmaster).
*/
- wes = CreateWaitEventSet(CurrentMemoryContext, 2);
+ wes = CreateWaitEventSet(NULL, 2);
AddWaitEventToSet(wes, WL_LATCH_SET, PGINVALID_SOCKET, MyLatch, NULL);
#ifndef WIN32
AddWaitEventToSet(wes, WL_SOCKET_READABLE, syslogPipe[0], NULL, NULL);
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 2fd386a4edb..d8a69990b3a 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -62,6 +62,7 @@
#include "storage/pmsignal.h"
#include "storage/shmem.h"
#include "utils/memutils.h"
+#include "utils/resowner.h"
/*
* Select the fd readiness primitive to use. Normally the "most modern"
@@ -101,6 +102,8 @@
/* typedef in latch.h */
struct WaitEventSet
{
+ ResourceOwner owner;
+
int nevents; /* number of registered events */
int nevents_space; /* maximum number of events in this set */
@@ -195,6 +198,31 @@ static void WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event);
static inline int WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
WaitEvent *occurred_events, int nevents);
+/* ResourceOwner support to hold WaitEventSets */
+static void ResOwnerReleaseWaitEventSet(Datum res);
+
+static const ResourceOwnerDesc wait_event_set_resowner_desc =
+{
+ .name = "WaitEventSet",
+ .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
+ .release_priority = RELEASE_PRIO_WAITEVENTSETS,
+ .ReleaseResource = ResOwnerReleaseWaitEventSet,
+ .DebugPrint = NULL
+};
+
+/* Convenience wrappers over ResourceOwnerRemember/Forget */
+static inline void
+ResourceOwnerRememberWaitEventSet(ResourceOwner owner, WaitEventSet *set)
+{
+ ResourceOwnerRemember(owner, PointerGetDatum(set), &wait_event_set_resowner_desc);
+}
+static inline void
+ResourceOwnerForgetWaitEventSet(ResourceOwner owner, WaitEventSet *set)
+{
+ ResourceOwnerForget(owner, PointerGetDatum(set), &wait_event_set_resowner_desc);
+}
+
+
/*
* Initialize the process-local latch infrastructure.
*
@@ -323,7 +351,7 @@ InitializeLatchWaitSet(void)
Assert(LatchWaitSet == NULL);
/* Set up the WaitEventSet used by WaitLatch(). */
- LatchWaitSet = CreateWaitEventSet(TopMemoryContext, 2);
+ LatchWaitSet = CreateWaitEventSet(NULL, 2);
latch_pos = AddWaitEventToSet(LatchWaitSet, WL_LATCH_SET, PGINVALID_SOCKET,
MyLatch, NULL);
if (IsUnderPostmaster)
@@ -541,7 +569,7 @@ WaitLatchOrSocket(Latch *latch, int wakeEvents, pgsocket sock,
int ret = 0;
int rc;
WaitEvent event;
- WaitEventSet *set = CreateWaitEventSet(CurrentMemoryContext, 3);
+ WaitEventSet *set = CreateWaitEventSet(CurrentResourceOwner, 3);
if (wakeEvents & WL_TIMEOUT)
Assert(timeout >= 0);
@@ -716,9 +744,12 @@ ResetLatch(Latch *latch)
*
* These events can then be efficiently waited upon together, using
* WaitEventSetWait().
+ *
+ * The WaitEventSet is tracked by the given 'resowner'. Use NULL for session
+ * lifetime.
*/
WaitEventSet *
-CreateWaitEventSet(MemoryContext context, int nevents)
+CreateWaitEventSet(ResourceOwner resowner, int nevents)
{
WaitEventSet *set;
char *data;
@@ -744,7 +775,10 @@ CreateWaitEventSet(MemoryContext context, int nevents)
sz += MAXALIGN(sizeof(HANDLE) * (nevents + 1));
#endif
- data = (char *) MemoryContextAllocZero(context, sz);
+ if (resowner != NULL)
+ ResourceOwnerEnlarge(resowner);
+
+ data = (char *) MemoryContextAllocZero(TopMemoryContext, sz);
set = (WaitEventSet *) data;
data += MAXALIGN(sizeof(WaitEventSet));
@@ -770,6 +804,12 @@ CreateWaitEventSet(MemoryContext context, int nevents)
set->nevents_space = nevents;
set->exit_on_postmaster_death = false;
+ if (resowner != NULL)
+ {
+ ResourceOwnerRememberWaitEventSet(resowner, set);
+ set->owner = resowner;
+ }
+
#if defined(WAIT_USE_EPOLL)
if (!AcquireExternalFD())
{
@@ -834,6 +874,12 @@ CreateWaitEventSet(MemoryContext context, int nevents)
void
FreeWaitEventSet(WaitEventSet *set)
{
+ if (set->owner)
+ {
+ ResourceOwnerForgetWaitEventSet(set->owner, set);
+ set->owner = NULL;
+ }
+
#if defined(WAIT_USE_EPOLL)
close(set->epoll_fd);
ReleaseExternalFD();
@@ -841,9 +887,7 @@ FreeWaitEventSet(WaitEventSet *set)
close(set->kqueue_fd);
ReleaseExternalFD();
#elif defined(WAIT_USE_WIN32)
- WaitEvent *cur_event;
-
- for (cur_event = set->events;
+ for (WaitEvent *cur_event = set->events;
cur_event < (set->events + set->nevents);
cur_event++)
{
@@ -2300,3 +2344,13 @@ drain(void)
}
#endif
+
+static void
+ResOwnerReleaseWaitEventSet(Datum res)
+{
+ WaitEventSet *set = (WaitEventSet *) DatumGetPointer(res);
+
+ Assert(set->owner != NULL);
+ set->owner = NULL;
+ FreeWaitEventSet(set);
+}
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index 99cc47874ac..9efc33add8f 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -102,6 +102,8 @@
#include <signal.h>
+#include "utils/resowner.h"
+
/*
* Latch structure should be treated as opaque and only accessed through
* the public functions. It is defined here to allow embedding Latches as
@@ -173,7 +175,7 @@ extern void SetLatch(Latch *latch);
extern void ResetLatch(Latch *latch);
extern void ShutdownLatchSupport(void);
-extern WaitEventSet *CreateWaitEventSet(MemoryContext context, int nevents);
+extern WaitEventSet *CreateWaitEventSet(ResourceOwner resowner, int nevents);
extern void FreeWaitEventSet(WaitEventSet *set);
extern void FreeWaitEventSetAfterFork(WaitEventSet *set);
extern int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd,
diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h
index 0735480214e..ddbf19d8da0 100644
--- a/src/include/utils/resowner.h
+++ b/src/include/utils/resowner.h
@@ -74,6 +74,7 @@ typedef uint32 ResourceReleasePriority;
#define RELEASE_PRIO_TUPDESC_REFS 400
#define RELEASE_PRIO_SNAPSHOT_REFS 500
#define RELEASE_PRIO_FILES 600
+#define RELEASE_PRIO_WAITEVENTSETS 700
/* 0 is considered invalid */
#define RELEASE_PRIO_FIRST 1