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/pdb/PDBStorage.java | 109 +++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 82 insertions(+), 27 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
index 7ad8cc7..392f25b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pdb/PDBStorage.java
@@ -1102,35 +1102,49 @@
@Override
public void close()
{
- if (db != null)
+ try
{
- DirectoryServer.deregisterMonitorProvider(monitor);
- monitor = null;
- try
+ if (db != null)
{
+ // Not yet registered when a failed open got no further than the database itself.
+ if (monitor != null)
+ {
+ DirectoryServer.deregisterMonitorProvider(monitor);
+ monitor = null;
+ }
db.close();
db = null;
}
- catch (final PersistitException e)
- {
- throw new IllegalStateException(e);
- }
}
- if (memQuota != null)
+ catch (final PersistitException e)
{
- if (config.getDBCacheSize() > 0)
- {
- memQuota.releaseMemory(config.getDBCacheSize());
- }
- else
- {
- memQuota.releaseMemory(memQuota.memPercentToBytes(config.getDBCachePercent()));
- }
+ throw new IllegalStateException(e);
}
- config.removePDBChangeListener(this);
- if (diskMonitor != null)
+ finally
{
- diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
+ // Given back after the database, and whether or not its close threw: reporting the memory
+ // free before the database has actually freed it would let a racing enable of another
+ // backend be admitted while this one's cache is still resident.
+ if (memQuota != null)
+ {
+ if (config.getDBCacheSize() > 0)
+ {
+ memQuota.releaseMemory(config.getDBCacheSize());
+ }
+ else
+ {
+ memQuota.releaseMemory(memQuota.memPercentToBytes(config.getDBCachePercent()));
+ }
+ // Released once: what an open takes, the next open takes again, and a close which follows
+ // a close - BackendImpl.importLDIF closes the storage of its root container however the
+ // import ended, on top of the close the import itself made - releases nothing more.
+ memQuota = null;
+ }
+ config.removePDBChangeListener(this);
+ if (diskMonitor != null)
+ {
+ diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
+ }
}
}
@@ -1148,7 +1162,52 @@
// Do not open volume on disk
return;
}
- open0(buildConfiguration(accessMode));
+ rejectIfOpen();
+ openOrGiveBack(buildConfiguration(accessMode));
+ }
+
+ /**
+ * Refuses to open a database which is open, before anything is taken for the attempt: the
+ * refusal guards against a programming error, and what this storage holds is left as it is.
+ */
+ private void rejectIfOpen()
+ {
+ if (db != null)
+ {
+ throw new IllegalStateException(
+ "Database is already open, either the backend is enabled or an import is currently running.");
+ }
+ }
+
+ /**
+ * Opens the database, or gives back what the attempt took before it failed. Nothing else will: a
+ * root container does not close a storage whose {@code open()} threw, and a backend whose open
+ * failed is thrown away with the storage still registered as a listener of its configuration and
+ * the cache size it reserved still drawn from the memory quota - once per attempt to enable it.
+ */
+ private void openOrGiveBack(final Configuration dbCfg) throws ConfigException
+ {
+ boolean opened = false;
+ try
+ {
+ open0(dbCfg);
+ opened = true;
+ }
+ finally
+ {
+ if (!opened)
+ {
+ try
+ {
+ close();
+ }
+ catch (RuntimeException e)
+ {
+ // The failure being given up after is the one worth reporting, and this must not replace it.
+ logger.traceException(e);
+ }
+ }
+ }
}
private boolean isBackendIncomplete(AccessMode accessMode)
@@ -1174,11 +1233,6 @@
setupStorageFiles(backendDirectory, config.getDBDirectoryPermissions(), config.dn());
try
{
- if (db != null)
- {
- throw new IllegalStateException(
- "Database is already open, either the backend is enabled or an import is currently running.");
- }
db = new Persistit(dbCfg);
final long bufferCount = getBufferPoolCfg(dbCfg).computeBufferCount(db.getAvailableHeap());
@@ -1217,7 +1271,8 @@
@Override
public Importer startImport() throws ConfigException, StorageRuntimeException
{
- open0(buildImportConfiguration());
+ rejectIfOpen();
+ openOrGiveBack(buildImportConfiguration());
return new ImporterImpl();
}
--
Gitblit v1.10.0