From 1af0a1247d3e2d503a53723dd1d844c90c43ccc6 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Sat, 19 Sep 2026 08:56:47 +0000
Subject: [PATCH] [#993] Register an entry container's configuration listeners only once it has opened (#999)

---
 opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java |   41 +++++++++++++++++++++++++++--------------
 1 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
index 917b230..d47e2db 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/EntryContainer.java
@@ -467,15 +467,8 @@
     this.dn2uri = new DN2URI(getIndexName(REFERRAL_TREE_NAME), this);
     this.state = new State(getIndexName(STATE_TREE_NAME));
 
-    config.addPluggableChangeListener(this);
-
     attributeIndexCfgManager = new AttributeIndexCfgManager();
-    config.addBackendIndexAddListener(attributeIndexCfgManager);
-    config.addBackendIndexDeleteListener(attributeIndexCfgManager);
-
     vlvIndexCfgManager = new VLVIndexCfgManager();
-    config.addBackendVLVIndexAddListener(vlvIndexCfgManager);
-    config.addBackendVLVIndexDeleteListener(vlvIndexCfgManager);
   }
 
   private CryptoSuite newCryptoSuite(boolean confidentiality)
@@ -533,13 +526,16 @@
 
         CryptoSuite cryptoSuite = newCryptoSuite(indexCfg.isConfidentialityEnabled());
         final AttributeIndex index = newAttributeIndex(indexCfg, cryptoSuite);
+        // Held before it is opened, because open() is what registers it as a listener of its own
+        // configuration and close() is what takes that off again: an index which fails while
+        // opening is one this container must still be able to close.
+        attrIndexMap.put(indexCfg.getAttribute(), index);
+        attrCryptoMap.put(indexCfg.getAttribute(), cryptoSuite);
         index.open(txn, shouldCreate);
         if(!index.isTrusted() && isNotEmpty)
         {
           logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, index.getName());
         }
-        attrIndexMap.put(indexCfg.getAttribute(), index);
-        attrCryptoMap.put(indexCfg.getAttribute(), cryptoSuite);
       }
 
       for (String idx : config.listBackendVLVIndexes())
@@ -547,20 +543,37 @@
         BackendVLVIndexCfg vlvIndexCfg = config.getBackendVLVIndex(idx);
 
         VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, storage, this, txn);
+        // Held before it is opened, for the reason given above, and here the window is wider still:
+        // a VLV index registers itself as a listener of its configuration from its constructor.
+        vlvIndexMap.put(vlvIndexCfg.getName().toLowerCase(), vlvIndex);
         vlvIndex.open(txn, shouldCreate);
         if(!vlvIndex.isTrusted() && isNotEmpty)
         {
           logger.info(NOTE_INDEX_ADD_REQUIRES_REBUILD, vlvIndex.getName());
         }
-
-        vlvIndexMap.put(vlvIndexCfg.getName().toLowerCase(), vlvIndex);
       }
+
+      // Registered once everything they answer for is open, and never from the constructor: an
+      // entry container which fails to open is registered nowhere - RootContainer.openEntryContainer
+      // and BackendImpl.changeBaseDNTrees both let the failure through before anything holds it -
+      // so nothing would ever call the close() which takes these off again, and they would go on
+      // answering configuration changes for a backend which is not running. Nothing can reach this
+      // container in between either: open() is called before it is registered anywhere.
+      config.addPluggableChangeListener(this);
+      config.addBackendIndexAddListener(attributeIndexCfgManager);
+      config.addBackendIndexDeleteListener(attributeIndexCfgManager);
+      config.addBackendVLVIndexAddListener(vlvIndexCfgManager);
+      config.addBackendVLVIndexDeleteListener(vlvIndexCfgManager);
     }
-    catch (StorageRuntimeException de)
+    catch (Exception e)
     {
-      logger.traceException(de);
+      // Every failure, not the storage ones alone: open() is declared to throw ConfigException and
+      // does - an index type the attribute has no matching rule for, an index protecting both its
+      // keys and its values, a VLV filter or sort order which does not parse - and the indexes
+      // opened before it registered listeners of their own, which only close() takes back.
+      logger.traceException(e);
       close();
-      throw de;
+      throw e;
     }
   }
 

--
Gitblit v1.10.0