From 739ea68b7c5946d80e640fde010221098fd83011 Mon Sep 17 00:00:00 2001
From: Maxim Thomas <maxim.thomas@gmail.com>
Date: Sat, 19 Sep 2026 14:17:51 +0000
Subject: [PATCH] [#962] Flag an admin action when a bounded storage write gives up on a configuration change (#994)
---
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java | 28 +++++++++++++++++++++++-----
1 files changed, 23 insertions(+), 5 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
index 86ddbea..055fdd6 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/AttributeIndex.java
@@ -973,10 +973,6 @@
ccr.addMessage(NOTE_INDEX_ADD_REQUIRES_REBUILD.get(addedIndex));
}
- config = newConfiguration;
- indexingOptions = newIndexingOptions;
- indexIdToIndexes = Collections.unmodifiableMap(newIndexIdToIndexes);
-
// We get exclusive lock to ensure that no query is actually using the indexes that will be deleted.
entryContainer.lock();
try
@@ -992,6 +988,17 @@
}
}
});
+ // Published once the deletion has committed, not before it: a write the storage gives up on
+ // leaves the trees of the removed indexes behind, and a map which no longer names them is a
+ // map through which nothing maintains them and nothing deletes them. The lock has drained
+ // every operation which enters through shared access, so the window in which the map names
+ // trees the write has just deleted lies inside it and no search sees it; published after the
+ // write rather than from within it, so that an operation the storage replays publishes once,
+ // from the attempt which committed. The added indexes are named only at the end of that
+ // window rather than before the deletion, which costs nothing: the write above has just
+ // asked for them to be rebuilt, so nothing may read them until it has been.
+ indexingOptions = newIndexingOptions;
+ indexIdToIndexes = Collections.unmodifiableMap(newIndexIdToIndexes);
}
finally
{
@@ -1020,11 +1027,22 @@
{
updatedIndex.setIndexEntryLimit(newConfiguration.getIndexEntryLimit());
}
+ // Published last: the entry limit this configuration declares reaches the indexes which stay
+ // only once the write which untrusts them has committed, so a configuration published before
+ // that would declare a limit those indexes do not hold yet.
+ config = newConfiguration;
}
catch (Exception e)
{
+ // Logged as well as reported, for the reason given in the index delete listener of
+ // EntryContainer: what this index holds and what its configuration declares may no longer
+ // agree long after the session which asked for the change has ended.
+ final LocalizableMessage message = ERR_CONFIG_INDEX_CHANGE_FAILED.get(getAttributeType().getNameOrOID(),
+ entryContainer.getBaseDN(), StaticUtils.stackTraceToSingleLineString(e));
+ logger.error(message);
ccr.setResultCode(DirectoryServer.getCoreConfigManager().getServerErrorResultCode());
- ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e)));
+ ccr.setAdminActionRequired(true);
+ ccr.addMessage(message);
}
return ccr;
--
Gitblit v1.10.0