From 74fea9c73aa679eebe68f78d34ae80fa0f263c24 Mon Sep 17 00:00:00 2001
From: Fabio Pistolesi <fabio.pistolesi@forgerock.com>
Date: Fri, 21 Oct 2016 09:41:24 +0000
Subject: [PATCH] OPENDJ-3400 Fake a no-operation storage for offline commands when a suffix has no files
---
opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 108 insertions(+), 9 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java
index e6115f3..210a267 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/jeb/JEStorage.java
@@ -56,6 +56,7 @@
import org.forgerock.opendj.server.config.server.JEBackendCfg;
import org.opends.server.api.Backupable;
import org.opends.server.api.DiskSpaceMonitorHandler;
+import org.opends.server.backends.pluggable.spi.EmptyCursor;
import org.opends.server.backends.pluggable.spi.AccessMode;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.Importer;
@@ -352,7 +353,7 @@
* <ol>
* <li>Opening the EntryContainer calls {@link #openTree(TreeName, boolean)} for each index</li>
* <li>Then the underlying storage is closed</li>
- * <li>Then {@link Importer#startImport()} is called</li>
+ * <li>Then {@link #startImport()} is called</li>
* <li>Then ID2Entry#put() is called</li>
* <li>Which in turn calls ID2Entry#encodeEntry()</li>
* <li>Which in turn finally calls PersistentCompressedSchema#store()</li>
@@ -520,7 +521,7 @@
}
}
- /** JE read-only implementation of {@link StorageImpl} interface. */
+ /** JE read-only implementation of {@link WriteableTransaction} interface. */
private final class ReadOnlyTransactionImpl implements WriteableTransaction
{
private final WriteableTransactionImpl delegate;
@@ -583,8 +584,69 @@
}
}
+ /** No operation storage transaction faking database files are present and empty. */
+ private final class ReadOnlyEmptyTransactionImpl implements WriteableTransaction
+ {
+ @Override
+ public void openTree(TreeName name, boolean createOnDemand)
+ {
+ if (createOnDemand)
+ {
+ throw new ReadOnlyStorageException();
+ }
+ }
+
+ @Override
+ public void deleteTree(TreeName name)
+ {
+ throw new ReadOnlyStorageException();
+ }
+
+ @Override
+ public void put(TreeName treeName, ByteSequence key, ByteSequence value)
+ {
+ throw new ReadOnlyStorageException();
+ }
+
+ @Override
+ public boolean update(TreeName treeName, ByteSequence key, UpdateFunction f)
+ {
+ throw new ReadOnlyStorageException();
+ }
+
+ @Override
+ public boolean delete(TreeName treeName, ByteSequence key)
+ {
+ throw new ReadOnlyStorageException();
+ }
+
+ @Override
+ public ByteString read(TreeName treeName, ByteSequence key)
+ {
+ return null;
+ }
+
+ @Override
+ public Cursor<ByteString, ByteString> openCursor(TreeName treeName)
+ {
+ return new EmptyCursor<>();
+ }
+
+ @Override
+ public long getRecordCount(TreeName treeName)
+ {
+ return 0;
+ }
+ }
+
private WriteableTransaction newWriteableTransaction(Transaction txn)
{
+ // If no database files have been created yet and we're opening READ-ONLY
+ // there is no db to use, since open was not called. Fake it.
+ if (env == null)
+ {
+ return new ReadOnlyEmptyTransactionImpl();
+ }
final WriteableTransactionImpl writeableStorage = new WriteableTransactionImpl(txn);
return accessMode.isWriteable() ? writeableStorage : new ReadOnlyTransactionImpl(writeableStorage);
}
@@ -601,6 +663,7 @@
private JEBackendCfg config;
private AccessMode accessMode;
+ /** It is NULL when opening the storage READ-ONLY and no files have been created yet. */
private Environment env;
private EnvironmentConfig envConfig;
private MemoryQuota memQuota;
@@ -713,26 +776,58 @@
}
}
- if (config.getDBCacheSize() > 0)
+ if (memQuota != null)
{
- memQuota.releaseMemory(config.getDBCacheSize());
- }
- else
- {
- memQuota.releaseMemory(memQuota.memPercentToBytes(config.getDBCachePercent()));
+ if (config.getDBCacheSize() > 0)
+ {
+ memQuota.releaseMemory(config.getDBCacheSize());
+ }
+ else
+ {
+ memQuota.releaseMemory(memQuota.memPercentToBytes(config.getDBCachePercent()));
+ }
}
config.removeJEChangeListener(this);
- diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
+ envConfig = null;
+ if (diskMonitor != null)
+ {
+ diskMonitor.deregisterMonitoredDirectory(getDirectory(), this);
+ }
}
@Override
public void open(AccessMode accessMode) throws ConfigException, StorageRuntimeException
{
Reject.ifNull(accessMode, "accessMode must not be null");
+ if (isBackendIncomplete(accessMode))
+ {
+ envConfig = new EnvironmentConfig();
+ envConfig.setAllowCreate(false).setTransactional(false);
+ // Do not open files on disk
+ return;
+ }
buildConfiguration(accessMode, false);
open0();
}
+ private boolean isBackendIncomplete(AccessMode accessMode)
+ {
+ return !accessMode.isWriteable() && (!backendDirectory.exists() || backendDirectoryIncomplete());
+ }
+
+ // TODO: it belongs to disk-based Storage Interface.
+ private boolean backendDirectoryIncomplete()
+ {
+ try
+ {
+ return !getFilesToBackup().hasNext();
+ }
+ catch (DirectoryException ignored)
+ {
+ return true;
+ }
+ }
+
private void open0() throws ConfigException
{
setupStorageFiles(backendDirectory, config.getDBDirectoryPermissions(), config.dn());
@@ -1073,6 +1168,10 @@
@Override
public Set<TreeName> listTrees()
{
+ if (env == null)
+ {
+ return Collections.<TreeName>emptySet();
+ }
try
{
List<String> treeNames = env.getDatabaseNames();
--
Gitblit v1.10.0