From 05875933ae6929bc8e53f366ce116f2fc431fd46 Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Fri, 27 Jul 2007 21:06:35 +0000
Subject: [PATCH] These set of changes implement VLV and filter capability to OpenDS:
---
opends/src/server/org/opends/server/backends/jeb/EntryContainer.java | 536 ++++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 378 insertions(+), 158 deletions(-)
diff --git a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
index 69fb221..8113b85 100644
--- a/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
+++ b/opends/src/server/org/opends/server/backends/jeb/EntryContainer.java
@@ -59,6 +59,7 @@
import static org.opends.server.util.ServerConstants.*;
import org.opends.server.admin.std.server.JEBackendCfg;
import org.opends.server.admin.std.server.JEIndexCfg;
+import org.opends.server.admin.std.server.VLVJEIndexCfg;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.server.ConfigurationAddListener;
import org.opends.server.admin.server.ConfigurationDeleteListener;
@@ -70,9 +71,7 @@
* the guts of the backend API methods for LDAP operations.
*/
public class EntryContainer
- implements ConfigurationChangeListener<JEBackendCfg>,
- ConfigurationAddListener<JEIndexCfg>,
- ConfigurationDeleteListener<JEIndexCfg>
+ implements ConfigurationChangeListener<JEBackendCfg>
{
/**
* The tracer object for the debug logger.
@@ -116,6 +115,16 @@
public static final String ATTR_DEBUG_SEARCH_INDEX = "debugsearchindex";
/**
+ * The attribute index configuration manager.
+ */
+ public AttributeJEIndexCfgManager attributeJEIndexCfgManager;
+
+ /**
+ * The vlv index configuration manager.
+ */
+ public VLVJEIndexCfgManager vlvJEIndexCfgManager;
+
+ /**
* The backend to which this entry entryContainer belongs.
*/
private Backend backend;
@@ -176,6 +185,11 @@
private HashMap<AttributeType, AttributeIndex> attrIndexMap;
/**
+ * The set of VLV indexes.
+ */
+ private HashMap<String, VLVIndex> vlvIndexMap;
+
+ /**
* Cached value from config so they don't have to be retrieved per operation.
*/
private int deadlockRetryLimit;
@@ -188,6 +202,196 @@
private String databasePrefix;
/**
+ * This class is responsible for managing the configuraiton for attribute
+ * indexes used within this entry container.
+ */
+ public class AttributeJEIndexCfgManager implements
+ ConfigurationAddListener<JEIndexCfg>,
+ ConfigurationDeleteListener<JEIndexCfg>
+ {
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(JEIndexCfg cfg,
+ List<String> unacceptableReasons)
+ {
+ // TODO: validate more before returning true?
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(JEIndexCfg cfg)
+ {
+ ConfigChangeResult ccr;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ try
+ {
+ AttributeIndex index =
+ new AttributeIndex(cfg, state, env, EntryContainer.this);
+ index.open();
+ attrIndexMap.put(cfg.getIndexAttribute(), index);
+ }
+ catch(Exception e)
+ {
+ messages.add(StaticUtils.stackTraceToSingleLineString(e));
+ ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
+ adminActionRequired,
+ messages);
+ return ccr;
+ }
+
+ adminActionRequired = true;
+ int msgID = MSGID_JEB_INDEX_ADD_REQUIRES_REBUILD;
+ messages.add(getMessage(msgID, cfg.getIndexAttribute().getNameOrOID()));
+ return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
+ messages);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized boolean isConfigurationDeleteAcceptable(
+ JEIndexCfg cfg, List<String> unacceptableReasons)
+ {
+ // TODO: validate more before returning true?
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(JEIndexCfg cfg)
+ {
+ ConfigChangeResult ccr;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ exclusiveLock.lock();
+ try
+ {
+ AttributeIndex index = attrIndexMap.get(cfg.getIndexAttribute());
+ deleteAttributeIndex(index);
+ attrIndexMap.remove(cfg.getIndexAttribute());
+ }
+ catch(DatabaseException de)
+ {
+ messages.add(StaticUtils.stackTraceToSingleLineString(de));
+ ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
+ adminActionRequired,
+ messages);
+ return ccr;
+ }
+ finally
+ {
+ exclusiveLock.unlock();
+ }
+
+ return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
+ messages);
+ }
+ }
+
+ /**
+ * This class is responsible for managing the configuraiton for VLV indexes
+ * used within this entry container.
+ */
+ public class VLVJEIndexCfgManager implements
+ ConfigurationAddListener<VLVJEIndexCfg>,
+ ConfigurationDeleteListener<VLVJEIndexCfg>
+ {
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(
+ VLVJEIndexCfg cfg, List<String> unacceptableReasons)
+ {
+ // TODO: validate more before returning true?
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(VLVJEIndexCfg cfg)
+ {
+ ConfigChangeResult ccr;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ try
+ {
+ VLVIndex vlvIndex = new VLVIndex(cfg, state, env, EntryContainer.this);
+ vlvIndex.open();
+ vlvIndexMap.put(cfg.getVLVIndexName().toLowerCase(), vlvIndex);
+ }
+ catch(Exception e)
+ {
+ messages.add(StaticUtils.stackTraceToSingleLineString(e));
+ ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
+ adminActionRequired,
+ messages);
+ return ccr;
+ }
+
+ adminActionRequired = true;
+ int msgID = MSGID_JEB_INDEX_ADD_REQUIRES_REBUILD;
+ messages.add(getMessage(msgID, cfg.getVLVIndexName()));
+ return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
+ messages);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(VLVJEIndexCfg cfg,
+ List<String> unacceptableReasons)
+ {
+ // TODO: validate more before returning true?
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationDelete(VLVJEIndexCfg cfg)
+ {
+ ConfigChangeResult ccr;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ exclusiveLock.lock();
+ try
+ {
+ VLVIndex vlvIndex =
+ vlvIndexMap.get(cfg.getVLVIndexName().toLowerCase());
+ vlvIndex.close();
+ deleteDatabase(vlvIndex);
+ vlvIndexMap.remove(cfg.getVLVIndexName());
+ }
+ catch(DatabaseException de)
+ {
+ messages.add(StaticUtils.stackTraceToSingleLineString(de));
+ ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
+ adminActionRequired,
+ messages);
+ return ccr;
+ }
+ finally
+ {
+ exclusiveLock.unlock();
+ }
+
+ return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
+ messages);
+ }
+
+ }
+
+ /**
* A read write lock to handle schema changes and bulk changes.
*/
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
@@ -243,9 +447,20 @@
// Instantiate the attribute indexes.
attrIndexMap = new HashMap<AttributeType, AttributeIndex>();
+ // Instantiate the VLV indexes.
+ vlvIndexMap = new HashMap<String, VLVIndex>();
+
config.addJEChangeListener(this);
- config.addJEIndexAddListener(this);
- config.addJEIndexDeleteListener(this);
+
+ attributeJEIndexCfgManager =
+ new AttributeJEIndexCfgManager();
+ config.addJEIndexAddListener(attributeJEIndexCfgManager);
+ config.addJEIndexDeleteListener(attributeJEIndexCfgManager);
+
+ vlvJEIndexCfgManager =
+ new VLVJEIndexCfgManager();
+ config.addVLVJEIndexAddListener(vlvJEIndexCfgManager);
+ config.addVLVJEIndexDeleteListener(vlvJEIndexCfgManager);
}
/**
@@ -298,6 +513,15 @@
index.open();
attrIndexMap.put(indexCfg.getIndexAttribute(), index);
}
+
+ for(String idx : config.listVLVJEIndexes())
+ {
+ VLVJEIndexCfg vlvIndexCfg = config.getVLVJEIndex(idx);
+
+ VLVIndex vlvIndex = new VLVIndex(vlvIndexCfg, state, env, this);
+ vlvIndex.open();
+ vlvIndexMap.put(vlvIndexCfg.getVLVIndexName().toLowerCase(), vlvIndex);
+ }
}
catch (DatabaseException de)
{
@@ -326,8 +550,10 @@
}
config.removeJEChangeListener(this);
- config.removeJEIndexAddListener(this);
- config.removeJEIndexDeleteListener(this);
+ config.removeJEIndexAddListener(attributeJEIndexCfgManager);
+ config.removeJEIndexDeleteListener(attributeJEIndexCfgManager);
+ config.removeVLVJEIndexDeleteListener(vlvJEIndexCfgManager);
+ config.removeVLVJEIndexDeleteListener(vlvJEIndexCfgManager);
}
/**
@@ -397,6 +623,17 @@
}
/**
+ * Look for an VLV index for the given index name.
+ *
+ * @param vlvIndexName The vlv index name for which an vlv index is needed.
+ * @return The VLV index or null if there is none with that name.
+ */
+ public VLVIndex getVLVIndex(String vlvIndexName)
+ {
+ return vlvIndexMap.get(vlvIndexName);
+ }
+
+ /**
* Retrieve all attribute indexes.
*
* @return All attribute indexes defined in this entry container.
@@ -406,6 +643,15 @@
return attrIndexMap.values();
}
+ /**
+ * Retrieve all VLV indexes.
+ *
+ * @return The collection of VLV indexes defined in this entry container.
+ */
+ public Collection<VLVIndex> getVLVIndexes()
+ {
+ return vlvIndexMap.values();
+ }
/**
* Determine the highest entryID in the entryContainer.
@@ -448,9 +694,10 @@
* If a problem occurs while processing the
* search.
* @throws DatabaseException If an error occurs in the JE database.
+ * @throws JebException If an error occurs in the JE database.
*/
public void search(SearchOperation searchOperation)
- throws DirectoryException, DatabaseException
+ throws DirectoryException, DatabaseException, JebException
{
DN baseDN = searchOperation.getBaseDN();
SearchScope searchScope = searchOperation.getScope();
@@ -617,54 +864,115 @@
debugBuffer = new StringBuilder();
}
- // Create an index filter to get the search result candidate entries.
- IndexFilter indexFilter =
- new IndexFilter(this, searchOperation, debugBuffer);
-
- // Evaluate the filter against the attribute indexes.
- EntryIDSet entryIDList = indexFilter.evaluate();
-
- // Evaluate the search scope against the id2children and id2subtree indexes.
+ EntryIDSet entryIDList = null;
boolean candidatesAreInScope = false;
- if (entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
+ if(sortRequest != null)
{
- // Read the ID from dn2id.
- EntryID baseID = dn2id.get(null, baseDN);
- if (baseID == null)
+ for(VLVIndex vlvIndex : vlvIndexMap.values())
{
- int messageID = MSGID_JEB_SEARCH_NO_SUCH_OBJECT;
- String message = getMessage(messageID, baseDN.toString());
- DN matchedDN = getMatchedDN(baseDN);
- throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
- message, messageID, matchedDN, null);
- }
- DatabaseEntry baseIDData = baseID.getDatabaseEntry();
-
- EntryIDSet scopeList;
- if (searchScope == SearchScope.SINGLE_LEVEL)
- {
- scopeList = id2children.readKey(baseIDData, null, LockMode.DEFAULT);
- }
- else
- {
- scopeList = id2subtree.readKey(baseIDData, null, LockMode.DEFAULT);
- if (searchScope == SearchScope.WHOLE_SUBTREE)
+ try
{
- // The id2subtree list does not include the base entry ID.
- scopeList.add(baseID);
+ entryIDList =
+ vlvIndex.evaluate(null, searchOperation, sortRequest, vlvRequest,
+ debugBuffer);
+ if(entryIDList != null)
+ {
+ searchOperation.addResponseControl(
+ new ServerSideSortResponseControl(LDAPResultCode.SUCCESS,
+ null));
+ candidatesAreInScope = true;
+ break;
+ }
+ }
+ catch (DirectoryException de)
+ {
+ searchOperation.addResponseControl(
+ new ServerSideSortResponseControl(
+ de.getResultCode().getIntValue(), null));
+
+ if (sortRequest.isCritical())
+ {
+ throw de;
+ }
}
}
- entryIDList.retainAll(scopeList);
- if (debugBuffer != null)
+ }
+
+ if(entryIDList == null)
+ {
+ // Create an index filter to get the search result candidate entries.
+ IndexFilter indexFilter =
+ new IndexFilter(this, searchOperation, debugBuffer);
+
+ // Evaluate the filter against the attribute indexes.
+ entryIDList = indexFilter.evaluate();
+
+ // Evaluate the search scope against the id2children and id2subtree
+ // indexes.
+ if (entryIDList.size() > IndexFilter.FILTER_CANDIDATE_THRESHOLD)
{
- debugBuffer.append(" scope=");
- debugBuffer.append(searchScope);
- scopeList.toString(debugBuffer);
+ // Read the ID from dn2id.
+ EntryID baseID = dn2id.get(null, baseDN);
+ if (baseID == null)
+ {
+ int messageID = MSGID_JEB_SEARCH_NO_SUCH_OBJECT;
+ String message = getMessage(messageID, baseDN.toString());
+ DN matchedDN = getMatchedDN(baseDN);
+ throw new DirectoryException(ResultCode.NO_SUCH_OBJECT,
+ message, messageID, matchedDN, null);
+ }
+ DatabaseEntry baseIDData = baseID.getDatabaseEntry();
+
+ EntryIDSet scopeList;
+ if (searchScope == SearchScope.SINGLE_LEVEL)
+ {
+ scopeList = id2children.readKey(baseIDData, null, LockMode.DEFAULT);
+ }
+ else
+ {
+ scopeList = id2subtree.readKey(baseIDData, null, LockMode.DEFAULT);
+ if (searchScope == SearchScope.WHOLE_SUBTREE)
+ {
+ // The id2subtree list does not include the base entry ID.
+ scopeList.add(baseID);
+ }
+ }
+ entryIDList.retainAll(scopeList);
+ if (debugBuffer != null)
+ {
+ debugBuffer.append(" scope=");
+ debugBuffer.append(searchScope);
+ scopeList.toString(debugBuffer);
+ }
+ if (scopeList.isDefined())
+ {
+ // In this case we know that every candidate is in scope.
+ candidatesAreInScope = true;
+ }
}
- if (scopeList.isDefined())
+
+ if (sortRequest != null)
{
- // In this case we know that every candidate is in scope.
- candidatesAreInScope = true;
+ try
+ {
+ entryIDList = EntryIDSetSorter.sort(this, entryIDList,
+ searchOperation,
+ sortRequest.getSortOrder(),
+ vlvRequest);
+ searchOperation.addResponseControl(
+ new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null));
+ }
+ catch (DirectoryException de)
+ {
+ searchOperation.addResponseControl(
+ new ServerSideSortResponseControl(
+ de.getResultCode().getIntValue(), null));
+
+ if (sortRequest.isCritical())
+ {
+ throw de;
+ }
+ }
}
}
@@ -697,30 +1005,6 @@
if (entryIDList.isDefined())
{
- if (sortRequest != null)
- {
- try
- {
- entryIDList = EntryIDSetSorter.sort(this, entryIDList,
- searchOperation,
- sortRequest.getSortOrder(),
- vlvRequest);
- searchOperation.addResponseControl(
- new ServerSideSortResponseControl(LDAPResultCode.SUCCESS, null));
- }
- catch (DirectoryException de)
- {
- searchOperation.addResponseControl(
- new ServerSideSortResponseControl(
- de.getResultCode().getIntValue(), null));
-
- if (sortRequest.isCritical())
- {
- throw de;
- }
- }
- }
-
searchIndexed(entryIDList, candidatesAreInScope, searchOperation,
pageRequest);
}
@@ -3313,6 +3597,11 @@
{
index.addEntry(txn, entryID, entry);
}
+
+ for (VLVIndex vlvIndex : vlvIndexMap.values())
+ {
+ vlvIndex.addEntry(txn, entryID, entry);
+ }
}
/**
@@ -3332,6 +3621,11 @@
{
index.removeEntry(txn, entryID, entry);
}
+
+ for (VLVIndex vlvIndex : vlvIndexMap.values())
+ {
+ vlvIndex.removeEntry(txn, entryID, entry);
+ }
}
/**
@@ -3344,11 +3638,13 @@
* @param entryID The ID of the entry that was changed.
* @param mods The sequence of modifications made to the entry.
* @throws DatabaseException If an error occurs in the JE database.
+ * @throws DirectoryException If a Directory Server error occurs.
+ * @throws JebException If an error occurs in the JE backend.
*/
private void indexModifications(Transaction txn, Entry oldEntry,
Entry newEntry,
EntryID entryID, List<Modification> mods)
- throws DatabaseException
+ throws DatabaseException, DirectoryException, JebException
{
// Process in index configuration order.
for (AttributeIndex index : attrIndexMap.values())
@@ -3370,6 +3666,11 @@
index.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
}
}
+
+ for(VLVIndex vlvIndex : vlvIndexMap.values())
+ {
+ vlvIndex.modifyEntry(txn, entryID, oldEntry, newEntry, mods);
+ }
}
/**
@@ -3417,6 +3718,11 @@
{
index.listDatabases(dbList);
}
+
+ for (VLVIndex vlvIndex : vlvIndexMap.values())
+ {
+ dbList.add(vlvIndex);
+ }
}
/**
@@ -3861,92 +4167,6 @@
}
/**
- * {@inheritDoc}
- */
- public synchronized boolean isConfigurationAddAcceptable(
- JEIndexCfg cfg, List<String> unacceptableReasons)
- {
- // TODO: validate more before returning true?
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- public synchronized ConfigChangeResult applyConfigurationAdd(JEIndexCfg cfg)
- {
- ConfigChangeResult ccr;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
- try
- {
- AttributeIndex index =
- new AttributeIndex(cfg, state, env, this);
- index.open();
- attrIndexMap.put(cfg.getIndexAttribute(), index);
- }
- catch(Exception e)
- {
- messages.add(StaticUtils.stackTraceToSingleLineString(e));
- ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
- adminActionRequired,
- messages);
- return ccr;
- }
-
- adminActionRequired = true;
- int msgID = MSGID_JEB_INDEX_ADD_REQUIRES_REBUILD;
- messages.add(getMessage(msgID, cfg.getIndexAttribute().getNameOrOID()));
- return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
- messages);
- }
-
- /**
- * {@inheritDoc}
- */
- public synchronized boolean isConfigurationDeleteAcceptable(
- JEIndexCfg cfg, List<String> unacceptableReasons)
- {
- // TODO: validate more before returning true?
- return true;
- }
-
- /**
- * {@inheritDoc}
- */
- public synchronized ConfigChangeResult applyConfigurationDelete(
- JEIndexCfg cfg)
- {
- ConfigChangeResult ccr;
- boolean adminActionRequired = false;
- ArrayList<String> messages = new ArrayList<String>();
-
- exclusiveLock.lock();
- try
- {
- AttributeIndex index = attrIndexMap.get(cfg.getIndexAttribute());
- deleteAttributeIndex(index);
- attrIndexMap.remove(cfg.getIndexAttribute());
- }
- catch(DatabaseException de)
- {
- messages.add(StaticUtils.stackTraceToSingleLineString(de));
- ccr = new ConfigChangeResult(DirectoryServer.getServerErrorResultCode(),
- adminActionRequired,
- messages);
- return ccr;
- }
- finally
- {
- exclusiveLock.unlock();
- }
-
- return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired,
- messages);
- }
-
- /**
* Get the environment config of the JE environment used in this entry
* container.
*
--
Gitblit v1.10.0