From 5154f34503981b2f96755b1b6da9b425bb20ca7f Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Thu, 05 Nov 2026 14:32:12 +0000
Subject: [PATCH] [#1269] Preserve replay order across duplicate replication deliveries (#1270)

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/UpdateToReplay.java |   37 +++++++++++++++++++++++++++++++------
 1 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/UpdateToReplay.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/UpdateToReplay.java
index 3919dd6..6fdf659 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/UpdateToReplay.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/UpdateToReplay.java
@@ -13,21 +13,22 @@
  *
  * Copyright 2006-2008 Sun Microsystems, Inc.
  * Portions Copyright 2015 ForgeRock AS.
+ * Portions Copyright 2026 3A Systems, LLC.
  */
 package org.opends.server.replication.plugin;
 
 import org.opends.server.replication.protocol.LDAPUpdateMsg;
 
 /**
- * This is a bag class to hold an update to replay in the queue of updates to
- * be replayed by the replay threads.
- * It associates an update message to replay with the matching
- * ReplicationDomain.
+ * A delivery in the shared replay queue, associating an update with its domain.
+ * Cancellation belongs to this delivery, so an enqueue or claim failure can release
+ * it without acquiring the pending-changes lock or cancelling a newer retry.
  */
 public class UpdateToReplay
 {
-  private LDAPUpdateMsg updateMessage;
-  private LDAPReplicationDomain replicationDomain;
+  private final LDAPUpdateMsg updateMessage;
+  private final LDAPReplicationDomain replicationDomain;
+  private volatile boolean cancelled;
 
   /**
    * Construct the object associating the update message with the replication
@@ -44,6 +45,30 @@
   }
 
   /**
+   * Releases a failed hand-off without a lock or allocation, even on an OOME road.
+   * A stale cancellation affects only this delivery, never the retry which replaced it.
+   */
+  void cancel()
+  {
+    cancel(true);
+  }
+
+  /** Cancels this delivery, optionally requesting another session. */
+  void cancel(boolean requestRestart)
+  {
+    cancelled = true;
+    if (requestRestart && replicationDomain != null)
+    {
+      replicationDomain.requestSessionRestart();
+    }
+  }
+
+  boolean isCancelled()
+  {
+    return cancelled;
+  }
+
+  /**
    * Getter for update message.
    * @return The update message
    */

--
Gitblit v1.10.0