From 466fc15f25bd00f774f40909fd30cb9a0674f555 Mon Sep 17 00:00:00 2001 From: Valera V Harseko Date: Fri, 3 Jul 2026 18:14:59 +0300 Subject: [PATCH] Skip replication processing when no replication domain is configured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Multimaster Synchronization provider is enabled by default even on standalone servers with no replication domain configured, and its three per-operation hooks (conflict resolution, pre-operation, post-operation) each called findDomain(), which iterated the request controls and walked the entry DN up to the suffix querying an empty domains map, allocating a fresh result object every time. Return null from findDomain() before the DN walk when no domains are registered (repair-control processing is preserved), and reuse a shared stateless ContinueProcessing result instead of allocating one per hook invocation. An interleaved A/B under concurrent modify load shows no measurable throughput change on an 8-core host — the write path is dominated by the JE write-ahead log — so this is a cleanliness fix: it removes pointless per-write work from every non-replicated deployment rather than a measured win. --- .../plugin/MultimasterReplication.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/MultimasterReplication.java b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/MultimasterReplication.java index a692fa9b9e..0bc8a036e4 100644 --- a/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/MultimasterReplication.java +++ b/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/MultimasterReplication.java @@ -13,6 +13,7 @@ * * Copyright 2006-2010 Sun Microsystems, Inc. * Portions Copyright 2011-2016 ForgeRock AS. + * Portions Copyright 2026 3A Systems, LLC */ package org.opends.server.replication.plugin; @@ -97,6 +98,12 @@ public class MultimasterReplication private ReplicationServerListener replicationServerListener; private static final Map domains = new ConcurrentHashMap<>(4); + /** + * Shared stateless "continue processing" result: the provider hooks run for + * every operation, so avoid allocating a fresh result each time. + */ + private static final SynchronizationProviderResult CONTINUE = + new SynchronizationProviderResult.ContinueProcessing(); private static final DSRSShutdownSync dsrsShutdownSync = new DSRSShutdownSync(); /** The queue of received update messages, to be treated by the ReplayThread threads. */ private static final BlockingQueue updateToReplayQueue = new LinkedBlockingQueue<>(10000); @@ -166,6 +173,15 @@ public static LDAPReplicationDomain findDomain(DN dn, PluginOperation pluginOp) } } + if (domains.isEmpty()) + { + // The Multimaster Synchronization provider is enabled by default even + // on standalone servers with no replication domain configured: skip + // the walk to the suffix that every write operation would otherwise + // pay three times (conflict resolution, pre- and post-operation). + return null; + } + LDAPReplicationDomain domain = null; DN temp = dn; BackendConfigManager backendConfigManager = @@ -402,7 +418,7 @@ public SynchronizationProviderResult handleConflictResolution( { return domain.handleConflictResolution(modifyOperation); } - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -414,7 +430,7 @@ public SynchronizationProviderResult handleConflictResolution( { return domain.handleConflictResolution(addOperation); } - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -426,7 +442,7 @@ public SynchronizationProviderResult handleConflictResolution( { return domain.handleConflictResolution(deleteOperation); } - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -438,7 +454,7 @@ public SynchronizationProviderResult handleConflictResolution( { return domain.handleConflictResolution(modifyDNOperation); } - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -450,7 +466,7 @@ public SynchronizationProviderResult handleConflictResolution( if (domain == null || !domain.solveConflict()) { - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } EntryHistorical historicalInformation = (EntryHistorical) @@ -475,14 +491,14 @@ public SynchronizationProviderResult handleConflictResolution( ResultCode.SUCCESS, null); } - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override public SynchronizationProviderResult doPreOperation( PreOperationDeleteOperation deleteOperation) throws DirectoryException { - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -495,7 +511,7 @@ public SynchronizationProviderResult doPreOperation( if (domain == null || !domain.solveConflict()) { - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } // The historical object is retrieved from the attachment created @@ -516,7 +532,7 @@ public SynchronizationProviderResult doPreOperation( // Add to the operation the historical attribute : "dn:changeNumber:moddn" historicalInformation.setHistoricalAttrToOperation(modifyDNOperation); - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override @@ -528,7 +544,7 @@ public SynchronizationProviderResult doPreOperation( findDomain(addOperation.getEntryDN(), addOperation); if (domain == null) { - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } // For LOCAL op only, generate CSN and attach Context @@ -540,7 +556,7 @@ public SynchronizationProviderResult doPreOperation( // Add to the operation the historical attribute : "dn:changeNumber:add" EntryHistorical.setHistoricalAttrToOperation(addOperation); - return new SynchronizationProviderResult.ContinueProcessing(); + return CONTINUE; } @Override