From 06e91a18f48ddf1cae6cbc9946688dea6a161425 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Sat, 11 Jul 2026 10:36:01 +0000
Subject: [PATCH] [#730] Fix import/export context leak on failed initializeRemote validation (#731)

---
 opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java |   58 ++++++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
index 8781e70..a63f74a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/service/ReplicationDomain.java
@@ -1442,8 +1442,6 @@
       int serverRunningTheTask, Task initTask, int initWindow)
   throws DirectoryException
   {
-    final ImportExportContext ieCtx = acquireIEContext(false);
-
     /*
     We manage the list of servers to initialize in order :
     - to test at the end that all expected servers have reconnected
@@ -1451,7 +1449,12 @@
     - to update the task with the server(s) where this test failed
     */
 
-    Map<Integer, DSInfo> replicaInfos = getReplicaInfos();
+    // Validate the request before acquiring the import/export context: a
+    // validation failure must not leave the context acquired, otherwise
+    // ieRunning() would remain true forever and the domain would reject every
+    // subsequent total update as a simultaneous import/export.
+    final Map<Integer, DSInfo> replicaInfos = getReplicaInfos();
+    final DSInfo targetDsi;
     if (serverToInitialize == RoutableMsg.ALL_SERVERS)
     {
       if (replicaInfos.isEmpty())
@@ -1459,7 +1462,44 @@
         throw new DirectoryException(UNWILLING_TO_PERFORM,
             ERR_FULL_UPDATE_NO_REMOTES.get(getBaseDN(), getServerId()));
       }
+      targetDsi = null;
+    }
+    else
+    {
+      targetDsi = getDsInfoOrNull(replicaInfos.values(), serverToInitialize);
+      if (targetDsi == null)
+      {
+        throw new DirectoryException(UNWILLING_TO_PERFORM,
+            ERR_FULL_UPDATE_MISSING_REMOTE.get(getBaseDN(), getServerId(), serverToInitialize));
+      }
+    }
 
+    final ImportExportContext ieCtx = acquireIEContext(false);
+    try
+    {
+      initializeRemote(ieCtx, replicaInfos, targetDsi, serverToInitialize,
+          serverRunningTheTask, initTask, initWindow);
+    }
+    finally
+    {
+      // Release the context whatever the outcome, otherwise ieRunning() would
+      // remain true forever (resolves the historical "FIXME should not this
+      // be in a finally?").
+      releaseIEContext();
+    }
+  }
+
+  /**
+   * Performs the remote initialization with the import/export context already
+   * acquired - and released - by the caller.
+   */
+  private void initializeRemote(ImportExportContext ieCtx,
+      Map<Integer, DSInfo> replicaInfos, DSInfo targetDsi,
+      int serverToInitialize, int serverRunningTheTask, Task initTask,
+      int initWindow) throws DirectoryException
+  {
+    if (serverToInitialize == RoutableMsg.ALL_SERVERS)
+    {
       logger.info(NOTE_FULL_UPDATE_ENGAGED_FOR_REMOTE_START_ALL,
           countEntries(), getBaseDN(), getServerId());
 
@@ -1475,18 +1515,11 @@
     }
     else
     {
-      DSInfo dsi = getDsInfoOrNull(replicaInfos.values(), serverToInitialize);
-      if (dsi == null)
-      {
-        throw new DirectoryException(UNWILLING_TO_PERFORM,
-            ERR_FULL_UPDATE_MISSING_REMOTE.get(getBaseDN(), getServerId(), serverToInitialize));
-      }
-
       logger.info(NOTE_FULL_UPDATE_ENGAGED_FOR_REMOTE_START, countEntries(),
           getBaseDN(), getServerId(), serverToInitialize);
 
       ieCtx.startList.add(serverToInitialize);
-      ieCtx.setAckVal(dsi.getDsId(), 0);
+      ieCtx.setAckVal(targetDsi.getDsId(), 0);
     }
 
     DirectoryException exportRootException = null;
@@ -1625,9 +1658,6 @@
               ERR_INIT_NO_SUCCESS_END_FROM_SERVERS.get(getGenerationID(), ieCtx.failureList));
     }
 
-    // Don't forget to release IEcontext acquired at beginning.
-    releaseIEContext(); // FIXME should not this be in a finally?
-
     final String cause = exportRootException == null ? ""
         : exportRootException.getLocalizedMessage();
     if (serverToInitialize == RoutableMsg.ALL_SERVERS)

--
Gitblit v1.10.0