/*
* 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
* 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
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2014 ForgeRock AS
*/
/**
* Class representing an attribute index.
* We have a separate database for each type of indexing, which makes it easy
* to tell which attribute indexes are configured. The different types of
* indexing are equality, presence, substrings and ordering. The keys in the
* ordering index are ordered by setting the btree comparator to the ordering
* matching rule comparator.
* Note that the values in the equality index are normalized by the equality
* matching rule, whereas the values in the ordering index are normalized
* by the ordering matching rule. If these could be guaranteed to be identical
* then we would not need a separate ordering index.
*/
public class AttributeIndex
implements ConfigurationChangeListener<LocalDBIndexCfg>
{
/**
* The tracer object for the debug logger.
*/
/**
* A database key for the presence index.
*/
/**
* The entryContainer in which this attribute index resides.
*/
/**
* The attribute index configuration.
*/
/**
* The index database for attribute equality.
*/
/**
* The index database for attribute presence.
*/
/**
* The index database for attribute substrings.
*/
/**
* The index database for attribute ordering.
*/
/**
* The index database for attribute approximate.
*/
/**
* The ExtensibleMatchingRuleIndex instance for ExtensibleMatchingRule
* indexes.
*/
/**
* Create a new attribute index object.
* @param entryContainer The entryContainer of this attribute index.
* @param state The state database to persist index state info.
* @param env The JE environment handle.
* @param indexConfig The attribute index configuration.
* @throws DatabaseException if a JE database error occurs.
* @throws ConfigException if a configuration related error occurs.
*/
throws DatabaseException, ConfigException
{
this.entryContainer = entryContainer;
this.indexConfig = indexConfig;
{
{
throw new ConfigException(message);
}
false,
env,
}
{
false,
env,
}
{
{
throw new ConfigException(message);
}
false,
env,
}
{
{
throw new ConfigException(message);
}
false,
env,
}
{
{
throw new ConfigException(message);
}
false,
env,
}
{
{
throw new ConfigException(message);
}
//Iterate through the Set and create the index only if necessary.
//Collation equality and Ordering matching rules share the same
//indexer and index. A Collation substring matching rule is treated
// differently as it uses a separate indexer and index.
{
{
continue;
}
{
+ "." + indexerId;
{
//There is no index available for this index id. Create a new index.
rule,
indexer);
+ indexID;
false,
env,
}
}
}
}
}
/**
* Open the attribute index.
*
* @throws DatabaseException if a JE database error occurs while
* openning the index.
*/
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
indexConfig.addChangeListener(this);
}
/**
* Close the attribute index.
*
* @throws DatabaseException if a JE database error occurs while
* closing the index.
*/
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
indexConfig.removeChangeListener(this);
// The entryContainer is responsible for closing the JE databases.
}
/**
* Get the attribute type of this attribute index.
* @return The attribute type of this attribute index.
*/
{
return indexConfig.getAttribute();
}
/**
* Get the JE index configuration used by this index.
* @return The configuration in effect.
*/
{
return indexConfig;
}
/**
* Update the attribute index for a new entry.
*
* @param buffer The index buffer to use to store the added keys
* @param entryID The entry ID.
* @param entry The contents of the new entry.
* @return True if all the index keys for the entry are added. False if the
* entry ID already exists for some keys.
* @throws DatabaseException If an error occurs in the JE database.
* @throws DirectoryException If a Directory Server error occurs.
*/
throws DatabaseException, DirectoryException
{
boolean success = true;
if (equalityIndex != null)
{
{
success = false;
}
}
if (presenceIndex != null)
{
{
success = false;
}
}
if (substringIndex != null)
{
{
success = false;
}
}
if (orderingIndex != null)
{
{
success = false;
}
}
if (approximateIndex != null)
{
{
success = false;
}
}
if(extensibleIndexes!=null)
{
{
{
success = false;
}
}
}
return success;
}
/**
* Update the attribute index for a new entry.
*
* @param txn The database transaction to be used for the insertions.
* @param entryID The entry ID.
* @param entry The contents of the new entry.
* @return True if all the index keys for the entry are added. False if the
* entry ID already exists for some keys.
* @throws DatabaseException If an error occurs in the JE database.
* @throws DirectoryException If a Directory Server error occurs.
*/
throws DatabaseException, DirectoryException
{
boolean success = true;
if (equalityIndex != null)
{
{
success = false;
}
}
if (presenceIndex != null)
{
{
success = false;
}
}
if (substringIndex != null)
{
{
success = false;
}
}
if (orderingIndex != null)
{
{
success = false;
}
}
if (approximateIndex != null)
{
{
success = false;
}
}
if(extensibleIndexes!=null)
{
{
{
success = false;
}
}
}
return success;
}
/**
* Update the attribute index for a deleted entry.
*
* @param buffer The index buffer to use to store the deleted keys
* @param entryID The entry ID
* @param entry The contents of the deleted entry.
* @throws DatabaseException If an error occurs in the JE database.
* @throws DirectoryException If a Directory Server error occurs.
*/
throws DatabaseException, DirectoryException
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if(approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Update the attribute index for a deleted entry.
*
* @param txn The database transaction to be used for the deletions
* @param entryID The entry ID
* @param entry The contents of the deleted entry.
* @throws DatabaseException If an error occurs in the JE database.
* @throws DirectoryException If a Directory Server error occurs.
*/
throws DatabaseException, DirectoryException
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if(approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Update the index to reflect a sequence of modifications in a Modify
* operation.
*
* @param txn The JE transaction to use for database updates.
* @param entryID The ID of the entry that was modified.
* @param oldEntry The entry before the modifications were applied.
* @param newEntry The entry after the modifications were applied.
* @param mods The sequence of modifications in the Modify operation.
* @throws DatabaseException If an error occurs during an operation on a
* JE database.
*/
throws DatabaseException
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Update the index to reflect a sequence of modifications in a Modify
* operation.
*
* @param buffer The index buffer used to buffer up the index changes.
* @param entryID The ID of the entry that was modified.
* @param oldEntry The entry before the modifications were applied.
* @param newEntry The entry after the modifications were applied.
* @param mods The sequence of modifications in the Modify operation.
* @throws DatabaseException If an error occurs during an operation on a
* JE database.
*/
throws DatabaseException
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Makes a byte array representing a substring index key for
* one substring of a value.
*
* @param bytes The byte array containing the value.
* @param pos The starting position of the substring.
* @param len The length of the substring.
* @return A byte array containing a substring key.
*/
{
return keyBytes;
}
/**
* Decompose an attribute value into a set of substring index keys.
* The ID of the entry containing this value should be inserted
* into the list of each of these keys.
*
* @param value A byte array containing the normalized attribute value.
* @return A set of index keys.
*/
{
// Eliminate duplicates by putting the keys into a set.
// Sorting the keys will ensure database record locks are acquired
// in a consistent order and help prevent transaction deadlocks between
// concurrent writers.
byte[] keyBytes;
// Example: The value is ABCDE and the substring length is 3.
// We produce the keys ABC BCD CDE DE E
// To find values containing a short substring such as DE,
// iterate through keys with prefix DE. To find values
// containing a longer substring such as BCDE, read keys
// BCD and CDE.
{
}
return set;
}
/**
* Retrieve the entry IDs that might contain a given substring.
* @param bytes A normalized substring of an attribute value.
* @return The candidate entry IDs.
*/
{
// There are two cases, depending on whether the user-provided
// substring is smaller than the configured index substring length or not.
{
// Iterate through all the keys that have this value as the prefix.
// Set the lower bound for a range search.
// Set the upper bound for a range search.
// We need a key for the upper bound that is of equal length
// but slightly greater than the lower bound.
{
if (upper[i] == 0xFF)
{
// We have to carry the overflow to the more significant byte.
upper[i] = 0;
}
else
{
// No overflow, we can stop.
break;
}
}
// Read the range: lower <= keys < upper.
}
else
{
// Break the value up into fragments of length equal to the
// index substring length, and read those keys.
// Eliminate duplicates by putting the keys into a set.
// Example: The value is ABCDE and the substring length is 3.
// We produce the keys ABC BCD CDE.
{
byte[] keyBytes;
}
{
// Read the key.
// Incorporate them into the results.
// We may have reached the point of diminishing returns where
// it is quicker to stop now and process the current small number of
// candidates.
{
break;
}
}
return results;
}
}
/**
* Uses an equality index to retrieve the entry IDs that might contain a
* given initial substring.
* @param bytes A normalized initial substring of an attribute value.
* @return The candidate entry IDs.
*/
{
// Iterate through all the keys that have this value as the prefix.
// Set the lower bound for a range search.
// Set the upper bound for a range search.
// We need a key for the upper bound that is of equal length
// but slightly greater than the lower bound.
{
if (upper[i] == 0xFF)
{
// We have to carry the overflow to the more significant byte.
upper[i] = 0;
}
else
{
// No overflow, we can stop.
break;
}
}
// Read the range: lower <= keys < upper.
}
/**
* Retrieve the entry IDs that might match an equality filter.
*
* @param equalityFilter The equality filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain the filter
* assertion value.
*/
{
if (equalityIndex == null)
{
if(monitor.isFilterUseEnabled())
{
}
return new EntryIDSet();
}
try
{
// Make a key from the normalized assertion value.
byte[] keyBytes =
if(debugBuffer != null)
{
}
// Read the key.
if(monitor.isFilterUseEnabled())
{
{
}
else if(!equalityIndex.isTrusted())
{
equalityIndex.getName()));
}
else if(equalityIndex.isRebuildRunning())
{
equalityIndex.getName()));
}
else
{
equalityIndex.getName()));
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* Retrieve the entry IDs that might match a presence filter.
*
* @param filter The presence filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain one or more
* values of the attribute type in the filter.
*/
{
if (presenceIndex == null)
{
if(monitor.isFilterUseEnabled())
{
}
return new EntryIDSet();
}
if(debugBuffer != null)
{
}
// Read the presence key
if(monitor.isFilterUseEnabled())
{
{
}
else if(!presenceIndex.isTrusted())
{
presenceIndex.getName()));
}
else if(presenceIndex.isRebuildRunning())
{
presenceIndex.getName()));
}
else
{
presenceIndex.getName()));
}
}
return idSet;
}
/**
* Retrieve the entry IDs that might match a greater-or-equal filter.
*
* @param filter The greater-or-equal filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain a value
* greater than or equal to the filter assertion value.
*/
{
if (orderingIndex == null)
{
if(monitor.isFilterUseEnabled())
{
}
return new EntryIDSet();
}
try
{
// Set the lower bound for a range search.
// Use the ordering matching rule to normalize the value.
// Set the upper bound to 0 to search all keys greater then the lower
// bound.
byte[] upper = new byte[0];
if(debugBuffer != null)
{
}
// Read the range: lower <= keys < upper.
if(monitor.isFilterUseEnabled())
{
{
}
else if(!orderingIndex.isTrusted())
{
orderingIndex.getName()));
}
else if(orderingIndex.isRebuildRunning())
{
orderingIndex.getName()));
}
else
{
orderingIndex.getName()));
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* Retrieve the entry IDs that might match a less-or-equal filter.
*
* @param filter The less-or-equal filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain a value
* less than or equal to the filter assertion value.
*/
{
if (orderingIndex == null)
{
if(monitor.isFilterUseEnabled())
{
}
return new EntryIDSet();
}
try
{
// Set the lower bound to 0 to start the range search from the smallest
// key.
byte[] lower = new byte[0];
// Set the upper bound for a range search.
// Use the ordering matching rule to normalize the value.
if(debugBuffer != null)
{
}
// Read the range: lower < keys <= upper.
if(monitor.isFilterUseEnabled())
{
{
}
else if(!orderingIndex.isTrusted())
{
orderingIndex.getName()));
}
else if(orderingIndex.isRebuildRunning())
{
orderingIndex.getName()));
}
else
{
orderingIndex.getName()));
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* Retrieve the entry IDs that might match a substring filter.
*
* @param filter The substring filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain a value
* that matches the filter substrings.
*/
{
try
{
{
// Use the equality index for initial substrings if possible.
{
{
if(debugBuffer != null)
{
getNameOrOID());
}
if(monitor.isFilterUseEnabled())
{
}
return results;
}
}
else
{
}
}
if (substringIndex == null)
{
if(monitor.isFilterUseEnabled())
{
{
{
if(equalityIndex == null)
{
}
else if(!equalityIndex.isTrusted())
{
equalityIndex.getName()));
}
else if(equalityIndex.isRebuildRunning())
{
equalityIndex.getName()));
}
else
{
equalityIndex.getName()));
}
}
else
{
}
}
else
{
}
}
return results;
}
// We do not distinguish between sub and final elements
// in the substring index. Put all the elements into a single list.
{
}
// Iterate through each substring element.
{
// Normalize the substring according to the substring matching rule.
// Get the candidate entry IDs from the index.
// Incorporate them into the results.
// We may have reached the point of diminishing returns where
// it is quicker to stop now and process the current small number of
// candidates.
{
break;
}
}
if(debugBuffer != null)
{
}
if(monitor.isFilterUseEnabled())
{
{
}
else if(!substringIndex.isTrusted())
{
substringIndex.getName()));
}
else if(substringIndex.isRebuildRunning())
{
substringIndex.getName()));
}
else
{
substringIndex.getName()));
}
}
return results;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* Retrieve the entry IDs that might have a value greater than or
* equal to the lower bound value, and less than or equal to the
* upper bound value.
*
* @param lowerValue The lower bound value
* @param upperValue The upper bound value
* @return The candidate entry IDs.
*/
{
if (orderingIndex == null)
{
return new EntryIDSet();
}
try
{
// Use the ordering matching rule to normalize the values.
// Set the lower bound for a range search.
byte[] lower =
// Set the upper bound for a range search.
byte[] upper =
// Read the range: lower <= keys <= upper.
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* The default lexicographic byte array comparator.
* Is there one available in the Java platform?
*/
{
/**
* Compares its two arguments for order. Returns a negative integer,
* zero, or a positive integer as the first argument is less than, equal
* to, or greater than the second.
*
* @param a the first object to be compared.
* @param b the second object to be compared.
* @return a negative integer, zero, or a positive integer as the
* first argument is less than, equal to, or greater than the
* second.
*/
public int compare(byte[] a, byte[] b)
{
int i;
{
if (a[i] > b[i])
{
return 1;
}
else if (a[i] < b[i])
{
return -1;
}
}
{
return 0;
}
{
return 1;
}
else
{
return -1;
}
}
}
/**
* Retrieve the entry IDs that might match an approximate filter.
*
* @param approximateFilter The approximate filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain the filter
* assertion value.
*/
{
if (approximateIndex == null)
{
if(monitor.isFilterUseEnabled())
{
}
return new EntryIDSet();
}
try
{
// Make a key from the normalized assertion value.
byte[] keyBytes =
if(debugBuffer != null)
{
}
// Read the key.
if(monitor.isFilterUseEnabled())
{
{
}
else if(!approximateIndex.isTrusted())
{
approximateIndex.getName()));
}
else if(approximateIndex.isRebuildRunning())
{
approximateIndex.getName()));
}
else
{
approximateIndex.getName()));
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
return new EntryIDSet();
}
}
/**
* Close cursors related to the attribute indexes.
*
* @throws DatabaseException If a database error occurs.
*/
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Return the number of values that have exceeded the entry limit since this
* object was created.
*
* @return The number of values that have exceeded the entry limit.
*/
public long getEntryLimitExceededCount()
{
long entryLimitExceededCount = 0;
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
return entryLimitExceededCount;
}
/**
* Get a list of the databases opened by this attribute index.
* @param dbList A list of database containers.
*/
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Get a string representation of this object.
* @return return A string representation of this object.
*/
{
return getName();
}
/**
* {@inheritDoc}
*/
public synchronized boolean isConfigurationChangeAcceptable(
{
{
{
return false;
}
}
{
{
return false;
}
}
{
{
return false;
}
}
{
if (approximateIndex == null &&
{
return false;
}
}
{
{
return false;
}
}
return true;
}
/**
* {@inheritDoc}
*/
{
boolean adminActionRequired = false;
try
{
{
if (equalityIndex == null)
{
// Adding equality index
false,
env,
if(!equalityIndex.isTrusted())
{
adminActionRequired = true;
equalityIndex.getName()));
}
}
else
{
// already exists. Just update index entry limit.
{
adminActionRequired = true;
equalityIndex.getName());
}
}
}
else
{
if (equalityIndex != null)
{
try
{
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
{
if(presenceIndex == null)
{
false,
env,
if(!presenceIndex.isTrusted())
{
adminActionRequired = true;
presenceIndex.getName()));
}
}
else
{
// already exists. Just update index entry limit.
{
adminActionRequired = true;
presenceIndex.getName());
}
}
}
else
{
if (presenceIndex != null)
{
try
{
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
{
if(substringIndex == null)
{
false,
env,
if(!substringIndex.isTrusted())
{
adminActionRequired = true;
substringIndex.getName()));
}
}
else
{
// already exists. Just update index entry limit.
{
adminActionRequired = true;
}
if(indexConfig.getSubstringLength() !=
{
}
}
}
else
{
if (substringIndex != null)
{
try
{
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
{
if(orderingIndex == null)
{
false,
env,
if(!orderingIndex.isTrusted())
{
adminActionRequired = true;
orderingIndex.getName()));
}
}
else
{
// already exists. Just update index entry limit.
{
adminActionRequired = true;
orderingIndex.getName());
}
}
}
else
{
if (orderingIndex != null)
{
try
{
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
{
if(approximateIndex == null)
{
false,
env,
if(!approximateIndex.isTrusted())
{
adminActionRequired = true;
approximateIndex.getName()));
}
}
else
{
// already exists. Just update index entry limit.
{
adminActionRequired = true;
}
}
}
else
{
if (approximateIndex != null)
{
try
{
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
{
new HashSet<ExtensibleMatchingRule>();
if(extensibleIndexes == null)
{
}
{
{
continue;
}
{
+ "." + indexerId;
{
rule,
indexer);
+ indexID;
false,
env,
if(!extensibleIndex.isTrusted())
{
adminActionRequired = true;
extensibleIndex.getName()));
}
}
else
{
{
adminActionRequired = true;
}
if(indexConfig.getSubstringLength() !=
{
rule,
indexer);
}
}
}
}
//Some rules might have been removed from the configuration.
new HashSet<ExtensibleMatchingRule>();
{
if(!validRules.contains(r))
{
deletedRules.add(r);
}
}
{
try
{
{
new HashSet<ExtensibleMatchingRule>();
{
}
{
//Rule has been already deleted.
continue;
}
//If all the rules are part of the deletedRules, delete
//this index.
{
//it is safe to delete this index as it is not shared.
{
}
}
else
{
{
}
}
}
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
else
{
if(extensibleIndexes != null)
{
try
{
{
}
}
catch(DatabaseException de)
{
ccr = new ConfigChangeResult(
return ccr;
}
finally
{
}
}
}
indexConfig = cfg;
messages);
}
catch(Exception e)
{
messages);
return ccr;
}
}
/**
* Set the index truststate.
* @param txn A database transaction, or null if none is required.
* @param trusted True if this index should be trusted or false
* otherwise.
* @throws DatabaseException If an error occurs in the JE database.
*/
throws DatabaseException
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Return true iff this index is trusted.
* @return the trusted state of this index
*/
public boolean isTrusted()
{
{
return false;
}
{
return false;
}
{
return false;
}
{
return false;
}
{
return false;
}
if(extensibleIndexes!=null)
{
{
{
return false;
}
}
}
return true;
}
/**
* Set the rebuild status of this index.
* @param rebuildRunning True if a rebuild process on this index
* is running or False otherwise.
*/
{
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
}
/**
* Get the JE database name prefix for indexes in this attribute
* index.
*
* @return JE database name for this database container.
*/
{
}
/**
* Return the equality index.
*
* @return The equality index.
*/
return equalityIndex;
}
/**
* Return the approximate index.
*
* @return The approximate index.
*/
return approximateIndex;
}
/**
* Return the ordering index.
*
* @return The ordering index.
*/
return orderingIndex;
}
/**
* Return the substring index.
*
* @return The substring index.
*/
return substringIndex;
}
/**
* Return the presence index.
*
* @return The presence index.
*/
return presenceIndex;
}
/**
* Return the mapping of extensible index types and indexes.
*
* @return The Map of extensible index types and indexes.
*/
{
if(extensibleIndexes == null)
{
return Collections.emptyMap();
}
return extensibleIndexes.getIndexMap();
}
/**
* Retrieves all the indexes used by this attribute index.
*
* @return A collection of all indexes in use by this attribute
* index.
*/
if (equalityIndex != null)
{
}
if (presenceIndex != null)
{
}
if (substringIndex != null)
{
}
if (orderingIndex != null)
{
}
if (approximateIndex != null)
{
}
if(extensibleIndexes!=null)
{
{
}
}
return indexes;
}
/**
* Retrieve the entry IDs that might match an extensible filter.
*
* @param extensibleFilter The extensible filter.
* @param debugBuffer If not null, a diagnostic string will be written
* which will help determine how the indexes contributed
* to this search.
* @param monitor The database environment monitor provider that will keep
* index filter usage statistics.
* @return The candidate entry IDs that might contain the filter
* assertion value.
*/
{
//Get the Matching Rule OID of the filter.
/**
* Use the default equality index in two conditions:
* 1. There is no matching rule provided
* 2. The matching rule specified is actually the default equality.
*/
{
//No matching rule is defined; use the default equality matching rule.
if(equalityIndex == null)
{
// There is no index on this matching rule.
if(monitor.isFilterUseEnabled())
{
}
}
try
{
// Make a key from the normalized assertion value.
byte[] keyBytes =
toByteArray();
if(debugBuffer != null)
{
}
// Read the key.
if(monitor.isFilterUseEnabled())
{
{
}
else if(!equalityIndex.isTrusted())
{
equalityIndex.getName()));
}
else if(equalityIndex.isRebuildRunning())
{
equalityIndex.getName()));
}
else
{
equalityIndex.getName()));
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
}
}
if(extensibleIndexes == null
{
// There is no index on this matching rule.
if(monitor.isFilterUseEnabled())
{
}
}
try
{
if(debugBuffer != null)
{
{
+ "." + indexName
+ "." +indexerID;
}
}
if(monitor.isFilterUseEnabled())
{
{
}
else
{
{
}
else
{
}
}
}
return idSet;
}
catch (DirectoryException e)
{
if (debugEnabled())
{
}
}
}
/**
* This class manages all the configured extensible matching rules and
* their corresponding indexes.
*/
private class ExtensibleMatchingRuleIndex
{
/**
* The mapping of index ID and Index database.
*/
/**
* The mapping of Index ID and Set the matching rules.
*/
/**
* The Map of configured ExtensibleMatchingRule and the corresponding
* IndexQueryFactory.
*/
private final Map<ExtensibleMatchingRule,
/**
* Creates a new instance of ExtensibleMatchingRuleIndex.
*/
private ExtensibleMatchingRuleIndex()
{
}
/**
* Returns all configured ExtensibleMatchingRule instances.
* @return A Set of extensible matching rules.
*/
{
return rule2FactoryMap.keySet();
}
/**
* Returns ExtensibleMatchingRule instances for an index.
* @param indexID The index ID of an extensible matching rule index.
* @return A Set of extensible matching rules corresponding to
* an index ID.
*/
private Set<ExtensibleMatchingRule>
{
{
return Collections.emptySet();
}
else
{
}
}
/**
* Returns whether an index is present or not.
* @param indexID The index ID of an extensible matching rule index.
* @return True if an index is present. False if there is no matching index.
*/
{
}
/**
* Returns the index corresponding to an index ID.
* @param indexID The ID of an index.
* @return The extensible rule index corresponding to the index ID.
*/
{
}
/**
* Adds a new matching Rule and the name of the associated index.
* @indexName Name of the index.
* @rule An ExtensibleMatchingRule instance that needs to be indexed.
*/
{
{
}
}
/**
* Adds a new Index and its name.
* @param index The extensible matching rule index.
* @indexName The name of the index.
*/
{
}
/**
* Returns all the configured extensible indexes.
* @return All the available extensible matching rule indexes.
*/
{
}
/**
* Returns a map of all the configured extensible indexes and their types.
* @return A map of all the available extensible matching rule indexes
* and their types.
*/
{
if(id2IndexMap.isEmpty())
{
return Collections.emptyMap();
}
{
{
}
else
{
}
}
}
/**
* Deletes an index corresponding to the index ID.
* @param indexID Name of the index.
*/
{
}
/**
* Deletes an extensible matching rule from the list of available rules.
* @param rule The ExtensibleMatchingRule that needs to be removed.
* @param indexID The name of the index corresponding to the rule.
*/
{
{
}
}
/**
* Adds an ExtensibleMatchingRule and its corresponding IndexQueryFactory.
* @param rule An ExtensibleMatchingRule that needs to be added.
* @param query A query factory matching the rule.
*/
{
}
/**
* Returns the query factory associated with the rule.
* @param rule An ExtensibleMatchingRule that needs to be searched.
* @return An IndexQueryFactory corresponding to the matching rule.
*/
{
}
/**
* Deletes extensible matching rules from the list of available rules.
* @param indexID The name of the index corresponding to the rules.
*/
{
{
}
}
/**
* Deletes all references to matching rules and the indexes.
*/
private void deleteAll()
{
id2IndexMap.clear();
id2RulesMap.clear();
}
}
/**
* This class extends the IndexConfig for JE Backend.
*/
{
//The length of the substring index.
private int substringLength;
/**
* Creates a new JEIndexConfig instance.
* @param substringLength The length of the substring.
*/
{
this.substringLength = substringLength;
}
/**
* Returns the length of the substring.
* @return the length of the substring.
*/
public int getSubstringLength()
{
return substringLength;
}
}
}