From 7ba371e30e4b2c13734a2dfeee3cf06d41ab1c1d Mon Sep 17 00:00:00 2001
From: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Date: Fri, 9 Jan 2026 19:31:57 +0900
Subject: [PATCH v4 2/2] Handle corner cases related with origin

The attribute acquired_by can still be 0 while processes are acquiring the origin.
This can happen if the first process exits while holding the origin. This commit
handles corner cases related to it:

 - rejects acquiring origin if it does not have a valid acquired_by
   but counter > 0.
 - ensures origins cannot be dropped if the counter > 0.
---
 src/backend/replication/logical/origin.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index 389d2b38d20..b9132b3475d 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -386,16 +386,19 @@ restart:
 		if (state->roident == roident)
 		{
 			/* found our slot, is it busy? */
-			if (state->acquired_by != 0)
+			if (state->refcount > 0)
 			{
 				ConditionVariable *cv;
 
 				if (nowait)
 					ereport(ERROR,
 							(errcode(ERRCODE_OBJECT_IN_USE),
-							 errmsg("could not drop replication origin with ID %d, in use by PID %d",
-									state->roident,
-									state->acquired_by)));
+							 (state->acquired_by != 0)
+							 ? errmsg("could not drop replication origin with ID %d, in use by PID %d",
+									  state->roident,
+									  state->acquired_by)
+							 : errmsg("could not drop replication origin with ID %d, in use by another process",
+									  state->roident)));
 
 				/*
 				 * We must wait and then retry.  Since we don't know which CV
@@ -1192,6 +1195,18 @@ replorigin_session_setup(RepOriginId node, int acquired_by)
 							node, acquired_by)));
 		}
 
+		/*
+		 * PID was not noted in the origin. This can happen the process
+		 * originally acquired the origin exits without releasing. To make the
+		 * staus clean again, other processes cannot acquire the origin till
+		 * all using ones release.
+		 */
+		else if (curstate->acquired_by == 0 && curstate->refcount > 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_OBJECT_IN_USE),
+					 errmsg("replication origin with ID %d is already active in another process",
+							curstate->roident)));
+
 		/* ok, found slot */
 		session_replication_state = curstate;
 		break;
-- 
2.47.3

