From 7606bd26f14a4b9755577bc7dad8ea57c36e7ba1 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Tue, 22 Sep 2026 09:33:34 +0000
Subject: [PATCH] [#1029] Send a directory server only the updates it gives send-window credit for (#1034)

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/DataServerHandler.java |   20 ++++++++++++++++++++
 1 files changed, 20 insertions(+), 0 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/DataServerHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/DataServerHandler.java
index c13aea8..4e4bac6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/DataServerHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/DataServerHandler.java
@@ -49,6 +49,7 @@
 import org.opends.server.replication.protocol.StartSessionMsg;
 import org.opends.server.replication.protocol.StopMsg;
 import org.opends.server.replication.protocol.TopologyMsg;
+import org.opends.server.replication.protocol.UpdateMsg;
 import org.opends.server.types.DirectoryException;
 
 /**
@@ -303,6 +304,25 @@
   }
 
   /**
+   * A directory server is sent only the updates which contribute to the domain state: those are
+   * the ones it replays, and the only ones it gives credit for on the send window of the session
+   * - see the listener of ReplicationDomain, which calls processUpdateDone() for nothing else.
+   * ServerHandler.take() takes a permit of that window for every message it hands to the writer,
+   * so any other message sent to a directory server would cost the session a permit for good.
+   * <p>
+   * Today that is the ReplicaOfflineMsg, which is exchanged between replication servers only.
+   * ReplicationServerDomain.put() never queues one for a directory server, but the catch-up path
+   * reads the changelog, where the cursor of a replica which went offline synthesizes one from
+   * its offline CSN, and since the state of this handler never moves past that CSN every
+   * catch-up round would read the same message again, one permit each (issue #1029).
+   */
+  @Override
+  boolean updateServerState(UpdateMsg msg)
+  {
+    return msg.contributesToDomainState() && super.updateServerState(msg);
+  }
+
+  /**
    * Process message of a remote server changing his status.
    * @param csMsg The message containing the new status
    * @return The new server status of the DS

--
Gitblit v1.10.0