From 5905074f71d4add21a72881816b873e3053d8a37 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 02 Dec 2014 09:57:47 +0000
Subject: [PATCH] OPENDJ-1602 New pluggable storage based backend
---
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java | 150 ++++++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java | 51 ++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java | 33 +
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java | 308 ++++++++++++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java | 13
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java | 33 +
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java | 168 +++++++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java | 316 +++++++++++++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java | 94 +++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java | 3
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java | 160 ++++++
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java | 106 ++++
12 files changed, 1,410 insertions(+), 25 deletions(-)
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 6c5df91..33f1ca7 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -75,17 +75,17 @@
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
/** The name of the entry database. */
- public static final String ID2ENTRY_DATABASE_NAME = "id2entry";
+ public static final String ID2ENTRY_DATABASE_NAME = ID2ENTRY_INDEX_NAME;
/** The name of the DN database. */
- public static final String DN2ID_DATABASE_NAME = "dn2id";
+ public static final String DN2ID_DATABASE_NAME = DN2ID_INDEX_NAME;
/** The name of the children index database. */
- private static final String ID2CHILDREN_DATABASE_NAME = "id2children";
+ private static final String ID2CHILDREN_DATABASE_NAME = ID2CHILDREN_INDEX_NAME;
/** The name of the subtree index database. */
- private static final String ID2SUBTREE_DATABASE_NAME = "id2subtree";
+ private static final String ID2SUBTREE_DATABASE_NAME = ID2SUBTREE_INDEX_NAME;
/** The name of the referral database. */
- private static final String REFERRAL_DATABASE_NAME = "referral";
+ private static final String REFERRAL_DATABASE_NAME = REFERRAL_INDEX_NAME;
/** The name of the state database. */
- private static final String STATE_DATABASE_NAME = "state";
+ private static final String STATE_DATABASE_NAME = STATE_INDEX_NAME;
/** The attribute used to return a search index debug string to the client. */
public static final String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
@@ -510,6 +510,7 @@
*
* @throws DatabaseException If an error occurs in the JE database.
*/
+ @Override
public void close() throws DatabaseException
{
// Close core indexes.
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java
new file mode 100644
index 0000000..4660da0
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitBackend.java
@@ -0,0 +1,150 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.persistit;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.opends.server.admin.std.server.LocalDBBackendCfg;
+import org.opends.server.backends.pluggable.PluggableStorageBackend;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.InitializationException;
+
+import com.persistit.exception.PersistitException;
+import com.sleepycat.je.DatabaseException;
+
+import static org.opends.messages.BackendMessages.*;
+import static org.opends.messages.JebMessages.*;
+import static org.opends.server.util.StaticUtils.*;
+
+/**
+ * This is an implementation of a Directory Server Backend which stores entries
+ * locally in a Persistit database.
+ */
+public class PersistitBackend extends PluggableStorageBackend<LocalDBBackendCfg>
+{
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ private PersistitRootContainer rootContainer;
+
+ /**
+ * Returns the root container.
+ *
+ * @return the root container
+ */
+ public PersistitRootContainer getRootContainer()
+ {
+ return rootContainer;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void initializeBackend() throws ConfigException, InitializationException
+ {
+ rootContainer = new PersistitRootContainer(this, cfg);
+ rootContainer.open();
+
+ registerBaseDNs(cfg.getBaseDN());
+
+ cfg.addLocalDBChangeListener(this);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void finalizeBackend()
+ {
+ super.finalizeBackend();
+ cfg.removeLocalDBChangeListener(this);
+
+ deregisterBaseDNs(rootContainer.getSuffixContainers().keySet());
+
+ // Close the database.
+ try
+ {
+ rootContainer.close();
+ rootContainer = null;
+ }
+ catch (DatabaseException e)
+ {
+ logger.traceException(e);
+ logger.error(ERR_JEB_DATABASE_EXCEPTION, e.getMessage());
+ }
+
+ // Log an informational message.
+ logger.info(NOTE_BACKEND_OFFLINE, cfg.getBackendId());
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long getEntryCount()
+ {
+ if (rootContainer != null)
+ {
+ try
+ {
+ return rootContainer.getEntryCount();
+ }
+ catch (Exception e)
+ {
+ logger.traceException(e);
+ }
+ }
+ return -1;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Entry getEntry(DN entryDN) throws DirectoryException
+ {
+ PersistitSuffixContainer sc = rootContainer.getSuffixContainer(entryDN);
+ try
+ {
+ return sc.getEntry(entryDN);
+ }
+ catch (PersistitException e)
+ {
+ logger.traceException(e);
+ throw createDirectoryException(e);
+ }
+ }
+
+ /**
+ * Creates a customized DirectoryException from the DatabaseException thrown
+ * by JE backend.
+ *
+ * @param e
+ * The PersistitException to be converted.
+ * @return DirectoryException created from exception.
+ */
+ private DirectoryException createDirectoryException(PersistitException e)
+ {
+ // TODO JNR rename the exception to remove the "JEB"
+ LocalizableMessage message = ERR_JEB_DATABASE_EXCEPTION.get(stackTraceToSingleLineString(e));
+ return new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e);
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java
new file mode 100644
index 0000000..3767624
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitDN2ID.java
@@ -0,0 +1,168 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.persistit;
+
+import org.opends.server.backends.jeb.EntryID;
+import org.opends.server.backends.pluggable.KeyValueStore;
+import org.opends.server.backends.pluggable.NotImplementedException;
+import org.opends.server.backends.pluggable.SuffixContainer;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+
+import com.persistit.Exchange;
+import com.persistit.Key;
+import com.persistit.Transaction;
+import com.persistit.Value;
+import com.persistit.exception.PersistitException;
+
+import static org.opends.server.backends.jeb.JebFormat.*;
+
+/**
+ * Persistit implementation of the DN2ID index.
+ */
+class PersistitDN2ID implements KeyValueStore<DN, EntryID, Transaction, Void>
+{
+
+ private static final String INDEX_NAME = SuffixContainer.ID2ENTRY_INDEX_NAME;
+ private final String fullyQualifiedIndexName;
+ private final PersistitSuffixContainer suffixContainer;
+ private final int prefixRDNComponents;
+
+ /**
+ * Creates a new dn2id index.
+ *
+ * @param suffixContainer
+ * the suffix container holding this dn2id index
+ */
+ PersistitDN2ID(PersistitSuffixContainer suffixContainer)
+ {
+ this.suffixContainer = suffixContainer;
+ this.fullyQualifiedIndexName = suffixContainer.getFullyQualifiedIndexName(INDEX_NAME);
+ this.prefixRDNComponents = suffixContainer.getBaseDN().size();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void open() throws DirectoryException
+ {
+ try
+ {
+ this.suffixContainer.createTree(INDEX_NAME);
+ }
+ catch (PersistitException e)
+ {
+ throw new NotImplementedException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean insert(Transaction txn, DN dn, EntryID entryID) throws DirectoryException
+ {
+ Exchange ex = null;
+ try
+ {
+ ex = suffixContainer.getExchange(INDEX_NAME);
+ appendAll(ex.getKey(), dnToDNKey(dn, prefixRDNComponents));
+ ex.getValue().put(entryID.longValue());
+ ex.store();
+ return true;
+ }
+ catch (PersistitException e)
+ {
+ throw new NotImplementedException(e);
+ }
+ finally
+ {
+ suffixContainer.releaseExchange(ex);
+ }
+ }
+
+ private void appendAll(Key key, byte[] bytes)
+ {
+ if (bytes.length == 0)
+ {
+ // TODO JNR which is best here?
+ // key.append(null);
+ key.append((byte) ',');
+ }
+ else
+ {
+ // FIXME JNR this way to append is really not efficient
+ for (byte b : bytes)
+ {
+ key.append(b);
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean put(Transaction txn, DN dn, EntryID entryID) throws DirectoryException
+ {
+ throw new NotImplementedException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public EntryID get(Transaction txn, DN dn, Void mode) throws DirectoryException
+ {
+ Exchange ex = null;
+ try
+ {
+ ex = suffixContainer.getExchange(INDEX_NAME);
+ appendAll(ex.getKey(), dnToDNKey(dn, prefixRDNComponents));
+ ex.fetch();
+ final Value value = ex.getValue();
+ if (value.isDefined())
+ {
+ return new EntryID(value.getLong());
+ }
+ return null;
+ }
+ catch (PersistitException e)
+ {
+ throw new NotImplementedException(e);
+ }
+ finally
+ {
+ suffixContainer.releaseExchange(ex);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean remove(Transaction txn, DN dn) throws DirectoryException
+ {
+ throw new NotImplementedException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close()
+ {
+ // nothing to do
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java
new file mode 100644
index 0000000..5c0bc54
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitID2Entry.java
@@ -0,0 +1,160 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.persistit;
+
+import org.forgerock.opendj.ldap.ByteString;
+import org.opends.server.api.CompressedSchema;
+import org.opends.server.backends.jeb.DataConfig;
+import org.opends.server.backends.jeb.EntryID;
+import org.opends.server.backends.jeb.ID2Entry;
+import org.opends.server.backends.pluggable.KeyValueStore;
+import org.opends.server.backends.pluggable.NotImplementedException;
+import org.opends.server.backends.pluggable.SuffixContainer;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+
+import com.persistit.Exchange;
+import com.persistit.Value;
+import com.persistit.exception.PersistitException;
+
+/**
+ * Persistit implementation of the ID2entry index.
+ */
+class PersistitID2Entry implements KeyValueStore<EntryID, Entry, Void, Void>
+{
+
+ // TODO JNR use com.persistit.encoding.ObjectCache when decoding attributes?
+
+ private static final String INDEX_NAME = SuffixContainer.ID2ENTRY_INDEX_NAME;
+ private final String fullyQualifiedIndexName;
+ private final PersistitSuffixContainer suffixContainer;
+ /** TODO JNR remove. */
+ private final DataConfig dataConfig = new DataConfig(false, false, new CompressedSchema());
+
+ /**
+ * Creates a new id2entry index.
+ *
+ * @param suffixContainer
+ * the suffix container holding this id2entry index
+ */
+ PersistitID2Entry(PersistitSuffixContainer suffixContainer)
+ {
+ this.suffixContainer = suffixContainer;
+ this.fullyQualifiedIndexName = suffixContainer.getFullyQualifiedIndexName(INDEX_NAME);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void open() throws DirectoryException
+ {
+ try
+ {
+ this.suffixContainer.createTree(INDEX_NAME);
+ }
+ catch (PersistitException e)
+ {
+ throw new NotImplementedException(e);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean insert(Void txn, EntryID entryID, Entry entry) throws DirectoryException
+ {
+ Exchange ex = null;
+ try
+ {
+ ex = suffixContainer.getExchange(INDEX_NAME);
+ ex.getKey().append(entryID.longValue());
+ ex.getValue().putByteArray(toByteArray(entry));
+ ex.store();
+ return true;
+ }
+ catch (PersistitException e)
+ {
+ throw new NotImplementedException(e);
+ }
+ finally
+ {
+ suffixContainer.releaseExchange(ex);
+ }
+ }
+
+ private byte[] toByteArray(Entry entry) throws DirectoryException
+ {
+ ByteString bs = ID2Entry.entryToDatabase(entry, dataConfig);
+ return bs.toByteArray();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean put(Void txn, EntryID entryID, Entry entry) throws DirectoryException
+ {
+ throw new NotImplementedException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Entry get(Void txn, EntryID entryID, Void mode) throws DirectoryException
+ {
+ Exchange ex = null;
+ try
+ {
+ ex = suffixContainer.getExchange(INDEX_NAME);
+ ex.getKey().append(entryID.longValue());
+ ex.fetch();
+ final Value value = ex.getValue();
+ if (value.isDefined())
+ {
+ ByteString bytes = ByteString.wrap(value.getByteArray());
+ CompressedSchema compressedSchema = dataConfig.getEntryEncodeConfig().getCompressedSchema();
+ return ID2Entry.entryFromDatabase(bytes, compressedSchema);
+ }
+ return null;
+ }
+ catch (Exception e)
+ {
+ throw new NotImplementedException(e);
+ }
+ finally
+ {
+ suffixContainer.releaseExchange(ex);
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean remove(Void txn, EntryID entryID) throws DirectoryException
+ {
+ throw new NotImplementedException();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close()
+ {
+ // nothing to do
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java
new file mode 100644
index 0000000..e7d0450
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitRootContainer.java
@@ -0,0 +1,316 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.persistit;
+
+import java.io.File;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.opends.server.admin.std.server.LocalDBBackendCfg;
+import org.opends.server.backends.pluggable.NotImplementedException;
+import org.opends.server.backends.pluggable.RootContainer;
+import org.opends.server.backends.pluggable.SuffixContainer;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.FilePermission;
+import org.opends.server.types.InitializationException;
+
+import com.persistit.Persistit;
+import com.persistit.Volume;
+import com.persistit.exception.PersistitException;
+
+import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.JebMessages.*;
+import static org.opends.server.util.StaticUtils.*;
+
+/**
+ * Persistit implementation of a {@link RootContainer}.
+ */
+class PersistitRootContainer implements RootContainer<PersistitSuffixContainer>
+{
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ private final PersistitBackend backend;
+ private final LocalDBBackendCfg cfg;
+ private Persistit db;
+
+ /** The base DNs contained in this root container. */
+ private final ConcurrentHashMap<DN, PersistitSuffixContainer> suffixContainers =
+ new ConcurrentHashMap<DN, PersistitSuffixContainer>();
+
+ /**
+ * Constructor for this class.
+ *
+ * @param backend
+ * the persistit backend
+ * @param config
+ * the configuration object
+ */
+ PersistitRootContainer(PersistitBackend backend, LocalDBBackendCfg config)
+ {
+ this.backend = backend;
+ this.cfg = config;
+ }
+
+ /**
+ * Returns the persistit backend.
+ *
+ * @return the persistit backend
+ */
+ public final PersistitBackend getBackend()
+ {
+ return backend;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Map<DN, PersistitSuffixContainer> getSuffixContainers()
+ {
+ return suffixContainers;
+ }
+
+ /**
+ * Code copied from
+ * {@link org.opends.server.backends.jeb. RootContainer#open(com.sleepycat.je.EnvironmentConfig)}
+ *
+ * @throws ConfigException
+ * If an configuration error occurs while creating the environment.
+ */
+ void open() throws ConfigException
+ {
+ // Determine the backend database directory.
+ File parentDirectory = getFileForPath(cfg.getDBDirectory());
+ File backendDirectory = new File(parentDirectory, cfg.getBackendId());
+
+ // Create the directory if it doesn't exist.
+ if (!backendDirectory.exists())
+ {
+ if (!backendDirectory.mkdirs())
+ {
+ throw new ConfigException(ERR_JEB_CREATE_FAIL.get(backendDirectory.getPath()));
+ }
+ }
+ // Make sure the directory is valid.
+ else if (!backendDirectory.isDirectory())
+ {
+ throw new ConfigException(ERR_JEB_DIRECTORY_INVALID.get(backendDirectory.getPath()));
+ }
+
+ FilePermission backendPermission;
+ try
+ {
+ backendPermission = FilePermission.decodeUNIXMode(cfg.getDBDirectoryPermissions());
+ }
+ catch (Exception e)
+ {
+ throw new ConfigException(ERR_CONFIG_BACKEND_MODE_INVALID.get(cfg.dn()));
+ }
+
+ // Make sure the mode will allow the server itself access to the database
+ if (!backendPermission.isOwnerWritable()
+ || !backendPermission.isOwnerReadable()
+ || !backendPermission.isOwnerExecutable())
+ {
+ throw new ConfigException(ERR_CONFIG_BACKEND_INSANE_MODE.get(cfg.getDBDirectoryPermissions()));
+ }
+
+ // Get the backend database backendDirectory permissions and apply
+ if (FilePermission.canSetPermissions())
+ {
+ try
+ {
+ if (!FilePermission.setPermissions(backendDirectory, backendPermission))
+ {
+ logger.warn(WARN_JEB_UNABLE_SET_PERMISSIONS, backendPermission, backendDirectory);
+ }
+ }
+ catch (Exception e)
+ {
+ // Log an warning that the permissions were not set.
+ logger.warn(WARN_JEB_SET_PERMISSIONS_FAILED, backendDirectory, e);
+ }
+ }
+
+ openAndRegisterSuffixContainers(backendDirectory);
+ }
+
+ private void openAndRegisterSuffixContainers(File backendDirectory)
+ {
+ DN[] baseDNs = backend.getBaseDNs();
+ final Properties properties = new Properties();
+ properties.setProperty("datapath", backendDirectory.toString());
+ properties.setProperty("logpath", backendDirectory + "/log");
+ properties.setProperty("logfile", "${logpath}/dj_${timestamp}.log");
+ properties.setProperty("buffer.count.16384", "64K");
+ for (int i = 0; i < baseDNs.length; i++)
+ {
+ // TODO JNR in the replace() down below,
+ // persistit does not like commas and does not know how to escape them
+ final String baseDN = toVolumeName(baseDNs[i]);
+ properties.setProperty("volume." + (i + 1), "${datapath}/" + baseDN + ",create,pageSize:16K,"
+ + "initialSize:50M,extensionSize:1M,maximumSize:10G");
+ }
+ properties.setProperty("journalpath", "${datapath}/dj_journal");
+ try
+ {
+ db = new Persistit(properties);
+ db.initialize();
+
+ openAndRegisterSuffixContainers(baseDNs);
+
+ if (logger.isTraceEnabled())
+ {
+ logger.trace("Persistit (%s) environment opened with the following config: %n%s",
+ Persistit.VERSION, properties);
+
+ // Get current size of heap in bytes
+ long heapSize = Runtime.getRuntime().totalMemory();
+
+ // Get maximum size of heap in bytes. The heap cannot grow beyond this size.
+ // Any attempt will result in an OutOfMemoryException.
+ long heapMaxSize = Runtime.getRuntime().maxMemory();
+
+ // Get amount of free memory within the heap in bytes. This size will increase
+ // after garbage collection and decrease as new objects are created.
+ long heapFreeSize = Runtime.getRuntime().freeMemory();
+
+ logger.trace("Current size of heap: %d bytes", heapSize);
+ logger.trace("Max size of heap: %d bytes", heapMaxSize);
+ logger.trace("Free memory in heap: %d bytes", heapFreeSize);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new NotImplementedException(e);
+ }
+ }
+
+ private void openAndRegisterSuffixContainers(DN[] baseDNs) throws PersistitException, InitializationException,
+ ConfigException, DirectoryException
+ {
+ for (DN baseDN : baseDNs)
+ {
+ PersistitSuffixContainer sc = openSuffixContainer(baseDN, null);
+ registerSuffixContainer(baseDN, sc);
+ }
+ }
+
+ private PersistitSuffixContainer openSuffixContainer(DN baseDN, String name) throws PersistitException,
+ DirectoryException
+ {
+ String databasePrefix;
+ if (name == null || name.equals(""))
+ {
+ databasePrefix = baseDN.toNormalizedString();
+ }
+ else
+ {
+ databasePrefix = name;
+ }
+
+ final Volume volume = db.loadVolume(toVolumeName(baseDN));
+ final PersistitSuffixContainer suffixContainer =
+ new PersistitSuffixContainer(baseDN, databasePrefix, this, db, volume);
+ suffixContainer.open();
+ return suffixContainer;
+ }
+
+ private String toVolumeName(DN dn)
+ {
+ return dn.toString().replace(",", "_");
+ }
+
+ private void registerSuffixContainer(DN baseDN, PersistitSuffixContainer suffixContainer)
+ throws InitializationException
+ {
+ PersistitSuffixContainer sc = suffixContainers.get(baseDN);
+ if (sc != null)
+ {
+ // If an entry container for this baseDN is already opened we do not allow
+ // another to be opened.
+ throw new InitializationException(ERR_JEB_ENTRY_CONTAINER_ALREADY_REGISTERED.get(sc.getIndexPrefix(), baseDN));
+ }
+
+ suffixContainers.put(baseDN, suffixContainer);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close()
+ {
+ for (PersistitSuffixContainer sc : suffixContainers.values())
+ {
+ sc.close();
+ }
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long getEntryCount()
+ {
+ boolean couldDetermineAllCounts = true;
+ long result = 0;
+ for (SuffixContainer suffixContainer : getSuffixContainers().values())
+ {
+ final long suffixCount = suffixContainer.getEntryCount();
+ if (suffixCount != -1)
+ {
+ result += suffixCount;
+ }
+ else
+ {
+ couldDetermineAllCounts = false;
+ }
+ }
+ return couldDetermineAllCounts ? result : -1;
+ }
+
+ /**
+ * Return the suffix container holding a specific DN.
+ *
+ * @param entryDN
+ * The DN for which to return the suffix container.
+ * @return The suffix container holding the DN
+ */
+ PersistitSuffixContainer getSuffixContainer(DN entryDN)
+ {
+ PersistitSuffixContainer sc = null;
+ DN nodeDN = entryDN;
+
+ while (sc == null && nodeDN != null)
+ {
+ sc = suffixContainers.get(nodeDN);
+ if (sc == null)
+ {
+ nodeDN = nodeDN.getParentDNInSuffix();
+ }
+ }
+
+ return sc;
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java
new file mode 100644
index 0000000..31dd3d7
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/PersistitSuffixContainer.java
@@ -0,0 +1,308 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.persistit;
+
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.opends.server.api.EntryCache;
+import org.opends.server.backends.jeb.EntryID;
+import org.opends.server.backends.pluggable.SuffixContainer;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+
+import com.persistit.Exchange;
+import com.persistit.Persistit;
+import com.persistit.Volume;
+import com.persistit.exception.PersistitException;
+import com.sleepycat.je.DatabaseException;
+
+import static org.opends.messages.JebMessages.*;
+
+/**
+ * Persistit implementation of a {@link SuffixContainer}.
+ */
+class PersistitSuffixContainer implements SuffixContainer
+{
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ /** The baseDN handled by this suffix container. */
+ private final DN baseDN;
+ /**
+ * Prevents name clashes for common indexes (like id2entry) across multiple
+ * suffixes. For example when a root container contains multiple suffixes.
+ */
+ private final String indexPrefix;
+ private final PersistitRootContainer rootContainer;
+ private final Persistit db;
+ private final Volume volume;
+
+ private PersistitID2Entry id2entry;
+ private PersistitDN2ID dn2id;
+
+ /**
+ * Constructor for this class.
+ *
+ * @param baseDN
+ * The baseDN handled by this suffix container
+ * @param indexPrefix
+ * the prefix to use for indexes name
+ * @param rootContainer
+ * the persisit root container
+ * @param db
+ * the persisit database
+ * @param volume
+ * the volume where indexes will be created
+ */
+ PersistitSuffixContainer(DN baseDN, String indexPrefix, PersistitRootContainer rootContainer,
+ Persistit db, Volume volume)
+ {
+ this.baseDN = baseDN;
+ this.indexPrefix = indexPrefix;
+ this.rootContainer = rootContainer;
+ this.db = db;
+ this.volume = volume;
+ }
+
+ /**
+ * Opens the entryContainer for reading and writing.
+ *
+ * @throws DirectoryException
+ * If an error occurs while opening the suffix container.
+ */
+ void open() throws DirectoryException
+ {
+ id2entry = new PersistitID2Entry(this);
+ id2entry.open();
+ dn2id = new PersistitDN2ID(this);
+ dn2id.open();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void close()
+ {
+ dn2id.close();
+ id2entry.close();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public DN getBaseDN()
+ {
+ return baseDN;
+ }
+
+ /**
+ * Returns the index name prefix.
+ *
+ * @return the index name prefix
+ */
+ public String getIndexPrefix()
+ {
+ return indexPrefix;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public long getEntryCount()
+ {
+ // FIXME To be implemented
+ // JNR: I have not found a suitable API to return this value
+ return -1;
+ }
+
+ /**
+ * Returns the id2entry index.
+ *
+ * @return the id2entry index
+ */
+ public PersistitID2Entry getID2Entry()
+ {
+ return id2entry;
+ }
+
+ /**
+ * Creates a {@link Tree} for the fully qualified index name.
+ *
+ * @param fullyQualifiedIndexName
+ * The fully qualified index name
+ * @throws PersistitException
+ * if a database exception happens
+ */
+ void createTree(String fullyQualifiedIndexName) throws PersistitException
+ {
+ volume.getTree(fullyQualifiedIndexName, true);
+ }
+
+ /**
+ * Returns a new {@link Exchange} working on the index provided via its fully
+ * qualified name.
+ * <p>
+ * Note: exchanges obtained with this method must be released by calling
+ * {@link #releaseExchange(Exchange)}.
+ *
+ * @param fullyQualifiedIndexName
+ * The fully qualified index name
+ * @return the exchange
+ * @throws PersistitException
+ * if a database exception happens
+ */
+ final Exchange getExchange(String fullyQualifiedIndexName) throws PersistitException
+ {
+ return db.getExchange(volume, fullyQualifiedIndexName, false);
+ }
+
+ /**
+ * Returns the fully qualified index name for this simple index name.
+ * <p>
+ * e.g.
+ *
+ * <pre>
+ * PersistitSuffixContainer sc = ...; // initialize the suffix container
+ * assertEquals(sc.getIndexPrefix(), "dccom");
+ * assertEquals(sc.getFullyQualifiedIndexName("id2entry"), "dccom_id2entry");
+ * </pre>
+ *
+ * @param simpleIndexName
+ * the simple index name to convert to a fully qualified index name
+ * @return the fully qualified index name
+ */
+ public String getFullyQualifiedIndexName(String simpleIndexName)
+ {
+ return indexPrefix + "_" + simpleIndexName;
+ }
+
+ /**
+ * Releases the provided exchange.
+ *
+ * @param exchange
+ * the exchange to release
+ */
+ final void releaseExchange(Exchange exchange)
+ {
+ if (exchange != null)
+ {
+ db.releaseExchange(exchange);
+ }
+ }
+
+ /**
+ * Indicates whether an entry with the specified DN exists.
+ *
+ * @param entryDN
+ * The DN of the entry for which to determine existence.
+ * @return <CODE>true</CODE> if the specified entry exists, or
+ * <CODE>false</CODE> if it does not.
+ * @throws DirectoryException
+ * If a problem occurs while trying to make the determination.
+ */
+ public boolean entryExists(DN entryDN) throws DirectoryException
+ {
+ // Try the entry cache first.
+ EntryCache<?> entryCache = DirectoryServer.getEntryCache();
+ if (entryCache != null && entryCache.containsEntry(entryDN))
+ {
+ return true;
+ }
+
+ try
+ {
+ // Read the ID from dn2id.
+ EntryID id = dn2id.get(null, entryDN, null);
+ return id != null;
+ }
+ catch (DatabaseException e)
+ {
+ logger.traceException(e);
+ return false;
+ }
+ }
+
+ /**
+ * Retrieves and returns the entry associated to the provided DN.
+ *
+ * @param entryDN
+ * the DN of the entry to return
+ * @return the entry associated to the provided DN
+ * @throws DirectoryException
+ * if a directory exception happens
+ * @throws PersistitException
+ * if a database exception happens
+ */
+ Entry getEntry(DN entryDN) throws DirectoryException, PersistitException
+ {
+ EntryCache<?> entryCache = DirectoryServer.getEntryCache();
+
+ // Try the entry cache first.
+ Entry entry = null;
+ if (entryCache != null)
+ {
+ entry = entryCache.getEntry(entryDN);
+ }
+
+ if (entry == null)
+ {
+ // Read dn2id.
+ EntryID entryID = dn2id.get(null, entryDN, null);
+ if (entryID == null)
+ {
+ // The entryDN does not exist.
+
+ // Check for referral entries above the target entry.
+ // TODO JNR uncomment next line
+ // dn2uri.targetEntryReferrals(entryDN, null);
+
+ return null;
+ }
+
+ // Read id2entry.
+ entry = id2entry.get(null, entryID, null);
+ if (entry == null)
+ {
+ // The entryID does not exist.
+ throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), ERR_JEB_MISSING_ID2ENTRY_RECORD
+ .get(entryID));
+ }
+
+ // Put the entry in the cache making sure not to overwrite
+ // a newer copy that may have been inserted since the time
+ // we read the cache.
+ if (entryCache != null)
+ {
+ entryCache.putEntryIfAbsent(entry, rootContainer.getBackend(), entryID.longValue());
+ }
+ }
+
+ return entry;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return getClass().getSimpleName() + " baseDN=" + baseDN;
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java
new file mode 100644
index 0000000..00d74b5
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/persistit/package-info.java
@@ -0,0 +1,33 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+
+/**
+ * Contains the code for the Directory Server backend that uses Persistit
+ * as the repository for storing entry and index information.
+ */
+@org.opends.server.types.PublicAPI(
+ stability=org.opends.server.types.StabilityLevel.PRIVATE)
+package org.opends.server.backends.persistit;
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java
new file mode 100644
index 0000000..c83d4e9
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/KeyValueStore.java
@@ -0,0 +1,106 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.pluggable;
+
+import java.io.Closeable;
+
+import org.opends.server.types.DirectoryException;
+
+/**
+ * TODO JNR.
+ * @param <K> TODO JNR
+ * @param <V> TODO JNR
+ * @param <T> TODO JNR
+ * @param <M> TODO JNR
+ */
+public interface KeyValueStore<K, V, T, M> extends Closeable
+{
+
+ /**
+ * TODO JNR.
+ *
+ * @throws DirectoryException
+ * TODO JNR
+ */
+ void open() throws DirectoryException;
+
+ /**
+ * TODO JNR.
+ *
+ * @param txn
+ * TODO JNR
+ * @param key
+ * TODO JNR
+ * @param value
+ * TODO JNR
+ * @return TODO JNR
+ * @throws DirectoryException
+ * TODO JNR
+ */
+ boolean insert(T txn, K key, V value) throws DirectoryException;
+
+ /**
+ * TODO JNR.
+ *
+ * @param txn
+ * TODO JNR
+ * @param key
+ * TODO JNR
+ * @param value
+ * TODO JNR
+ * @return TODO JNR
+ * @throws DirectoryException
+ * TODO JNR
+ */
+ boolean put(T txn, K key, V value) throws DirectoryException;
+
+ /**
+ * TODO JNR.
+ *
+ * @param txn
+ * TODO JNR
+ * @param key
+ * TODO JNR
+ * @param mode
+ * TODO JNR
+ * @return TODO JNR
+ * @throws DirectoryException
+ * TODO JNR
+ */
+ V get(T txn, K key, M mode) throws DirectoryException;
+
+ /**
+ * TODO JNR.
+ *
+ * @param txn
+ * TODO JNR
+ * @param key
+ * TODO JNR
+ * @return TODO JNR
+ * @throws DirectoryException
+ * TODO JNR
+ */
+ boolean remove(T txn, K key) throws DirectoryException;
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java
new file mode 100644
index 0000000..cb18210
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/NotImplementedException.java
@@ -0,0 +1,51 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ * Copyright 2014 ForgeRock AS
+ */
+package org.opends.server.backends.pluggable;
+
+/**
+ * Class that helps figuring out where code is not implemented. This class
+ * should only be used during the implementation of pluggable storage backends.
+ */
+public class NotImplementedException extends RuntimeException
+{
+ private static final long serialVersionUID = 6647576563755499711L;
+
+ /** Default constructor. */
+ public NotImplementedException()
+ {
+ super("Code is not implemented");
+ }
+
+ /**
+ * Default constructor.
+ *
+ * @param cause
+ * the cause
+ */
+ public NotImplementedException(Throwable cause)
+ {
+ super("Code is not implemented", cause);
+ }
+}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java
index d523b40..70a3e56 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/PluggableStorageBackend.java
@@ -25,15 +25,20 @@
*/
package org.opends.server.backends.pluggable;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Set;
+import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.util.Reject;
-import org.opends.server.admin.Configuration;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.BackendCfg;
import org.opends.server.api.Backend;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -45,6 +50,7 @@
import org.opends.server.types.BackupConfig;
import org.opends.server.types.BackupDirectory;
import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
@@ -64,29 +70,65 @@
* @param <C>
* the type of the BackendCfg for the current backend
*/
-public abstract class PluggableStorageBackend<C extends Configuration> extends Backend<C>
+public abstract class PluggableStorageBackend<C extends BackendCfg>
+ extends Backend<C>
+ implements ConfigurationChangeListener<C>
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+ /** The configuration object. */
+ protected C cfg;
/** The set of base DNs for this backend. */
private DN[] baseDNs;
/** {@inheritDoc} */
@Override
- public void configureBackend(final Configuration cfg) throws ConfigException
+ public void configureBackend(final C cfg) throws ConfigException
{
Reject.ifNull(cfg);
+
+ this.cfg = cfg;
+ baseDNs = this.cfg.getBaseDN().toArray(new DN[0]);
}
/** {@inheritDoc} */
@Override
- public void initializeBackend() throws InitializationException
+ public boolean isConfigurationChangeAcceptable(C cfg, List<LocalizableMessage> unacceptableReasons)
{
- for (DN baseDN : this.baseDNs)
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public ConfigChangeResult applyConfigurationChange(C cfg)
+ {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void initializeBackend() throws ConfigException, InitializationException
+ {
+ registerBaseDNs(cfg.getBaseDN());
+ }
+
+ /**
+ * Associates the current backend with the provided baseDNs in the directory
+ * server.
+ *
+ * @param baseDNs
+ * the base DNs to be associated with this backend
+ * @throws InitializationException
+ * If a problem occurs during initialization that is not related to
+ * the server configuration.
+ */
+ public void registerBaseDNs(Collection<DN> baseDNs) throws InitializationException
+ {
+ for (DN baseDN : baseDNs)
{
try
{
- DirectoryServer.registerBaseDN(baseDN, this, true);
+ DirectoryServer.registerBaseDN(baseDN, this, false);
}
catch (final Exception e)
{
@@ -101,7 +143,19 @@
{
super.finalizeBackend();
- for (DN baseDN : this.baseDNs)
+ deregisterBaseDNs(cfg.getBaseDN());
+ }
+
+ /**
+ * Dissociates the current backend from the provided baseDNs in the directory
+ * server.
+ *
+ * @param baseDNs
+ * the base DNs to dissociate from this backend
+ */
+ public void deregisterBaseDNs(Collection<DN> baseDNs)
+ {
+ for (DN baseDN : baseDNs)
{
try
{
@@ -125,7 +179,7 @@
@Override
public void preloadEntryCache() throws UnsupportedOperationException
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -139,7 +193,7 @@
@Override
public boolean isIndexed(final AttributeType attributeType, final IndexType indexType)
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -151,7 +205,7 @@
throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID()));
}
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -170,7 +224,7 @@
@Override
public long numSubordinates(final DN entryDN, final boolean subtree) throws DirectoryException
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -210,9 +264,9 @@
/** {@inheritDoc} */
@Override
- public void search(final SearchOperation searchOperation) throws DirectoryException
+ public void search(final SearchOperation searchOperation) throws DirectoryException, CanceledOperationException
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -263,14 +317,14 @@
@Override
public boolean supportsBackup()
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@Override
public boolean supportsBackup(BackupConfig backupConfig, StringBuilder unsupportedReason)
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -293,7 +347,7 @@
@Override
public boolean supportsRestore()
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
/** {@inheritDoc} */
@@ -308,7 +362,13 @@
@Override
public long getEntryCount()
{
- throw new RuntimeException("Not implemented");
+ throw new NotImplementedException();
}
+ /** {@inheritDoc} */
+ @Override
+ public String toString()
+ {
+ return getClass().getSimpleName() + " baseDNs=" + Arrays.toString(baseDNs);
+ }
}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
index f5c96a9..e351e95 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/RootContainer.java
@@ -24,6 +24,7 @@
*/
package org.opends.server.backends.pluggable;
+import java.io.Closeable;
import java.util.Map;
import org.opends.server.types.DN;
@@ -43,7 +44,7 @@
* @param <T>
* the type of the suffix containers
*/
-public interface RootContainer<T extends SuffixContainer>
+public interface RootContainer<T extends SuffixContainer> extends Closeable
{
/**
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
index a7a1726..a90682a 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/SuffixContainer.java
@@ -24,6 +24,8 @@
*/
package org.opends.server.backends.pluggable;
+import java.io.Closeable;
+
import org.opends.server.types.DN;
/**
@@ -32,10 +34,39 @@
* stores a.k.a indexes. It stores entries in these key-values stores and
* maintain the indexes all in sync on updates.
*/
-public interface SuffixContainer
+public interface SuffixContainer extends Closeable
{
/**
+ * The name of the index associating normalized DNs to ids. LDAP DNs uniquely
+ * identify entries.
+ */
+ String DN2ID_INDEX_NAME = "dn2id";
+ /**
+ * The name of the index associating entry ids to entries. Entry ids are
+ * monotonically increasing unique longs and entries are serialized versions
+ * of LDAP entries.
+ */
+ String ID2ENTRY_INDEX_NAME = "id2entry";
+ /**
+ * The name of the index associating an entry id to the entry id set of all
+ * its children.
+ */
+ String ID2CHILDREN_INDEX_NAME = "id2children";
+ /**
+ * The name of the index associating an entry id to the entry id set of all
+ * its subordinates.
+ */
+ String ID2SUBTREE_INDEX_NAME = "id2subtree";
+ /** The name of the index associating normalized DNs to normalized URIs. */
+ String REFERRAL_INDEX_NAME = "referral";
+ /**
+ * The name of the index which associates indexes with their trust state, i.e.
+ * does the index needs to be rebuilt ?
+ */
+ String STATE_INDEX_NAME = "state";
+
+ /**
* Returns the baseDN that this suffix container is responsible for.
*
* @return the baseDN that this suffix container is responsible for
--
Gitblit v1.10.0