From 5031429bf032af5e3d8797210cc47b402ef831d6 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 16 Dec 2014 23:48:24 +0000
Subject: [PATCH] OPENDJ-1602 (CR-5566) New pluggable storage based backend
---
opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java | 457 ++++++++++++++++++++++----------------------------------
1 files changed, 181 insertions(+), 276 deletions(-)
diff --git a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
index 35716bd..8ad27f7 100644
--- a/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
+++ b/opendj3-server-dev/src/server/org/opends/server/backends/pluggable/EntryContainer.java
@@ -27,7 +27,13 @@
*/
package org.opends.server.backends.pluggable;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -60,13 +66,38 @@
import org.opends.server.backends.pluggable.BackendImpl.TreeName;
import org.opends.server.backends.pluggable.BackendImpl.WriteOperation;
import org.opends.server.backends.pluggable.BackendImpl.WriteableStorage;
-import org.opends.server.backends.pluggable.SuffixContainer;
-import org.opends.server.controls.*;
-import org.opends.server.core.*;
-import org.opends.server.types.*;
+import org.opends.server.controls.PagedResultsControl;
+import org.opends.server.controls.ServerSideSortRequestControl;
+import org.opends.server.controls.ServerSideSortResponseControl;
+import org.opends.server.controls.SubtreeDeleteControl;
+import org.opends.server.controls.VLVRequestControl;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.ModifyOperation;
+import org.opends.server.core.SearchOperation;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.CanceledOperationException;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.Control;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.Operation;
+import org.opends.server.types.Privilege;
+import org.opends.server.types.RDN;
+import org.opends.server.types.SearchFilter;
+import org.opends.server.types.SortKey;
+import org.opends.server.types.VirtualAttributeRule;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
+import com.sleepycat.je.TransactionConfig;
+
import static org.opends.messages.JebMessages.*;
import static org.opends.server.backends.pluggable.JebFormat.*;
import static org.opends.server.core.DirectoryServer.*;
@@ -156,6 +187,8 @@
{
try
{
+ // FIXME this should be a read operation, but I cannot change it
+ // because of AttributeIndex ctor.
storage.write(new WriteOperation()
{
@Override
@@ -216,30 +249,35 @@
/** {@inheritDoc} */
@Override
- public ConfigChangeResult applyConfigurationDelete(LocalDBIndexCfg cfg)
+ public ConfigChangeResult applyConfigurationDelete(final LocalDBIndexCfg cfg)
{
- boolean adminActionRequired = false;
- ArrayList<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
+ final ConfigChangeResult ccr = new ConfigChangeResult();
exclusiveLock.lock();
try
{
- AttributeIndex index = attrIndexMap.get(cfg.getAttribute());
- deleteAttributeIndex(index);
- attrIndexMap.remove(cfg.getAttribute());
+ storage.write(new WriteOperation()
+ {
+ @Override
+ public void run(WriteableStorage txn) throws Exception
+ {
+ AttributeIndex index = attrIndexMap.get(cfg.getAttribute());
+ deleteAttributeIndex(txn, index, ccr);
+ attrIndexMap.remove(cfg.getAttribute());
+ }
+ });
}
- catch(StorageRuntimeException de)
+ catch (Exception de)
{
- messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
- return new ConfigChangeResult(
- DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages);
+ ccr.setResultCode(getServerErrorResultCode());
+ ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
}
finally
{
exclusiveLock.unlock();
}
- return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+ return ccr;
}
}
@@ -354,31 +392,33 @@
/** {@inheritDoc} */
@Override
- public ConfigChangeResult applyConfigurationDelete(LocalDBVLVIndexCfg cfg)
+ public ConfigChangeResult applyConfigurationDelete(final LocalDBVLVIndexCfg cfg)
{
- boolean adminActionRequired = false;
- List<LocalizableMessage> messages = new ArrayList<LocalizableMessage>();
-
+ final ConfigChangeResult ccr = new ConfigChangeResult();
exclusiveLock.lock();
try
{
- VLVIndex vlvIndex =
- vlvIndexMap.get(cfg.getName().toLowerCase());
- deleteDatabase(vlvIndex);
- vlvIndexMap.remove(cfg.getName());
+ storage.write(new WriteOperation()
+ {
+ @Override
+ public void run(WriteableStorage txn) throws Exception
+ {
+ VLVIndex vlvIndex = vlvIndexMap.get(cfg.getName().toLowerCase());
+ deleteDatabase(txn, vlvIndex);
+ vlvIndexMap.remove(cfg.getName());
+ }
+ });
}
- catch(StorageRuntimeException de)
+ catch (Exception e)
{
- messages.add(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(de)));
- return new ConfigChangeResult(
- DirectoryServer.getServerErrorResultCode(), adminActionRequired, messages);
+ ccr.setResultCode(getServerErrorResultCode());
+ ccr.addMessage(LocalizableMessage.raw(StaticUtils.stackTraceToSingleLineString(e)));
}
finally
{
exclusiveLock.unlock();
}
-
- return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired, messages);
+ return ccr;
}
}
@@ -403,7 +443,7 @@
* @param rootContainer The root container this entry container is in.
* @throws ConfigException if a configuration related error occurs.
*/
- public EntryContainer(DN baseDN, String databasePrefix, Backend<?> backend,
+ public EntryContainer(DN baseDN, TreeName databasePrefix, Backend<?> backend,
LocalDBBackendCfg config, Storage env, RootContainer rootContainer)
throws ConfigException
{
@@ -412,8 +452,7 @@
this.config = config;
this.storage = env;
this.rootContainer = rootContainer;
-
- this.databasePrefix = preparePrefix(databasePrefix);
+ this.databasePrefix = databasePrefix;
config.addLocalDBChangeListener(this);
@@ -1316,14 +1355,12 @@
boolean manageDsaIT = isManageDsaITOperation(searchOperation);
boolean continueSearch = true;
- // Set the starting value.
- EntryID begin = null;
if (pageRequest != null && pageRequest.getCookie().length() != 0)
{
// The cookie contains the ID of the next entry to be returned.
try
{
- begin = new EntryID(pageRequest.getCookie());
+ new EntryID(pageRequest.getCookie());
}
catch (Exception e)
{
@@ -1354,10 +1391,8 @@
// Iterate through the index candidates.
if (continueSearch)
{
- for (Iterator<EntryID> it = entryIDList.iterator(begin); it.hasNext();)
+ for (EntryID id : entryIDList)
{
- final EntryID id = it.next();
-
Entry entry;
try
{
@@ -1556,7 +1591,7 @@
EntryID nodeID = dn2id.get(txn, dn, false);
if (nodeID == null)
{
- throw new JebException(ERR_JEB_MISSING_DN2ID_RECORD.get(dn));
+ throw new StorageRuntimeException(ERR_JEB_MISSING_DN2ID_RECORD.get(dn).toString());
}
// Insert into id2subtree for this node.
@@ -1816,7 +1851,7 @@
DN targetDN,
ByteSequence leafDNKey,
EntryID leafID)
- throws StorageRuntimeException, DirectoryException, JebException
+ throws StorageRuntimeException, DirectoryException
{
if(leafID == null || leafDNKey == null)
{
@@ -1884,7 +1919,7 @@
EntryID parentID = dn2id.get(txn, parentDN, false);
if (parentID == null)
{
- throw new JebException(ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN));
+ throw new StorageRuntimeException(ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN).toString());
}
ByteString parentIDBytes = parentID.toByteString();
@@ -2747,14 +2782,12 @@
* @return The number of entries stored in this entry container.
* @throws StorageRuntimeException If an error occurs in the JE database.
*/
- @Override
- public long getEntryCount() throws StorageRuntimeException
+ public long getEntryCount(ReadableStorage txn) throws StorageRuntimeException
{
- EntryID entryID = dn2id.get(null, baseDN, false);
+ final EntryID entryID = dn2id.get(txn, baseDN, false);
if (entryID != null)
{
- EntryIDSet entryIDSet = id2subtree.readKey(entryID.toByteString(), null);
-
+ final EntryIDSet entryIDSet = id2subtree.readKey(entryID.toByteString(), txn);
long count = entryIDSet.size();
if(count != Long.MAX_VALUE)
{
@@ -2764,7 +2797,7 @@
else
{
// The count is not maintained. Fall back to the slow method
- return id2entry.getRecordCount();
+ return id2entry.getRecordCount(txn);
}
}
else
@@ -2910,36 +2943,14 @@
* @throws StorageRuntimeException If an error occurs while removing the entry
* container.
*/
- public void delete() throws StorageRuntimeException
+ public void delete(WriteableStorage txn) throws StorageRuntimeException
{
List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
listDatabases(databases);
- if(storage.getConfig().getTransactional())
+ for (DatabaseContainer db : databases)
{
- Transaction txn = beginTransaction();
-
- try
- {
- for(DatabaseContainer db : databases)
- {
- storage.removeDatabase(txn, db.getName());
- }
-
- transactionCommit(txn);
- }
- catch(StorageRuntimeException de)
- {
- transactionAbort(txn);
- throw de;
- }
- }
- else
- {
- for(DatabaseContainer db : databases)
- {
- storage.removeDatabase(null, db.getName());
- }
+ storage.removeDatabase(txn, db.getName());
}
}
@@ -2950,8 +2961,7 @@
* @throws StorageRuntimeException If an error occurs while attempting to delete the
* database.
*/
- public void deleteDatabase(DatabaseContainer database)
- throws StorageRuntimeException
+ public void deleteDatabase(WriteableStorage txn, DatabaseContainer database) throws StorageRuntimeException
{
if(database == state)
{
@@ -2960,31 +2970,10 @@
}
database.close();
- if(storage.getConfig().getTransactional())
+ storage.removeDatabase(txn, database.getName());
+ if(database instanceof Index)
{
- Transaction txn = beginTransaction();
- try
- {
- storage.removeDatabase(txn, database.getName());
- if(database instanceof Index)
- {
- state.removeIndexTrustState(txn, database);
- }
- transactionCommit(txn);
- }
- catch(StorageRuntimeException de)
- {
- transactionAbort(txn);
- throw de;
- }
- }
- else
- {
- storage.removeDatabase(null, database.getName());
- if(database instanceof Index)
- {
- state.removeIndexTrustState(null, database);
- }
+ state.removeIndexTrustState(txn, database);
}
}
@@ -2995,31 +2984,14 @@
* @throws StorageRuntimeException If an JE database error occurs while attempting
* to delete the index.
*/
- private void deleteAttributeIndex(AttributeIndex attributeIndex)
+ private void deleteAttributeIndex(WriteableStorage txn, AttributeIndex attributeIndex, ConfigChangeResult ccr)
throws StorageRuntimeException
{
attributeIndex.close();
- Transaction txn = storage.getConfig().getTransactional()
- ? beginTransaction() : null;
- try
+ for (Index index : attributeIndex.getAllIndexes())
{
- for (Index index : attributeIndex.getAllIndexes())
- {
- storage.removeDatabase(txn, index.getName());
- state.removeIndexTrustState(txn, index);
- }
- if (txn != null)
- {
- transactionCommit(txn);
- }
- }
- catch(StorageRuntimeException de)
- {
- if (txn != null)
- {
- transactionAbort(txn);
- }
- throw de;
+ storage.removeDatabase(txn, index.getName());
+ state.removeIndexTrustState(txn, index);
}
}
@@ -3041,16 +3013,13 @@
*
* @param newDatabasePrefix The new database prefix to use.
* @throws StorageRuntimeException If an error occurs in the JE database.
- * @throws JebException If an error occurs in the JE backend.
*/
- public void setDatabasePrefix(String newDatabasePrefix)
- throws StorageRuntimeException, JebException
-
+ public void setDatabasePrefix(TreeName newDatabasePrefix) throws StorageRuntimeException, StorageRuntimeException
{
- List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
+ final List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
listDatabases(databases);
- TreeName newDbPrefix = preparePrefix(newDatabasePrefix);
+ final TreeName newDbPrefix = newDatabasePrefix;
// close the containers.
for(DatabaseContainer db : databases)
@@ -3060,11 +3029,10 @@
try
{
- if(storage.getConfig().getTransactional())
+ storage.write(new WriteOperation()
{
- //Rename under transaction
- Transaction txn = beginTransaction();
- try
+ @Override
+ public void run(WriteableStorage txn) throws Exception
{
for(DatabaseContainer db : databases)
{
@@ -3072,52 +3040,60 @@
String newName = oldName.replace(databasePrefix, newDbPrefix);
storage.renameDatabase(txn, oldName, newName);
}
-
- transactionCommit(txn);
-
- for(DatabaseContainer db : databases)
+ }
+ });
+ storage.write(new WriteOperation()
+ {
+ @Override
+ public void run(WriteableStorage txn) throws Exception
+ {
+ for (DatabaseContainer db : databases)
{
TreeName oldName = db.getName();
String newName = oldName.replace(databasePrefix, newDbPrefix);
db.setName(newName);
}
- // Update the prefix.
- this.databasePrefix = newDbPrefix;
+ databasePrefix = newDbPrefix;
}
- catch(Exception e)
- {
- transactionAbort(txn);
-
- String msg = e.getMessage();
- if (msg == null)
- {
- msg = stackTraceToSingleLineString(e);
- }
- LocalizableMessage message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg);
- throw new JebException(message, e);
- }
- }
- else
+ });
+ }
+ catch (Exception e)
+ {
+ String msg = e.getMessage();
+ if (msg == null)
{
- for(DatabaseContainer db : databases)
- {
- TreeName oldName = db.getName();
- String newName = oldName.replace(databasePrefix, newDbPrefix);
- storage.renameDatabase(txn, oldName, newName);
- db.setName(newName);
- }
-
- // Update the prefix.
- this.databasePrefix = newDbPrefix;
+ msg = stackTraceToSingleLineString(e);
}
+ LocalizableMessage message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg);
+ throw new StorageRuntimeException(message.toString(), e);
}
finally
{
- // Open the containers backup.
- for(DatabaseContainer db : databases)
+ try
{
- db.open(txn);
+ storage.write(new WriteOperation()
+ {
+ @Override
+ public void run(WriteableStorage txn) throws Exception
+ {
+ // Open the containers backup.
+ for(DatabaseContainer db : databases)
+ {
+ db.open(txn);
+ }
+ }
+ });
+ }
+ catch (Exception e)
+ {
+ String msg = e.getMessage();
+ if (msg == null)
+ {
+ msg = stackTraceToSingleLineString(e);
+ }
+ LocalizableMessage message = ERR_JEB_UNCHECKED_EXCEPTION.get(msg);
+ throw new StorageRuntimeException(message.toString(), e);
}
}
}
@@ -3232,19 +3208,6 @@
}
/**
- * Get the environment config of the JE environment used in this entry
- * container.
- *
- * @return The environment config of the JE environment.
- * @throws StorageRuntimeException If an error occurs while retrieving the
- * configuration object.
- */
- public EnvironmentConfig getEnvironmentConfig() throws StorageRuntimeException
- {
- return storage.getConfig();
- }
-
- /**
* Clear the contents of this entry container.
*
* @return The number of records deleted.
@@ -3253,7 +3216,28 @@
*/
public long clear() throws StorageRuntimeException
{
- List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
+ final AtomicLong count = new AtomicLong();
+ try
+ {
+ storage.write(new WriteOperation()
+ {
+ @Override
+ public void run(WriteableStorage txn) throws Exception
+ {
+ count.set(clear0(txn));
+ }
+ });
+ return count.get();
+ }
+ catch (Exception e)
+ {
+ throw new StorageRuntimeException(e);
+ }
+ }
+
+ private long clear0(WriteableStorage txn) throws StorageRuntimeException
+ {
+ final List<DatabaseContainer> databases = new ArrayList<DatabaseContainer>();
listDatabases(databases);
long count = 0;
@@ -3263,31 +3247,9 @@
}
try
{
- if(storage.getConfig().getTransactional())
+ for (DatabaseContainer db : databases)
{
- Transaction txn = beginTransaction();
-
- try
- {
- for(DatabaseContainer db : databases)
- {
- count += storage.truncateDatabase(txn, db.getName(), true);
- }
-
- transactionCommit(txn);
- }
- catch(StorageRuntimeException de)
- {
- transactionAbort(txn);
- throw de;
- }
- }
- else
- {
- for(DatabaseContainer db : databases)
- {
- count += storage.truncateDatabase(null, db.getName(), true);
- }
+ count += storage.truncateDatabase(txn, db.getName(), true);
}
}
finally
@@ -3297,39 +3259,11 @@
db.open(txn);
}
- Transaction txn = null;
- try
+ for (DatabaseContainer db : databases)
{
- if(storage.getConfig().getTransactional()) {
- txn = beginTransaction();
- }
- for(DatabaseContainer db : databases)
+ if (db instanceof Index)
{
- if (db instanceof Index)
- {
- Index index = (Index)db;
- index.setTrusted(txn, true);
- }
- }
- if(storage.getConfig().getTransactional()) {
- transactionCommit(txn);
- }
- }
- catch(Exception de)
- {
- logger.traceException(de);
-
- // This is mainly used during the unit tests, so it's not essential.
- try
- {
- if (txn != null)
- {
- transactionAbort(txn);
- }
- }
- catch (Exception e)
- {
- logger.traceException(de);
+ ((Index) db).setTrusted(txn, true);
}
}
}
@@ -3343,34 +3277,30 @@
* @param database The database to clear.
* @throws StorageRuntimeException if a JE database error occurs.
*/
- public void clearDatabase(DatabaseContainer database)
- throws StorageRuntimeException
+ public void clearDatabase(final DatabaseContainer database) throws StorageRuntimeException
{
database.close();
try
{
- if(storage.getConfig().getTransactional())
+ storage.write(new WriteOperation()
{
- Transaction txn = beginTransaction();
- try
+ @Override
+ public void run(WriteableStorage txn) throws Exception
{
- storage.removeDatabase(txn, database.getName());
- transactionCommit(txn);
+ try
+ {
+ storage.removeDatabase(txn, database.getName());
+ }
+ finally
+ {
+ database.open(txn);
+ }
}
- catch(StorageRuntimeException de)
- {
- transactionAbort(txn);
- throw de;
- }
- }
- else
- {
- storage.removeDatabase(null, database.getName());
- }
+ });
}
- finally
+ catch (Exception e)
{
- database.open(txn);
+ throw new StorageRuntimeException(e);
}
if(logger.isTraceEnabled())
{
@@ -3507,31 +3437,6 @@
return baseEntry;
}
-
- /**
- * Transform a database prefix string to one usable by the DB.
- * @param databasePrefix the database prefix
- * @return a new string when non letter or digit characters
- * have been replaced with underscore
- */
- private TreeName preparePrefix(String databasePrefix)
- {
- StringBuilder builder = new StringBuilder(databasePrefix.length());
- for (int i = 0; i < databasePrefix.length(); i++)
- {
- char ch = databasePrefix.charAt(i);
- if (Character.isLetterOrDigit(ch))
- {
- builder.append(ch);
- }
- else
- {
- builder.append('_');
- }
- }
- return TreeName.of(builder.toString());
- }
-
/** Get the exclusive lock. */
public void lock() {
exclusiveLock.lock();
--
Gitblit v1.10.0