From 995d54a8963d87335196b86d8d4fc1b252a38ee4 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 07 Sep 2026 08:58:19 +0000
Subject: [PATCH] [#900] Time the ReplicaOfflineMsg grace period per replica, and spend it where the message can still be forwarded (#919)
---
opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 43 insertions(+), 1 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
index 4bea167..ef1ba8b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/server/ReplicationServer.java
@@ -178,6 +178,11 @@
/**
* Creates a new Replication server using the provided configuration entry.
+ * <p>
+ * The synchronization object this creates is its own, so the resulting server does not
+ * synchronize its shutdown with a collocated directory server. A server which has to must be
+ * built with {@link #ReplicationServer(ReplicationServerCfg, DSRSShutdownSync)}, passing the
+ * instance the directory server side records its ReplicaOfflineMsgs on.
*
* @param cfg The configuration of this replication server.
* @throws ConfigException When Configuration is invalid.
@@ -802,6 +807,9 @@
// listen port which cannot be bound, would otherwise leave them behind. Shut them down
// before the changelog they write to, and one unchecked exception at a time: the changelog
// this one is built on is known to be broken, and what follows still has to run.
+ // Nothing in an instance which never finished coming up can forward a pending
+ // ReplicaOfflineMsg, so this path does not wait for one: it would only delay the failure
+ // which is being reported by a grace period which cannot pay off.
for (ReplicationServerDomain domain : getReplicationServerDomains())
{
try
@@ -1181,7 +1189,19 @@
listenThread.interrupt();
}
- // shutdown all the replication domains
+ /*
+ * Let the ReplicaOfflineMsgs a collocated DS sent be forwarded while every handler is still
+ * up, and only then stop the domains: shutting a domain down deactivates the consumer of its
+ * handlers, clears their message queue and closes their session - see OPENDJ-1453. All the
+ * domains wait together and share one deadline, so the shutdown is bounded by one grace
+ * period and the wait of one domain does not spend the grace period of the next.
+ * <p>
+ * This also runs before the assured timer of any domain is cancelled, so an assured update
+ * still waiting for acks keeps timing out during the wait instead of holding its sender
+ * until the sessions are closed.
+ */
+ awaitReplicaOfflineMsgsForwarded();
+
for (ReplicationServerDomain domain : getReplicationServerDomains())
{
domain.shutdown();
@@ -1203,6 +1223,28 @@
}
/**
+ * Waits for the ReplicaOfflineMsg of every domain which has a replication server to forward it
+ * to. With no such server connected there is nobody to forward the message to, and waiting
+ * would only delay the shutdown by the whole grace period.
+ */
+ private void awaitReplicaOfflineMsgsForwarded()
+ {
+ final List<DN> domainsToWaitFor = new ArrayList<>();
+ for (ReplicationServerDomain domain : getReplicationServerDomains())
+ {
+ if (!domain.getConnectedRSs().isEmpty())
+ {
+ domainsToWaitFor.add(domain.getBaseDN());
+ }
+ }
+ if (!domainsToWaitFor.isEmpty())
+ {
+ dsrsShutdownSync.awaitReplicaOfflineMsgsForwarded(
+ domainsToWaitFor, dsrsShutdownSync.newShutdownDeadline());
+ }
+ }
+
+ /**
* Retrieves the time after which changes must be deleted from the
* persistent storage (in milliseconds).
*
--
Gitblit v1.10.0