At Thu, 2 Feb 2017 08:46:11 +0900, Michael Paquier <michael.paqu...@gmail.com> 
wrote in <cab7npqr6vq7aikck1ao3_mpvvn4v4zknjfq2oawfqpaephd...@mail.gmail.com>
> On Thu, Feb 2, 2017 at 2:14 AM, Fujii Masao <masao.fu...@gmail.com> wrote:
> > The lwlock would be released when an exception occurs, so I don't think
> > that TRY-CATCH is necessary here. Or it's necessary for another reason?
> 
> +    PG_CATCH();
> +    {
> +        LWLockRelease(LogicalRepLauncherLock);
> +        PG_RE_THROW();
> +    }
> +    PG_END_TRY();
> Just to do that, a TRY/CATCH block looks like an overkill to me. Why
> not just call LWLockRelease in the ERROR and return code paths?

I though the same first. The modification at the "if (wrconn =="
is the remains of that. It is reverted inthe attached patch.

Then, the reason for the TRY-CATCH cluase is that I found that
some functions called from there can throw exceptions.

logicalrep_worker_stop and replorigin_drop have ereport in its path.
load_library apparently can throw exception.
(walrcv_(libpq_) functions don't seeem to.)

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
>From d0ca653bb2aa776742a2e7a697b02794b1ad66d9 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Thu, 2 Feb 2017 11:33:40 +0900
Subject: [PATCH] Fix DROP SUBSCRIPTION's lock leak.

DROP SUBSCRIPTION acquires a lock on LogicalRepLauncherLock but never
releases. This fixes it.
---
 src/backend/commands/subscriptioncmds.c | 86 ++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 38 deletions(-)

diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 5de9999..223eea4 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -511,52 +511,62 @@ DropSubscription(DropSubscriptionStmt *stmt)
 	/* Protect against launcher restarting the worker. */
 	LWLockAcquire(LogicalRepLauncherLock, LW_EXCLUSIVE);
 
-	/* Kill the apply worker so that the slot becomes accessible. */
-	logicalrep_worker_stop(subid);
-
-	/* Remove the origin tracking if exists. */
-	snprintf(originname, sizeof(originname), "pg_%u", subid);
-	originid = replorigin_by_name(originname, true);
-	if (originid != InvalidRepOriginId)
-		replorigin_drop(originid);
-
-	/* If the user asked to not drop the slot, we are done mow.*/
-	if (!stmt->drop_slot)
-	{
-		heap_close(rel, NoLock);
-		return;
-	}
-
 	/*
-	 * Otherwise drop the replication slot at the publisher node using
-	 * the replication connection.
+	 * Some functions called here can throw exceptions. we must release
+	 * LogicalRepLauncherLock for the case.
 	 */
-	load_file("libpqwalreceiver", false);
+	PG_TRY();
+	{
+		/* Kill the apply worker so that the slot becomes accessible. */
+		logicalrep_worker_stop(subid);
 
-	initStringInfo(&cmd);
-	appendStringInfo(&cmd, "DROP_REPLICATION_SLOT \"%s\"", slotname);
+		/* Remove the origin tracking if exists. */
+		snprintf(originname, sizeof(originname), "pg_%u", subid);
+		originid = replorigin_by_name(originname, true);
+		if (originid != InvalidRepOriginId)
+			replorigin_drop(originid);
 
-	wrconn = walrcv_connect(conninfo, true, subname, &err);
-	if (wrconn == NULL)
-		ereport(ERROR,
-				(errmsg("could not connect to publisher when attempting to "
-						"drop the replication slot \"%s\"", slotname),
-				 errdetail("The error was: %s", err)));
+		/* Do the follwoing only if the user asked to actually drop the slot */
+		if (stmt->drop_slot)
+		{
+			/*
+			 * Drop the replication slot at the publisher node using the
+			 * replication connection.
+			 */
+			load_file("libpqwalreceiver", false);
 
-	if (!walrcv_command(wrconn, cmd.data, &err))
-		ereport(ERROR,
-				(errmsg("could not drop the replication slot \"%s\" on publisher",
-						slotname),
-				 errdetail("The error was: %s", err)));
-	else
-		ereport(NOTICE,
-				(errmsg("dropped replication slot \"%s\" on publisher",
-						slotname)));
+			initStringInfo(&cmd);
+			appendStringInfo(&cmd, "DROP_REPLICATION_SLOT \"%s\"", slotname);
+
+			wrconn = walrcv_connect(conninfo, true, subname, &err);
+			if (wrconn == NULL)
+				ereport(ERROR,
+						(errmsg("could not connect to publisher when attempting to "
+								"drop the replication slot \"%s\"", slotname),
+						 errdetail("The error was: %s", err)));
 
-	walrcv_disconnect(wrconn);
+			else if (!walrcv_command(wrconn, cmd.data, &err))
+				ereport(ERROR,
+						(errmsg("could not drop the replication slot \"%s\" on publisher",
+								slotname),
+						 errdetail("The error was: %s", err)));
+
+			ereport(NOTICE,
+					(errmsg("dropped replication slot \"%s\" on publisher",
+							slotname)));
 
-	pfree(cmd.data);
+			walrcv_disconnect(wrconn);
+			pfree(cmd.data);
+		}
+	}
+	PG_CATCH();
+	{
+		LWLockRelease(LogicalRepLauncherLock);
+		PG_RE_THROW();
+	}
+	PG_END_TRY();
 
+	LWLockRelease(LogicalRepLauncherLock);
 	heap_close(rel, NoLock);
 }
 
-- 
2.9.2

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to