aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2015-10-16 09:42:33 -0400
committerRobert Haas <rhaas@postgresql.org>2015-10-16 09:49:08 -0400
commit26981d292758c6ee9185332e4abc990ff19c81a2 (patch)
treea3c650b277ace15358b25c15da181e465f242b6d
parenta93b3782e3358cbb1ad8d65386a2e1478b805649 (diff)
downloadpostgresql-26981d292758c6ee9185332e4abc990ff19c81a2.tar.gz
postgresql-26981d292758c6ee9185332e4abc990ff19c81a2.zip
Don't send protocol messages to a shm_mq that no longer exists.
Commit 2bd9e412f92bc6a68f3e8bcb18e04955cc35001d introduced a mechanism for relaying protocol messages from a background worker to another backend via a shm_mq. However, there was no provision for shutting down the communication channel. Therefore, a protocol message sent late in the shutdown sequence, such as a DEBUG message resulting from cranking up log_min_messages, could crash the server. To fix, install an on_dsm_detach callback that disables sending messages to the shm_mq when the associated DSM is detached.
-rw-r--r--src/backend/access/transam/parallel.c2
-rw-r--r--src/backend/libpq/pqmq.c28
-rw-r--r--src/backend/storage/ipc/shm_mq.c9
-rw-r--r--src/include/libpq/pqmq.h2
-rw-r--r--src/include/storage/shm_mq.h3
5 files changed, 40 insertions, 4 deletions
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 29d6ed57cc2..0b94c0f87e9 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -867,7 +867,7 @@ ParallelWorkerMain(Datum main_arg)
ParallelWorkerNumber * PARALLEL_ERROR_QUEUE_SIZE);
shm_mq_set_sender(mq, MyProc);
mqh = shm_mq_attach(mq, seg, NULL);
- pq_redirect_to_shm_mq(mq, mqh);
+ pq_redirect_to_shm_mq(seg, mqh);
pq_set_parallel_master(fps->parallel_master_pid,
fps->parallel_master_backend_id);
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 9ca6b7ce0d1..0a3c2b70cbe 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -26,6 +26,7 @@ static bool pq_mq_busy = false;
static pid_t pq_mq_parallel_master_pid = 0;
static pid_t pq_mq_parallel_master_backend_id = InvalidBackendId;
+static void pq_cleanup_redirect_to_shm_mq(dsm_segment *seg, Datum arg);
static void mq_comm_reset(void);
static int mq_flush(void);
static int mq_flush_if_writable(void);
@@ -51,13 +52,26 @@ static PQcommMethods PqCommMqMethods = {
* message queue.
*/
void
-pq_redirect_to_shm_mq(shm_mq *mq, shm_mq_handle *mqh)
+pq_redirect_to_shm_mq(dsm_segment *seg, shm_mq_handle *mqh)
{
PqCommMethods = &PqCommMqMethods;
- pq_mq = mq;
+ pq_mq = shm_mq_get_queue(mqh);
pq_mq_handle = mqh;
whereToSendOutput = DestRemote;
FrontendProtocol = PG_PROTOCOL_LATEST;
+ on_dsm_detach(seg, pq_cleanup_redirect_to_shm_mq, (Datum) 0);
+}
+
+/*
+ * When the DSM that contains our shm_mq goes away, we need to stop sending
+ * messages to it.
+ */
+static void
+pq_cleanup_redirect_to_shm_mq(dsm_segment *seg, Datum arg)
+{
+ pq_mq = NULL;
+ pq_mq_handle = NULL;
+ whereToSendOutput = DestNone;
}
/*
@@ -123,9 +137,19 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (pq_mq != NULL)
shm_mq_detach(pq_mq);
pq_mq = NULL;
+ pq_mq_handle = NULL;
return EOF;
}
+ /*
+ * If the message queue is already gone, just ignore the message. This
+ * doesn't necessarily indicate a problem; for example, DEBUG messages
+ * can be generated late in the shutdown sequence, after all DSMs have
+ * already been detached.
+ */
+ if (pq_mq == NULL)
+ return 0;
+
pq_mq_busy = true;
iov[0].data = &msgtype;
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 0e60dbcddc8..c78f1650e6a 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -746,6 +746,15 @@ shm_mq_detach(shm_mq *mq)
}
/*
+ * Get the shm_mq from handle.
+ */
+shm_mq *
+shm_mq_get_queue(shm_mq_handle *mqh)
+{
+ return mqh->mqh_queue;
+}
+
+/*
* Write bytes into a shared message queue.
*/
static shm_mq_result
diff --git a/src/include/libpq/pqmq.h b/src/include/libpq/pqmq.h
index 901756596a4..97f17da89db 100644
--- a/src/include/libpq/pqmq.h
+++ b/src/include/libpq/pqmq.h
@@ -16,7 +16,7 @@
#include "lib/stringinfo.h"
#include "storage/shm_mq.h"
-extern void pq_redirect_to_shm_mq(shm_mq *, shm_mq_handle *);
+extern void pq_redirect_to_shm_mq(dsm_segment *seg, shm_mq_handle *mqh);
extern void pq_set_parallel_master(pid_t pid, BackendId backend_id);
extern void pq_parse_errornotice(StringInfo str, ErrorData *edata);
diff --git a/src/include/storage/shm_mq.h b/src/include/storage/shm_mq.h
index 1a2ba040cb4..7621a358ab4 100644
--- a/src/include/storage/shm_mq.h
+++ b/src/include/storage/shm_mq.h
@@ -65,6 +65,9 @@ extern void shm_mq_set_handle(shm_mq_handle *, BackgroundWorkerHandle *);
/* Break connection. */
extern void shm_mq_detach(shm_mq *);
+/* Get the shm_mq from handle. */
+extern shm_mq *shm_mq_get_queue(shm_mq_handle *mqh);
+
/* Send or receive messages. */
extern shm_mq_result shm_mq_send(shm_mq_handle *mqh,
Size nbytes, const void *data, bool nowait);