From 9e8bd8d694d82ec117c2c4a89c5d1aab2e52af94 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Fri, 25 Sep 2026 14:30:27 +0000
Subject: [PATCH] [#1080] Give back the send-window permit of an update the writer drops, and count only what it sends (#1106)

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerHandler.java |   47 ++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerHandler.java
index 6943c03..6694a9f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerHandler.java
@@ -980,6 +980,13 @@
   /**
    * Select the next update that must be sent to the server managed by this
    * ServerHandler.
+   * <p>
+   * The update comes with a permit of the send window of the session, taken
+   * before the writer decides whether it is sent at all. The peer gives the
+   * permit back for an update it receives, so the writer gives it back itself
+   * for one it drops - see {@link #releasePermitInSendWindow()} - and counts
+   * an update as sent only once it publishes it - see
+   * {@link #countSentUpdate(UpdateMsg)}.
    *
    * @return the next update that must be sent to the server managed by this
    *         ServerHandler.
@@ -1014,17 +1021,47 @@
       {
         msg = toNotAssuredUpdateMsg(msg);
       }
-      incrementOutCount();
-      if (msg.isAssured())
-      {
-        incrementAssuredStats(msg);
-      }
       return msg;
     }
     return null;
   }
 
   /**
+   * Gives back the permit of the send window {@link #take()} took for an
+   * update the writer drops rather than sends.
+   * <p>
+   * Only the peer gives permits back, for the updates it receives, and it
+   * never receives this one: kept, the permit would be lost for the rest of
+   * the session, and once more than half of the window is lost that way, the
+   * peer can no longer be sent enough to give any credit back, and the writer
+   * waits for it until the session is re-established (issue #1080).
+   * <p>
+   * A writer which is being shut down is let go of its wait without a permit,
+   * so one given back then may be one it never took: the window of a session
+   * which is going away is not used again.
+   */
+  void releasePermitInSendWindow()
+  {
+    sendWindow.release();
+  }
+
+  /**
+   * Counts an update {@link #take()} returned as sent to the peer, once the
+   * writer publishes it rather than drops it.
+   *
+   * @param msg
+   *          the update the writer publishes
+   */
+  void countSentUpdate(UpdateMsg msg)
+  {
+    incrementOutCount();
+    if (msg.isAssured())
+    {
+      incrementAssuredStats(msg);
+    }
+  }
+
+  /**
    * Substitutes a not assured version of the provided update message so that a
    * peer not expected to acknowledge it does not receive it with the assured
    * flag.

--
Gitblit v1.10.0