From 77ad03e14cc1bbc5471f332ba73430d4c472b366 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Tue, 20 Oct 2026 06:45:44 +0000
Subject: [PATCH] [#1202] [#1209] [#1222] Give the replication server a bounded time to give credit and to read once the broker is being stopped, and write nothing after a message given up (#1210)

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/service/HeartbeatMonitor.java |   24 +++++++++++++++++++++++-
 1 files changed, 23 insertions(+), 1 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/HeartbeatMonitor.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/HeartbeatMonitor.java
index f889968..affe18c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/HeartbeatMonitor.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/HeartbeatMonitor.java
@@ -13,11 +13,15 @@
  *
  * Copyright 2007-2009 Sun Microsystems, Inc.
  * Portions Copyright 2011-2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 
 package org.opends.server.replication.service;
 
 import static org.opends.messages.ReplicationMessages.*;
+
+import java.io.IOException;
+
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.opends.server.replication.protocol.Session;
 
@@ -107,6 +111,7 @@
                 heartbeatInterval);
     }
 
+    boolean heartbeatsStopped = false;
     try
     {
       boolean gotOneFailure = false;
@@ -124,6 +129,7 @@
 
             // Exit monitor and close session.
             shutdown = true;
+            heartbeatsStopped = true;
             break;
           }
           else
@@ -161,7 +167,23 @@
       {
         logger.trace("Heartbeat monitor is exiting");
       }
-      session.close();
+      if (heartbeatsStopped)
+      {
+        /*
+         * A replication server which is gone without a reset acknowledges nothing, and the writes to
+         * it fill the socket buffers: a write then blocks in the socket, holding the lock a close of
+         * a session with no error waits for, until TCP gives up retransmitting. Nothing else ends
+         * that write, nor the read of the listener, which neither data nor a reset ends: the
+         * session is closed as a failed one, with no StopMsg the replication server would not read.
+         */
+        session.abort(new IOException("No heartbeat came from replication server RS("
+            + replicationServerID + ") at " + session.getReadableRemoteAddress() + " for twice "
+            + heartbeatInterval + " ms"));
+      }
+      else
+      {
+        session.close();
+      }
     }
   }
 }

--
Gitblit v1.10.0