From c6650aedac5c1ade8aee9e7a76eb0dd100a3e179 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 02 Nov 2026 15:39:56 +0000
Subject: [PATCH] [#1246] Keep the messages of the last local changes, and have a recovery publish the changes done before it began from them, as they were done (#1251)

---
 opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java |   35 +++++++++++++++++++++++++++++++++++
 1 files changed, 35 insertions(+), 0 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
index ea42838..88c8de3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/LocalBackend.java
@@ -20,6 +20,8 @@
 import static org.opends.messages.BackendMessages.*;
 
 import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -76,6 +78,39 @@
 {
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
+  /** Process-lifetime write barriers for data which cannot safely be used after an online replacement. */
+  private static final Map<DN, LocalizableMessage> writeFailures = new ConcurrentHashMap<>();
+
+  /**
+   * Prevents writes overlapping a failed data replacement until the server process is restarted.
+   * An in-core restart keeps the barrier, as it keeps the JVM running.
+   * The barrier survives backend and synchronization-provider reconfiguration.
+   * @param baseDN the suffix whose data cannot safely be written
+   * @param reason the reason to report to the operator and to rejected updates
+   */
+  public static void quarantineWrites(DN baseDN, LocalizableMessage reason)
+  {
+    writeFailures.putIfAbsent(baseDN, reason);
+  }
+
+  /**
+   * Returns the reason writes overlapping a suffix are forbidden, or null if none are forbidden.
+   * Ancestors are included because deleting or moving a subtree affects the suffix below it.
+   * @param dn the DN of the entry or subtree an operation changes
+   * @return the recorded failure, or null
+   */
+  public static LocalizableMessage getWriteFailure(DN dn)
+  {
+    for (Map.Entry<DN, LocalizableMessage> failure : writeFailures.entrySet())
+    {
+      if (dn.isSubordinateOrEqualTo(failure.getKey()) || dn.isSuperiorOrEqualTo(failure.getKey()))
+      {
+        return failure.getValue();
+      }
+    }
+    return null;
+  }
+
   /** Indicates whether this is a private backend or one that holds user data. */
   private boolean isPrivateBackend;
 

--
Gitblit v1.10.0