opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/AbstractMatchingRule.java
@@ -52,6 +52,65 @@ public abstract class AbstractMatchingRule implements MatchingRule { /** * Default implementation of assertion. */ public static final class DefaultAssertion implements Assertion { /** The ID of the DB index to use with this assertion. */ private final String indexID; private final ByteSequence normalizedAssertionValue; /** * Returns the equality assertion. * * @param normalizedAssertionValue * The value on which the assertion is built. * @return the equality assertion */ public static DefaultAssertion equality(final ByteSequence normalizedAssertionValue) { return new DefaultAssertion("equality", normalizedAssertionValue); } /** * Returns the approximate assertion. * * @param normalizedAssertionValue * The value on which the assertion is built. * @return the approximate assertion */ static DefaultAssertion approximate(final ByteSequence normalizedAssertionValue) { return new DefaultAssertion("approximate", normalizedAssertionValue); } private DefaultAssertion(final String indexID, final ByteSequence normalizedAssertionValue) { this.indexID = indexID; this.normalizedAssertionValue = normalizedAssertionValue; } /** * {@inheritDoc} */ @Override public ConditionResult matches(final ByteSequence normalizedAttributeValue) { return ConditionResult.valueOf(normalizedAssertionValue.equals(normalizedAttributeValue)); } /** * {@inheritDoc} */ @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return factory.createExactMatchQuery(indexID, normalizedAssertionValue); } } private static final Assertion UNDEFINED_ASSERTION = new Assertion() { @Override @@ -71,9 +130,14 @@ }; /** * {@inheritDoc} * Returns the normalized form of the assertion value. * * @param value * The assertion value to normalize. * @return the normalized value * @throws DecodeException * If a problem occurs. */ @Override public ByteString normalizeAssertionValue(ByteSequence value) throws DecodeException { opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/ApproximateMatchingRule.java
@@ -26,8 +26,12 @@ */ package org.opends.server.api; import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteSequence; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ConditionResult; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.spi.IndexQueryFactory; /** * This class defines the set of methods and structures that must be @@ -86,5 +90,29 @@ return ConditionResult.valueOf( approximatelyMatch(attributeValue, assertionValue)); } /** {@inheritDoc} */ @Override public Assertion getAssertion(ByteSequence assertionValue) throws DecodeException { final ByteString normAssertionValue = normalizeAttributeValue(assertionValue); final DefaultAssertion approxAssertion = DefaultAssertion.approximate(normAssertionValue); return new Assertion() { @Override public ConditionResult matches(ByteSequence normalizedAttributeValue) { return valuesMatch(normalizedAttributeValue, normAssertionValue); } @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return approxAssertion.createIndexQuery(factory); } }; } } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/EqualityMatchingRule.java
@@ -26,8 +26,13 @@ */ package org.opends.server.api; import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteSequence; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ConditionResult; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.spi.IndexQueryFactory; import org.opends.server.api.AbstractMatchingRule.DefaultAssertion; /** * This class defines the set of methods and structures that must be @@ -108,5 +113,41 @@ { return attributeValue.hashCode(); } /** {@inheritDoc} */ @Override public Assertion getAssertion(ByteSequence assertionValue) throws DecodeException { final ByteString normAssertionValue = normalizeAttributeValue(assertionValue); return getEqualityAssertion(normAssertionValue); } /** * Return the equality assertion for the matching rule. * * @param normAssertionValue * The normalized assertion value. * @return the assertion */ protected Assertion getEqualityAssertion(final ByteString normAssertionValue) { final DefaultAssertion eqAssertion = DefaultAssertion.equality(normAssertionValue); return new Assertion() { @Override public ConditionResult matches(ByteSequence normalizedAttributeValue) { return valuesMatch(normalizedAttributeValue, normAssertionValue); } @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return eqAssertion.createIndexQuery(factory); } }; } } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/MatchingRule.java
@@ -64,25 +64,6 @@ */ String getOID(); /** * Retrieves the normalized form of the provided assertion value, * which is best suite for efficiently performing matching * operations on that value. * * @param value * The assertion value to be normalized. * @return The normalized version of the provided value. * @throws DecodeException * If the provided value is invalid according to the * associated attribute syntax. */ ByteString normalizeAssertionValue(ByteSequence value) throws DecodeException; /** * Retrieves the name or OID for this matching rule. If it has a * name, then it will be returned. Otherwise, the OID will be @@ -118,7 +99,7 @@ * @throws DecodeException * if problem */ Assertion getAssertion(final ByteSequence assertionValue) throws DecodeException; Assertion getAssertion(ByteSequence assertionValue) throws DecodeException; /** * Returns the normalized form of the provided assertion value, which is @@ -132,7 +113,7 @@ * @throws DecodeException * if the syntax of the value is not valid. */ public Assertion getGreaterOrEqualAssertion(final ByteSequence assertionValue) throws DecodeException; Assertion getGreaterOrEqualAssertion(ByteSequence assertionValue) throws DecodeException; /** * Returns the normalized form of the provided assertion value, which is @@ -146,7 +127,7 @@ * @throws DecodeException * if the syntax of the value is not valid. */ public Assertion getLessOrEqualAssertion(final ByteSequence assertionValue) throws DecodeException; Assertion getLessOrEqualAssertion(ByteSequence assertionValue) throws DecodeException; /** * Returns the normalized form of the provided assertion substring values, @@ -166,8 +147,8 @@ * @throws DecodeException * if the syntax of the value is not valid. */ public Assertion getSubstringAssertion(final ByteSequence subInitial, final List<? extends ByteSequence> subAnyElements, final ByteSequence subFinal) throws DecodeException; Assertion getSubstringAssertion(ByteSequence subInitial, List<? extends ByteSequence> subAnyElements, ByteSequence subFinal) throws DecodeException; /** * Indicates whether this matching rule is declared "OBSOLETE". The opendj-sdk/opendj3-server-dev/src/server/org/opends/server/api/SubstringMatchingRule.java
@@ -345,72 +345,6 @@ } } // TODO : reminder : should add this method in the SDK /** {@inheritDoc} */ @Override public int hashCode() { int hashCode = 0; if (normInitial != null) { hashCode += normInitial.hashCode(); } if (normAnys != null) { for (ByteString any : normAnys) { hashCode += any.hashCode(); } } if (normFinal != null) { hashCode += normFinal.hashCode(); } return hashCode; } // TODO : reminder : should add this method in the SDK /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (! (obj instanceof DefaultSubstringAssertion)) { return false; } DefaultSubstringAssertion other = (DefaultSubstringAssertion) obj; boolean initialCheck = normInitial == null ? other.normInitial == null : normInitial.equals(other.normInitial); if (!initialCheck) { return false; } boolean finalCheck = normFinal == null ? other.normFinal == null : normFinal.equals(other.normFinal); if (!finalCheck) { return false; } boolean anyCheck = normAnys == null ? other.normAnys == null : normAnys.length == other.normAnys.length; if (!anyCheck) { return false; } if (normAnys != null) { for (int i = 0; i < normAnys.length; i++) { if (! normAnys[i].equals(other.normAnys[i])) { return false; } } } return true; } } /** {@inheritDoc} */ opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/AttributeIndex.java
@@ -31,8 +31,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.config.server.ConfigException; import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.ResultCode; @@ -41,11 +43,11 @@ import org.forgerock.util.Utils; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn; import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn.IndexType; import org.opends.server.admin.std.server.LocalDBIndexCfg; import org.opends.server.api.ExtensibleIndexer; import org.opends.server.api.ExtensibleMatchingRule; import org.opends.server.api.MatchingRule; import org.opends.server.api.SubstringMatchingRule; import org.opends.server.core.DirectoryServer; import org.opends.server.monitors.DatabaseEnvironmentMonitor; import org.opends.server.types.*; @@ -119,6 +121,11 @@ */ Index approximateIndex = null; /** The mapping from names to indexes. */ private Map<String, Index> nameToIndexes; private IndexQueryFactory<IndexQuery> indexQueryFactory; /** * The ExtensibleMatchingRuleIndex instance for ExtensibleMatchingRule * indexes. @@ -131,6 +138,7 @@ /** * 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. @@ -139,71 +147,73 @@ * @throws ConfigException if a configuration related error occurs. */ public AttributeIndex(LocalDBIndexCfg indexConfig, State state, Environment env, EntryContainer entryContainer) Environment env, EntryContainer entryContainer) throws DatabaseException, ConfigException { this.entryContainer = entryContainer; this.env = env; this.indexConfig = indexConfig; this.state = state; nameToIndexes = new HashMap<String, Index>(); AttributeType attrType = indexConfig.getAttribute(); String name = entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); String name = entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); final JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength()); if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.EQUALITY)) if (indexConfig.getIndexType().contains(IndexType.EQUALITY)) { this.equalityIndex = buildExtIndex( name, attrType, attrType.getEqualityMatchingRule(), new EqualityIndexer(attrType)); nameToIndexes.put(IndexType.EQUALITY.toString(), equalityIndex); } if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.PRESENCE)) if (indexConfig.getIndexType().contains(IndexType.PRESENCE)) { this.presenceIndex = newIndex(name + ".presence", new PresenceIndexer(attrType), indexConfig.getIndexEntryLimit()); nameToIndexes.put(IndexType.PRESENCE.toString(), presenceIndex); } if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.SUBSTRING)) if (indexConfig.getIndexType().contains(IndexType.SUBSTRING)) { this.substringIndex = buildExtIndex( name, attrType, attrType.getSubstringMatchingRule(), new SubstringIndexer(attrType, config)); //nameToIndexes.put(IndexType.SUBSTRING.toString(), substringIndex); } if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.ORDERING)) if (indexConfig.getIndexType().contains(IndexType.ORDERING)) { this.orderingIndex = buildExtIndex( name, attrType, attrType.getOrderingMatchingRule(), new OrderingIndexer(attrType)); nameToIndexes.put(IndexType.ORDERING.toString(), orderingIndex); } if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.APPROXIMATE)) if (indexConfig.getIndexType().contains(IndexType.APPROXIMATE)) { this.approximateIndex = buildExtIndex( name, attrType, attrType.getApproximateMatchingRule(), new ApproximateIndexer(attrType)); nameToIndexes.put(IndexType.APPROXIMATE.toString(), approximateIndex); } if (indexConfig.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.EXTENSIBLE)) indexQueryFactory = new IndexQueryFactoryImpl(nameToIndexes, config); if (indexConfig.getIndexType().contains(IndexType.EXTENSIBLE)) { Set<String> extensibleRules = indexConfig.getIndexExtensibleMatchingRule(); Set<String> extensibleRules = indexConfig.getIndexExtensibleMatchingRule(); if(extensibleRules == null || extensibleRules.isEmpty()) { throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "extensible")); } extensibleIndexes = new ExtensibleMatchingRuleIndex(); //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. // indexer and index. // A Collation substring matching rule is treated differently // as it uses a separate indexer and index. for(String ruleName:extensibleRules) { ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(toLowerCase(ruleName)); ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(toLowerCase(ruleName)); if(rule == null) { logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); @@ -221,11 +231,9 @@ extensibleIndexes.addIndex(extIndex, indexID); } extensibleIndexes.addRule(indexID, rule); indexMap.put(indexer.getExtensibleIndexID(), extensibleIndexes.getIndex(indexID)); indexMap.put(indexer.getExtensibleIndexID(), extensibleIndexes.getIndex(indexID)); } IndexQueryFactory<IndexQuery> factory = new IndexQueryFactoryImpl(indexMap, config); IndexQueryFactory<IndexQuery> factory = new IndexQueryFactoryImpl(indexMap, config); extensibleIndexes.addQueryFactory(rule, factory); } } @@ -637,128 +645,48 @@ } /** * Retrieve the entry IDs that might contain a given substring. * @param bytes A normalized substring of an attribute value. * @return The candidate entry IDs. * Retrieve the entry IDs that might match the provided assertion. * * @param indexQuery * The query used to retrieve entries. * @param indexName * The name of index used to retrieve entries. * @param filter * The filter on entries. * @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. */ private EntryIDSet matchSubstring(byte[] bytes) { // FIXME replace this code with SDK's // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery() int substrLength = indexConfig.getSubstringLength(); // There are two cases, depending on whether the user-provided // substring is smaller than the configured index substring length or not. if (bytes.length < substrLength) private EntryIDSet evaluateIndexQuery(IndexQuery indexQuery, String indexName, SearchFilter filter, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { // Iterate through all the keys that have this value as the prefix. LocalizableMessageBuilder debugMessage = monitor.isFilterUseEnabled() ? new LocalizableMessageBuilder() : null; EntryIDSet results = indexQuery.evaluate(debugMessage); // Set the lower bound for a range search. byte[] lower = makeSubstringKey(bytes, 0, bytes.length); if (debugBuffer != null) { debugBuffer.append("[INDEX:").append(indexConfig.getAttribute().getNameOrOID()) .append(".").append(indexName).append("]"); } // 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. byte[] upper = makeSubstringKey(bytes, 0, bytes.length); for (int i = upper.length-1; i >= 0; i--) if (monitor.isFilterUseEnabled()) { if (upper[i] == 0xFF) if (results.isDefined()) { // We have to carry the overflow to the more significant byte. upper[i] = 0; monitor.updateStats(filter, results.size()); } else { // No overflow, we can stop. upper[i] = (byte) (upper[i] + 1); break; monitor.updateStats(filter, debugMessage.toMessage()); } } // Read the range: lower <= keys < upper. return substringIndex.readRange(lower, upper, true, false); } 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. Set<byte[]> set = new TreeSet<byte[]>(substringIndex.indexer.getComparator()); // Example: The value is ABCDE and the substring length is 3. // We produce the keys ABC BCD CDE. for (int first = 0, last = substrLength; last <= bytes.length; first++, last++) { set.add(makeSubstringKey(bytes, first, substrLength)); } EntryIDSet results = new EntryIDSet(); DatabaseEntry key = new DatabaseEntry(); for (byte[] keyBytes : set) { // Read the key. key.setData(keyBytes); EntryIDSet list = substringIndex.readKey(key, null, LockMode.DEFAULT); // Incorporate them into the results. results.retainAll(list); // We may have reached the point of diminishing returns where // it is quicker to stop now and process the current small number of // candidates. if (results.isDefined() && results.size() <= IndexFilter.FILTER_CANDIDATE_THRESHOLD) { 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. */ private EntryIDSet matchInitialSubstring(byte[] bytes) { // FIXME replace this code with SDK's // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery() // Iterate through all the keys that have this value as the prefix. // Set the lower bound for a range search. byte[] lower = bytes; // 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. byte[] upper = new byte[bytes.length]; System.arraycopy(bytes,0, upper, 0, bytes.length); for (int i = upper.length-1; i >= 0; i--) { if (upper[i] == 0xFF) { // We have to carry the overflow to the more significant byte. upper[i] = 0; } else { // No overflow, we can stop. upper[i] = (byte) (upper[i] + 1); break; } } // Read the range: lower <= keys < upper. return equalityIndex.readRange(lower, upper, true, false); } /** * Retrieve the entry IDs that might match an equality filter. @@ -776,62 +704,11 @@ StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { if (equalityIndex == null) { if(monitor.isFilterUseEnabled()) { monitor.updateStats(equalityFilter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("equality", indexConfig.getAttribute().getNameOrOID())); } return new EntryIDSet(); } try { // Make a key from the normalized assertion value. MatchingRule equalityRule = equalityFilter.getAttributeType(). getEqualityMatchingRule(); byte[] keyBytes = equalityRule.normalizeAssertionValue( equalityFilter.getAssertionValue()).toByteArray(); DatabaseEntry key = new DatabaseEntry(keyBytes); if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("equality]"); } // Read the key. EntryIDSet idSet = equalityIndex.readKey(key, null, LockMode.DEFAULT); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) { monitor.updateStats(equalityFilter, idSet.size()); } else if(!equalityIndex.isTrusted()) { monitor.updateStats(equalityFilter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( equalityIndex.getName())); } else if(equalityIndex.isRebuildRunning()) { monitor.updateStats(equalityFilter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( equalityIndex.getName())); } else { monitor.updateStats(equalityFilter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( equalityIndex.getName())); } } return idSet; try { final MatchingRule matchRule = equalityFilter.getAttributeType().getEqualityMatchingRule(); final IndexQuery indexQuery = matchRule.getAssertion(equalityFilter.getAssertionValue()) .createIndexQuery(indexQueryFactory); return evaluateIndexQuery(indexQuery, "equality", equalityFilter, debugBuffer, monitor); } catch (DecodeException e) { @@ -856,54 +733,8 @@ StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { if (presenceIndex == null) { if(monitor.isFilterUseEnabled()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("presence", indexConfig.getAttribute().getNameOrOID())); } return new EntryIDSet(); } if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("presence]"); } // Read the presence key EntryIDSet idSet = presenceIndex.readKey(presenceKey, null, LockMode.DEFAULT); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) { monitor.updateStats(filter, idSet.size()); } else if(!presenceIndex.isTrusted()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( presenceIndex.getName())); } else if(presenceIndex.isRebuildRunning()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( presenceIndex.getName())); } else { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( presenceIndex.getName())); } } return idSet; final IndexQuery indexQuery = indexQueryFactory.createMatchAllQuery(); return evaluateIndexQuery(indexQuery, "presence", filter, debugBuffer, monitor); } /** @@ -938,88 +769,22 @@ * @return The candidate entry IDs that might contain a value * less than or equal to the filter assertion value. */ public EntryIDSet evaluateLessOrEqualFilter(SearchFilter filter, StringBuilder debugBuffer, public EntryIDSet evaluateLessOrEqualFilter(SearchFilter filter, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { return evaluateOrderingFilter(filter, false, debugBuffer, monitor); } private EntryIDSet evaluateOrderingFilter(SearchFilter filter, boolean greater, StringBuilder debugBuffer, private EntryIDSet evaluateOrderingFilter(SearchFilter filter, boolean greater, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { if (orderingIndex == null) { if(monitor.isFilterUseEnabled()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("ordering", indexConfig.getAttribute().getNameOrOID())); } return new EntryIDSet(); } try { // Use the ordering matching rule to normalize the value. MatchingRule orderingRule = filter.getAttributeType().getOrderingMatchingRule(); byte[] normalizedValue = orderingRule.normalizeAssertionValue( filter.getAssertionValue()).toByteArray(); // Set the lower and upper bounds for a range search. byte[] lower; byte[] upper; if (greater) { // Set upper bound to 0 to search all keys greater than the lower bound. lower = normalizedValue; upper = new byte[0]; } else { // Set lower bound to 0 to start the range search from the smallest key. lower = new byte[0]; upper = normalizedValue; } if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("ordering]"); } // Read the range: lower <= keys < upper OR lower < keys <= upper EntryIDSet idSet = orderingIndex.readRange(lower, upper, greater, !greater); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) { monitor.updateStats(filter, idSet.size()); } else if(!orderingIndex.isTrusted()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( orderingIndex.getName())); } else if(orderingIndex.isRebuildRunning()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( orderingIndex.getName())); } else { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( orderingIndex.getName())); } } return idSet; try { final MatchingRule matchRule = filter.getAttributeType().getOrderingMatchingRule(); final Assertion assertion = greater ? matchRule.getGreaterOrEqualAssertion(filter.getAssertionValue()) : matchRule.getLessOrEqualAssertion(filter.getAssertionValue()); final IndexQuery indexQuery = assertion.createIndexQuery(indexQueryFactory); return evaluateIndexQuery(indexQuery, "ordering", filter, debugBuffer, monitor); } catch (DecodeException e) { @@ -1044,165 +809,12 @@ StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { SubstringMatchingRule matchRule = filter.getAttributeType().getSubstringMatchingRule(); try { ArrayList<ByteString> elements = new ArrayList<ByteString>(); EntryIDSet results = new EntryIDSet(); if (filter.getSubInitialElement() != null) { // Use the equality index for initial substrings if possible. if (equalityIndex != null && matchRule != null) { ByteString normValue = matchRule.normalizeSubstring(filter.getSubInitialElement()); byte[] normBytes = normValue.toByteArray(); EntryIDSet list = matchInitialSubstring(normBytes); results.retainAll(list); if (results.isDefined() && results.size() <= IndexFilter.FILTER_CANDIDATE_THRESHOLD) { if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute(). getNameOrOID()); debugBuffer.append("."); debugBuffer.append("equality]"); } if(monitor.isFilterUseEnabled()) { monitor.updateStats(filter, results.size()); } return results; } } else { elements.add(filter.getSubInitialElement()); } } if (substringIndex == null) { if(monitor.isFilterUseEnabled()) { if(!results.isDefined()) { if(filter.getSubInitialElement() != null) { if(equalityIndex == null) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("equality", indexConfig.getAttribute().getNameOrOID())); } else if(!equalityIndex.isTrusted()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( equalityIndex.getName())); } else if(equalityIndex.isRebuildRunning()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( equalityIndex.getName())); } else { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( equalityIndex.getName())); } } else { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("substring", indexConfig.getAttribute().getNameOrOID())); } } else { monitor.updateStats(filter, results.size()); } } return results; } // We do not distinguish between sub and final elements // in the substring index. Put all the elements into a single list. elements.addAll(filter.getSubAnyElements()); if (filter.getSubFinalElement() != null) { elements.add(filter.getSubFinalElement()); } // Iterate through each substring element. for (ByteString element : elements) { // Normalize the substring according to the substring matching rule. ByteString normValue = matchRule.normalizeSubstring(element); byte[] normBytes = normValue.toByteArray(); // Get the candidate entry IDs from the index. EntryIDSet list = matchSubstring(normBytes); // Incorporate them into the results. results.retainAll(list); // We may have reached the point of diminishing returns where // it is quicker to stop now and process the current small number of // candidates. if (results.isDefined() && results.size() <= IndexFilter.FILTER_CANDIDATE_THRESHOLD) { break; } } if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("substring]"); } if(monitor.isFilterUseEnabled()) { if(results.isDefined()) { monitor.updateStats(filter, results.size()); } else if(!substringIndex.isTrusted()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( substringIndex.getName())); } else if(substringIndex.isRebuildRunning()) { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( substringIndex.getName())); } else { monitor.updateStats(filter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( substringIndex.getName())); } } return results; try { final MatchingRule matchRule = filter.getAttributeType().getSubstringMatchingRule(); final IndexQuery indexQuery = matchRule.getSubstringAssertion( filter.getSubInitialElement(), filter.getSubAnyElements(), filter.getSubFinalElement()) .createIndexQuery(indexQueryFactory); return evaluateIndexQuery(indexQuery, "substring", filter, debugBuffer, monitor); } catch (DecodeException e) { @@ -1212,36 +824,41 @@ } /** * 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. * Retrieve the entry IDs that might match two filters that restrict a value * to both a lower bound and an upper bound. * * @param lowerValue The lower bound assertion value * @param upperValue The upper bound assertion value * @return The candidate entry IDs. * @param filter1 * The first filter, that is either a less-or-equal filter or a * greater-or-equal filter. * @param filter2 * The second filter, that is either a less-or-equal filter or a * greater-or-equal filter. It must not be of the same type than the * first 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 match both filters. */ public EntryIDSet evaluateBoundedRange(ByteString lowerValue, ByteString upperValue) public EntryIDSet evaluateBoundedRange(SearchFilter filter1, SearchFilter filter2, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { if (orderingIndex == null) { return new EntryIDSet(); } try { // Set the lower and upper bounds for a range search. MatchingRule orderingRule = getAttributeType().getOrderingMatchingRule(); byte[] lower = orderingRule.normalizeAssertionValue(lowerValue).toByteArray(); byte[] upper = orderingRule.normalizeAssertionValue(upperValue).toByteArray(); // Read the range: lower <= keys <= upper. return orderingIndex.readRange(lower, upper, true, true); } catch (DecodeException e) { logger.traceException(e); return new EntryIDSet(); } // TODO : this implementation is not optimal // as it implies two separate evaluations instead of a single one, // thus defeating the purpose of the optimisation done // in IndexFilter#evaluateLogicalAndFilter method. // One solution could be to implement a boundedRangeAssertion that combine // the two operations in one. EntryIDSet results = filter1.getFilterType() == FilterType.LESS_OR_EQUAL ? evaluateLessOrEqualFilter(filter1, debugBuffer, monitor) : evaluateGreaterOrEqualFilter(filter1, debugBuffer, monitor); EntryIDSet results2 = filter2.getFilterType() == FilterType.LESS_OR_EQUAL ? evaluateLessOrEqualFilter(filter2, debugBuffer, monitor) : evaluateGreaterOrEqualFilter(filter2, debugBuffer, monitor); results.retainAll(results2); return results; } /** @@ -1356,66 +973,14 @@ * @return The candidate entry IDs that might contain the filter * assertion value. */ public EntryIDSet evaluateApproximateFilter(SearchFilter approximateFilter, StringBuilder debugBuffer, public EntryIDSet evaluateApproximateFilter(SearchFilter approximateFilter, StringBuilder debugBuffer, DatabaseEnvironmentMonitor monitor) { if (approximateIndex == null) { if(monitor.isFilterUseEnabled()) { monitor.updateStats(approximateFilter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("approximate", indexConfig.getAttribute().getNameOrOID())); } return new EntryIDSet(); } try { MatchingRule approximateMatchingRule = approximateFilter.getAttributeType().getApproximateMatchingRule(); // Make a key from the normalized assertion value. byte[] keyBytes = approximateMatchingRule.normalizeAssertionValue( approximateFilter.getAssertionValue()).toByteArray(); DatabaseEntry key = new DatabaseEntry(keyBytes); if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("approximate]"); } // Read the key. EntryIDSet idSet = approximateIndex.readKey(key, null, LockMode.DEFAULT); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) { monitor.updateStats(approximateFilter, idSet.size()); } else if(!approximateIndex.isTrusted()) { monitor.updateStats(approximateFilter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( approximateIndex.getName())); } else if(approximateIndex.isRebuildRunning()) { monitor.updateStats(approximateFilter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( approximateIndex.getName())); } else { monitor.updateStats(approximateFilter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( approximateIndex.getName())); } } return idSet; try { MatchingRule matchRule = approximateFilter.getAttributeType().getApproximateMatchingRule(); IndexQuery indexQuery = matchRule.getAssertion(approximateFilter.getAssertionValue()) .createIndexQuery(indexQueryFactory); return evaluateIndexQuery(indexQuery, "approximate", approximateFilter, debugBuffer, monitor); } catch (DecodeException e) { @@ -1609,8 +1174,7 @@ try { AttributeType attrType = cfg.getAttribute(); String name = entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); String name = entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); final int indexEntryLimit = cfg.getIndexEntryLimit(); final JEIndexConfig config = new JEIndexConfig(cfg.getSubstringLength()); @@ -1620,6 +1184,7 @@ { equalityIndex = openNewIndex(name, attrType, new EqualityIndexer(attrType), adminActionRequired, messages); nameToIndexes.put(LocalDBIndexCfgDefn.IndexType.EQUALITY.toString(), equalityIndex); } else { @@ -1627,8 +1192,7 @@ if(this.equalityIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(equalityIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(equalityIndex.getName())); this.equalityIndex.setIndexEntryLimit(indexEntryLimit); } } @@ -1640,6 +1204,7 @@ entryContainer.exclusiveLock.lock(); try { nameToIndexes.remove(LocalDBIndexCfgDefn.IndexType.EQUALITY.toString()); entryContainer.deleteDatabase(equalityIndex); equalityIndex = null; } @@ -1657,6 +1222,7 @@ Indexer presenceIndexer = new PresenceIndexer(attrType); presenceIndex = newIndex(name + ".presence", presenceIndexer, indexEntryLimit); openIndex(presenceIndex, adminActionRequired, messages); nameToIndexes.put(LocalDBIndexCfgDefn.IndexType.PRESENCE.toString(), presenceIndex); } else { @@ -1664,8 +1230,7 @@ if(this.presenceIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(presenceIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(presenceIndex.getName())); } } } @@ -1676,6 +1241,7 @@ entryContainer.exclusiveLock.lock(); try { nameToIndexes.remove(LocalDBIndexCfgDefn.IndexType.PRESENCE.toString()); entryContainer.deleteDatabase(presenceIndex); presenceIndex = null; } @@ -1695,6 +1261,7 @@ Index index = newIndex(name + "." + indexer.getExtensibleIndexID(), extIndexer, indexEntryLimit); substringIndex = openIndex(index, adminActionRequired, messages); nameToIndexes.put(LocalDBIndexCfgDefn.IndexType.SUBSTRING.toString(), substringIndex); } else { @@ -1702,8 +1269,7 @@ if(this.substringIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(substringIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(substringIndex.getName())); } if (indexConfig.getSubstringLength() != cfg.getSubstringLength()) @@ -1719,6 +1285,7 @@ entryContainer.exclusiveLock.lock(); try { nameToIndexes.remove(LocalDBIndexCfgDefn.IndexType.SUBSTRING.toString()); entryContainer.deleteDatabase(substringIndex); substringIndex = null; } @@ -1735,6 +1302,7 @@ { orderingIndex = openNewIndex(name, attrType, new OrderingIndexer(attrType), adminActionRequired, messages); nameToIndexes.put(LocalDBIndexCfgDefn.IndexType.ORDERING.toString(), orderingIndex); } else { @@ -1742,8 +1310,7 @@ if(this.orderingIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(orderingIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(orderingIndex.getName())); } } } @@ -1754,6 +1321,7 @@ entryContainer.exclusiveLock.lock(); try { nameToIndexes.remove(LocalDBIndexCfgDefn.IndexType.ORDERING.toString()); entryContainer.deleteDatabase(orderingIndex); orderingIndex = null; } @@ -1764,13 +1332,13 @@ } } if (cfg.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.APPROXIMATE)) if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.APPROXIMATE)) { if(approximateIndex == null) { approximateIndex = openNewIndex(name, attrType, new ApproximateIndexer(attrType), adminActionRequired, messages); nameToIndexes.put(LocalDBIndexCfgDefn.IndexType.APPROXIMATE.toString(), approximateIndex); } else { @@ -1778,8 +1346,7 @@ if(this.approximateIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(approximateIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(approximateIndex.getName())); } } } @@ -1790,6 +1357,7 @@ entryContainer.exclusiveLock.lock(); try { nameToIndexes.remove(LocalDBIndexCfgDefn.IndexType.APPROXIMATE.toString()); entryContainer.deleteDatabase(approximateIndex); approximateIndex = null; } @@ -1800,21 +1368,17 @@ } } if (cfg.getIndexType().contains( LocalDBIndexCfgDefn.IndexType.EXTENSIBLE)) if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.EXTENSIBLE)) { Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule(); Set<ExtensibleMatchingRule> validRules = new HashSet<ExtensibleMatchingRule>(); Set<String> extensibleRules = cfg.getIndexExtensibleMatchingRule(); Set<ExtensibleMatchingRule> validRules = new HashSet<ExtensibleMatchingRule>(); if(extensibleIndexes == null) { extensibleIndexes = new ExtensibleMatchingRuleIndex(); } for(String ruleName:extensibleRules) { ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(toLowerCase(ruleName)); ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(toLowerCase(ruleName)); if(rule == null) { logger.error(ERR_CONFIG_INDEX_TYPE_NEEDS_VALID_MATCHING_RULE, attrType, ruleName); @@ -1838,8 +1402,7 @@ if(extensibleIndex.setIndexEntryLimit(indexEntryLimit)) { adminActionRequired.set(true); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD .get(extensibleIndex.getName())); messages.add(NOTE_JEB_CONFIG_INDEX_ENTRY_LIMIT_REQUIRES_REBUILD.get(extensibleIndex.getName())); } if (indexConfig.getSubstringLength() != cfg.getSubstringLength()) { @@ -1850,8 +1413,7 @@ extensibleIndexes.addRule(indexID, rule); indexMap.put(indexer.getExtensibleIndexID(), extensibleIndexes.getIndex(indexID)); } final IndexQueryFactory<IndexQuery> factory = new IndexQueryFactoryImpl(indexMap, config); IndexQueryFactory<IndexQuery> factory = new IndexQueryFactoryImpl(indexMap, config); extensibleIndexes.addQueryFactory(rule, factory); } //Some rules might have been removed from the configuration. @@ -1928,8 +1490,7 @@ indexConfig = cfg; return new ConfigChangeResult( ResultCode.SUCCESS, adminActionRequired.get(), messages); return new ConfigChangeResult(ResultCode.SUCCESS, adminActionRequired.get(), messages); } catch(Exception e) { @@ -2168,94 +1729,30 @@ DatabaseEnvironmentMonitor monitor) { //Get the Matching Rule OID of the filter. String nOID = extensibleFilter.getMatchingRuleID(); String matchRuleOID = extensibleFilter.getMatchingRuleID(); /** * 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. */ MatchingRule eqRule = indexConfig.getAttribute().getEqualityMatchingRule(); if (nOID == null || nOID.equals(eqRule.getOID()) || nOID.equalsIgnoreCase(eqRule.getNameOrOID())) MatchingRule eqRule = indexConfig.getAttribute().getEqualityMatchingRule(); if (matchRuleOID == null || matchRuleOID.equals(eqRule.getOID()) || matchRuleOID.equalsIgnoreCase(eqRule.getNameOrOID())) { //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()) { monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get("equality", indexConfig.getAttribute().getNameOrOID())); } return IndexQuery.createNullIndexQuery().evaluate(null); } try { // Make a key from the normalized assertion value. MatchingRule rule = extensibleFilter.getAttributeType().getEqualityMatchingRule(); ByteString value = extensibleFilter.getAssertionValue(); byte[] keyBytes = rule.normalizeAssertionValue(value).toByteArray(); DatabaseEntry key = new DatabaseEntry(keyBytes); if(debugBuffer != null) { debugBuffer.append("[INDEX:"); debugBuffer.append(indexConfig.getAttribute().getNameOrOID()); debugBuffer.append("."); debugBuffer.append("equality]"); return evaluateEqualityFilter(extensibleFilter, debugBuffer, monitor); } // Read the key. EntryIDSet idSet = equalityIndex.readKey(key, null, LockMode.DEFAULT); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) { monitor.updateStats(extensibleFilter, idSet.size()); } else if(!equalityIndex.isTrusted()) { monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( equalityIndex.getName())); } else if(equalityIndex.isRebuildRunning()) { monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( equalityIndex.getName())); } else { monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( equalityIndex.getName())); } } return idSet; } catch (DecodeException e) { logger.traceException(e); return IndexQuery.createNullIndexQuery().evaluate(null); } } ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(nOID); ExtensibleMatchingRule rule = DirectoryServer.getExtensibleMatchingRule(matchRuleOID); IndexQueryFactory<IndexQuery> factory = null; if(extensibleIndexes == null || (factory = extensibleIndexes.getQueryFactory(rule))==null) if (extensibleIndexes == null || (factory = extensibleIndexes.getQueryFactory(rule)) == null) { // There is no index on this matching rule. if(monitor.isFilterUseEnabled()) { monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_MATCHING_RULE_NOT_INDEXED.get(nOID, indexConfig.getAttribute().getNameOrOID())); monitor.updateStats(extensibleFilter, INFO_JEB_INDEX_FILTER_MATCHING_RULE_NOT_INDEXED.get( matchRuleOID, indexConfig.getAttribute().getNameOrOID())); } return IndexQuery.createNullIndexQuery().evaluate(null); } @@ -2276,9 +1773,8 @@ } ByteString assertionValue = extensibleFilter.getAssertionValue(); IndexQuery expression = rule.createIndexQuery(assertionValue, factory); List<LocalizableMessage> debugMessages = monitor.isFilterUseEnabled() ? new ArrayList<LocalizableMessage>() : null; EntryIDSet idSet = expression.evaluate(debugMessages); LocalizableMessageBuilder debugMessage = monitor.isFilterUseEnabled() ? new LocalizableMessageBuilder() : null; EntryIDSet idSet = expression.evaluate(debugMessage); if(monitor.isFilterUseEnabled()) { if(idSet.isDefined()) @@ -2287,14 +1783,7 @@ } else { if(debugMessages != null && !debugMessages.isEmpty()) { monitor.updateStats(extensibleFilter, debugMessages.get(0)); } else { monitor.updateStats(extensibleFilter, LocalizableMessage.EMPTY); } monitor.updateStats(extensibleFilter, debugMessage.toMessage()); } } return idSet; opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexFilter.java
@@ -22,7 +22,7 @@ * * * Copyright 2006-2010 Sun Microsystems, Inc. * Portions copyright 2011 ForgeRock AS * Portions copyright 2011-2014 ForgeRock AS * */ package org.opends.server.backends.jeb; @@ -298,11 +298,10 @@ ArrayList<SearchFilter> rangeList = rangeEntry.getValue(); if (rangeList.size() == 2) { SearchFilter a = rangeList.get(0); SearchFilter b = rangeList.get(1); SearchFilter filter1 = rangeList.get(0); SearchFilter filter2 = rangeList.get(1); AttributeIndex attributeIndex = entryContainer.getAttributeIndex(rangeEntry.getKey()); AttributeIndex attributeIndex = entryContainer.getAttributeIndex(rangeEntry.getKey()); if (attributeIndex == null) { if(monitor.isFilterUseEnabled()) @@ -313,47 +312,11 @@ } continue; } EntryIDSet set = attributeIndex.evaluateBoundedRange(filter1, filter2, buffer, monitor); if (a.getFilterType() == FilterType.GREATER_OR_EQUAL && b.getFilterType() == FilterType.LESS_OR_EQUAL) if(monitor.isFilterUseEnabled() && set.isDefined()) { // Like (cn>=A)(cn<=B). EntryIDSet set; set = attributeIndex.evaluateBoundedRange(a.getAssertionValue(), b.getAssertionValue()); if (buffer != null) { a.toString(buffer); b.toString(buffer); set.toString(buffer); } if(monitor.isFilterUseEnabled()) { if(set.isDefined()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), set.size()); } else if(!attributeIndex.orderingIndex.isTrusted()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( attributeIndex.orderingIndex.getName())); } else if(attributeIndex.orderingIndex.isRebuildRunning()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( attributeIndex.orderingIndex.getName())); } else { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( attributeIndex.orderingIndex.getName())); } monitor.updateStats(SearchFilter.createANDFilter(rangeList), set.size()); } if (retainAll(results, set)) @@ -362,56 +325,6 @@ } continue; } else if (a.getFilterType() == FilterType.LESS_OR_EQUAL && b.getFilterType() == FilterType.GREATER_OR_EQUAL) { // Like (cn<=A)(cn>=B). EntryIDSet set; set = attributeIndex.evaluateBoundedRange(b.getAssertionValue(), a.getAssertionValue()); if (buffer != null) { a.toString(buffer); b.toString(buffer); set.toString(buffer); } if(monitor.isFilterUseEnabled()) { if(set.isDefined()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), set.size()); } else if(!attributeIndex.orderingIndex.isTrusted()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( attributeIndex.orderingIndex.getName())); } else if(attributeIndex.orderingIndex.isRebuildRunning()) { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( attributeIndex.orderingIndex.getName())); } else { monitor.updateStats(SearchFilter.createANDFilter(rangeList), INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( attributeIndex.orderingIndex.getName())); } } if (retainAll(results, set)) { return results; } continue; } } // Add to the remaining range components to be processed. for (SearchFilter filter : rangeList) opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQuery.java
@@ -29,10 +29,9 @@ import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import java.util.Collection; import java.util.List; import static org.opends.server.backends.jeb.IndexFilter.*; @@ -51,12 +50,12 @@ /** * Evaluates the index query and returns the EntryIDSet. * * @param debugMessages If not null, diagnostic messages will be written * @param debugMessage If not null, diagnostic message will be written * which will help to determine why the returned * EntryIDSet is not defined. * @return The EntryIDSet as a result of evaulation of this query. * @return The EntryIDSet as a result of evaluation of this query. */ public abstract EntryIDSet evaluate(List<LocalizableMessage> debugMessages); public abstract EntryIDSet evaluate(LocalizableMessageBuilder debugMessage); @@ -117,7 +116,7 @@ * @param debugMessages */ @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { return new EntryIDSet(); } @@ -154,18 +153,18 @@ * @param debugMessages */ @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { EntryIDSet entryIDs = null; for (IndexQuery query : subIndexQueries) { if (entryIDs == null) { entryIDs = query.evaluate(debugMessages); entryIDs = query.evaluate(debugMessage); } else { entryIDs.retainAll(query.evaluate(debugMessages)); entryIDs.retainAll(query.evaluate(debugMessage)); } if (entryIDs.isDefined() && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD) @@ -207,18 +206,18 @@ * @param debugMessages */ @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { EntryIDSet entryIDs = null; for (IndexQuery query : subIndexQueries) { if (entryIDs == null) { entryIDs = query.evaluate(debugMessages); entryIDs = query.evaluate(debugMessage); } else { entryIDs.addAll(query.evaluate(debugMessages)); entryIDs.addAll(query.evaluate(debugMessage)); } if (entryIDs.isDefined() && entryIDs.size() <= FILTER_CANDIDATE_THRESHOLD) opendj-sdk/opendj3-server-dev/src/server/org/opends/server/backends/jeb/IndexQueryFactoryImpl.java
@@ -27,10 +27,9 @@ package org.opends.server.backends.jeb; import java.util.Collection; import java.util.List; import java.util.Map; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageBuilder; import org.forgerock.opendj.ldap.ByteSequence; import org.forgerock.opendj.ldap.spi.IndexQueryFactory; import org.forgerock.opendj.ldap.spi.IndexingOptions; @@ -48,6 +47,8 @@ IndexQueryFactory<IndexQuery> { private static final String PRESENCE_INDEX_KEY = "presence"; /** * The Map containing the string type identifier and the corresponding index. */ @@ -79,34 +80,35 @@ { @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { // Read the database and get Record for the key. DatabaseEntry key = new DatabaseEntry(value.toByteArray()); // Select the right index to be used. Index index = indexMap.get(indexID); EntryIDSet entrySet = index.readKey(key, null, LockMode.DEFAULT); if(debugMessages != null && !entrySet.isDefined()) if (index == null) { if(debugMessage != null) { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get(indexID, "")); } return createMatchAllQuery().evaluate(debugMessage); } EntryIDSet entrySet = index.readKey(key, null, LockMode.DEFAULT); if(debugMessage != null && !entrySet.isDefined()) { if(!index.isTrusted()) { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get(index.getName())); } else if(index.isRebuildRunning()) { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get(index.getName())); } else { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get(index.getName())); } } return entrySet; @@ -126,32 +128,33 @@ { @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { // Find the right index. Index index = indexMap.get(indexID); EntryIDSet entrySet = index.readRange(lowerBound.toByteArray(), upperBound .toByteArray(), includeLowerBound, includeUpperBound); if(debugMessages != null && !entrySet.isDefined()) if (index == null) { if(debugMessage != null) { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get(indexID, "")); } return createMatchAllQuery().evaluate(debugMessage); } EntryIDSet entrySet = index.readRange(lowerBound.toByteArray(), upperBound.toByteArray(), includeLowerBound, includeUpperBound); if(debugMessage != null && !entrySet.isDefined()) { if(!index.isTrusted()) { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get(index.getName())); } else if(index.isRebuildRunning()) { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get(index.getName())); } else { debugMessages.add( INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get( index.getName())); debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get(index.getName())); } } return entrySet; @@ -191,12 +194,39 @@ { return new IndexQuery() { @Override public EntryIDSet evaluate(List<LocalizableMessage> debugMessages) public EntryIDSet evaluate(LocalizableMessageBuilder debugMessage) { Index index = indexMap.get(PRESENCE_INDEX_KEY); if (index == null) { if(debugMessage != null) { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_TYPE_DISABLED.get(index.getName(), "")); } return new EntryIDSet(); } EntryIDSet entrySet = index.readKey(AttributeIndex.presenceKey, null, LockMode.DEFAULT); if (debugMessage != null && !entrySet.isDefined()) { if (!index.isTrusted()) { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED.get(index.getName())); } else if (index.isRebuildRunning()) { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS.get(index.getName())); } else { debugMessage.append(INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED.get(index.getName())); } } return entrySet; } }; } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/AbstractOrderingMatchingRule.java
@@ -28,8 +28,8 @@ import java.util.Comparator; import org.forgerock.opendj.ldap.*; import org.forgerock.opendj.ldap.spi.IndexQueryFactory; import org.opends.server.api.AbstractMatchingRule; import org.opends.server.api.NotImplementedAssertion; import org.opends.server.api.OrderingMatchingRule; /** @@ -57,46 +57,61 @@ /** {@inheritDoc} */ @Override public Assertion getAssertion(final ByteSequence value) throws DecodeException public Assertion getAssertion(final ByteSequence assertionValue) throws DecodeException { final ByteString assertionValue = normalizeAssertionValue(value); return new NotImplementedAssertion() final ByteString normAssertionValue = normalizeAttributeValue(assertionValue); return new Assertion() { @Override public ConditionResult matches(ByteSequence attributeValue) public ConditionResult matches(final ByteSequence attributeValue) { return ConditionResult.valueOf(compareValues(attributeValue, assertionValue) < 0); return ConditionResult.valueOf(compareValues(attributeValue, normAssertionValue) < 0); } @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return factory.createRangeMatchQuery("ordering", ByteString.empty(), normAssertionValue, false, false); } }; } /** {@inheritDoc} */ @Override public Assertion getGreaterOrEqualAssertion(ByteSequence value) throws DecodeException public Assertion getGreaterOrEqualAssertion(final ByteSequence assertionValue) throws DecodeException { final ByteString normAssertion = normalizeAssertionValue(value); return new NotImplementedAssertion() final ByteString normAssertionValue = normalizeAttributeValue(assertionValue); return new Assertion() { @Override public ConditionResult matches(final ByteSequence normalizedAttributeValue) { return ConditionResult.valueOf(compareValues(normalizedAttributeValue, normAssertion) >= 0); public ConditionResult matches(final ByteSequence normalizedAttributeValue) { return ConditionResult.valueOf(compareValues(normalizedAttributeValue, normAssertionValue) >= 0); } @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return factory.createRangeMatchQuery("ordering", normAssertionValue, ByteString.empty(), true, false); } }; } /** {@inheritDoc} */ @Override public Assertion getLessOrEqualAssertion(ByteSequence value) throws DecodeException public Assertion getLessOrEqualAssertion(final ByteSequence assertionValue) throws DecodeException { final ByteString normAssertion = normalizeAssertionValue(value); return new NotImplementedAssertion() final ByteString normAssertionValue = normalizeAttributeValue(assertionValue); return new Assertion() { @Override public ConditionResult matches(final ByteSequence normalizedAttributeValue) { return ConditionResult.valueOf(compareValues(normalizedAttributeValue, normAssertion) <= 0); return ConditionResult.valueOf(compareValues(normalizedAttributeValue, normAssertionValue) <= 0); } @Override public <T> T createIndexQuery(IndexQueryFactory<T> factory) throws DecodeException { return factory.createRangeMatchQuery("ordering", ByteString.empty(), normAssertionValue, false, true); } }; } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/schema/CertificateExactMatchingRule.java
@@ -42,6 +42,7 @@ import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.ldap.Assertion; import org.forgerock.opendj.ldap.ByteSequence; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ByteStringBuilder; @@ -369,5 +370,13 @@ return builder.toByteString(); } /** {@inheritDoc} */ @Override public Assertion getAssertion(ByteSequence assertionValue) throws DecodeException { final ByteString normAssertionValue = normalizeAssertionValue(assertionValue); return getEqualityAssertion(normAssertionValue); } } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/types/SearchFilter.java
@@ -42,7 +42,6 @@ import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.ByteStringBuilder; import org.forgerock.opendj.ldap.ConditionResult; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.api.MatchingRule; import org.opends.server.api.SubstringMatchingRule; @@ -2146,42 +2145,6 @@ return assertionValue; } private ByteString getNormalizedAssertionValue() throws DecodeException { if (normalizedAssertionValue == null) { return normalizedAssertionValue = normalizeAssertionValue(); } return normalizedAssertionValue; } private ByteString normalizeAssertionValue() throws DecodeException { switch (filterType) { case EQUALITY: return attributeType.getEqualityMatchingRule() .normalizeAssertionValue(assertionValue); case GREATER_OR_EQUAL: case LESS_OR_EQUAL: return attributeType.getOrderingMatchingRule() .normalizeAssertionValue(assertionValue); case APPROXIMATE_MATCH: return attributeType.getApproximateMatchingRule() .normalizeAssertionValue(assertionValue); case AND: case OR: case NOT: case PRESENT: case SUBSTRING: case EXTENSIBLE_MATCH: default: return null; } } /** * Retrieves the subInitial element for this substring filter. * @@ -3610,7 +3573,7 @@ case APPROXIMATE_MATCH: return typeAndOptionsAndAssertionEqual(f); case EXTENSIBLE_MATCH: return equalsExtensible(f); return extensibleEqual(f); default: return false; } @@ -3641,23 +3604,15 @@ private boolean typeAndOptionsAndAssertionEqual(SearchFilter f) { final boolean tmp = attributeType.equals(f.attributeType) && optionsEqual(attributeOptions, f.attributeOptions); try { return tmp && getNormalizedAssertionValue().equals(f.getNormalizedAssertionValue()); } catch (DecodeException e) { return tmp && assertionValue.equals(f.assertionValue); } return attributeType.equals(f.attributeType) && optionsEqual(attributeOptions, f.attributeOptions) && assertionValue.equals(f.assertionValue); } private boolean substringEqual(SearchFilter f) private boolean substringEqual(SearchFilter other) { if (! attributeType.equals(f.attributeType)) if (! attributeType.equals(other.attributeType)) { return false; } @@ -3667,20 +3622,43 @@ { return false; } try if (! optionsEqual(attributeOptions, other.attributeOptions)) { Assertion thisAssertion = rule.getSubstringAssertion(subInitialElement, subAnyElements, subFinalElement); Assertion thatAssertion = rule.getSubstringAssertion(f.subInitialElement, f.subAnyElements, f.subFinalElement); return thisAssertion.equals(thatAssertion); return false; } catch (DecodeException e) boolean initialCheck = subInitialElement == null ? other.subInitialElement == null : subInitialElement.equals(other.subInitialElement); if (!initialCheck) { return false; } boolean finalCheck = subFinalElement == null ? other.subFinalElement == null : subFinalElement.equals(other.subFinalElement); if (!finalCheck) { return false; } boolean anyCheck = subAnyElements == null ? other.subAnyElements == null : subAnyElements.size() == other.subAnyElements.size(); if (!anyCheck) { return false; } if (subAnyElements != null) { for (int i = 0; i < subAnyElements.size(); i++) { if (! subAnyElements.get(i).equals(other.subAnyElements.get(i))) { return false; } } } return true; } private boolean equalsExtensible(SearchFilter f) private boolean extensibleEqual(SearchFilter f) { if (attributeType == null) { @@ -3886,41 +3864,28 @@ private int typeAndAssertionHashCode() { final int hashCode = attributeType.hashCode(); try { return hashCode + getNormalizedAssertionValue().hashCode(); } catch (DecodeException e) { return hashCode + assertionValue.hashCode(); } return attributeType.hashCode() + assertionValue.hashCode(); } /** Returns hash code to use for substring filter. */ private int substringHashCode() { int hashCode = attributeType.hashCode(); final MatchingRule rule = attributeType.getSubstringMatchingRule(); if (rule != null) if (subInitialElement != null) { try { return hashCode + rule.getSubstringAssertion(subInitialElement, subAnyElements, subFinalElement).hashCode(); } catch (DecodeException e) { logger.traceException(e); } } // Fallback to hash code based on elements hashCode += subInitialElement.hashCode(); } if (subAnyElements != null) { for (ByteString e : subAnyElements) { hashCode += e.hashCode(); } } if (subFinalElement != null) { hashCode += subFinalElement.hashCode(); } return hashCode; } opendj-sdk/opendj3-server-dev/src/server/org/opends/server/workflowelement/externalchangelog/ECLSearchOperation.java
@@ -32,12 +32,10 @@ import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.ModificationType; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.SearchScope; import org.opends.server.api.ClientConnection; import org.opends.server.api.MatchingRule; import org.opends.server.api.plugin.PluginResult; import org.opends.server.config.ConfigConstants; import org.opends.server.controls.*; @@ -1247,17 +1245,7 @@ private static int extractChangeNumber(SearchFilter sf) throws DirectoryException { try { MatchingRule rule = sf.getAttributeType().getEqualityMatchingRule(); ByteString normValue = rule.normalizeAssertionValue(sf.getAssertionValue()); return Integer.decode(normValue.toString()); } catch (DecodeException e) { throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, e .getMessageObject(), e); } return Integer.decode(sf.getAssertionValue().toString()); } private static boolean matches(SearchFilter sf, FilterType filterType, opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/backends/jeb/TestBackendImpl.java
@@ -47,12 +47,6 @@ import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.ldap.LDAPFilter; import org.opends.server.types.*; import org.opends.server.types.Attribute; import org.opends.server.types.Attributes; import org.opends.server.types.DN; import org.opends.server.types.Entry; import org.opends.server.types.Modification; import org.opends.server.types.RDN; import org.opends.server.util.Base64; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -647,15 +641,75 @@ @Test(dependsOnMethods = "testAdd") public void testSearchIndex() throws Exception { InternalClientConnection conn = InternalClientConnection.getRootConnection(); InternalClientConnection conn = InternalClientConnection.getRootConnection(); Set<String> attribs = new LinkedHashSet<String>(); String debugString; int finalStartPos; int finalEndPos; int finalCount; List<SearchResultEntry> result; // search 1 result = doSubtreeSearch(conn, "(&(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs); assertEquals(result.size(), 0); // Adding a debug search attribute for next searches attribs.add(ATTR_DEBUG_SEARCH_INDEX); // search 2 result = doSubtreeSearch(conn, "(&(cn=Aaccf Amar)(employeeNumber=222))", attribs); // Only one index should be used because it is below the FILTER_CANDIDATE debugString = getDebugString(result); assertTrue(debugString.split("cn").length <= 3); assertResultsCountIs(1, debugString); // search 3 result = doSubtreeSearch(conn, "(|(cn=Aaccf Amar)(cn=Ardyth Bainton))", attribs); debugString = getDebugString(result); assertFalse(debugString.contains("NOT-INDEXED")); assertResultsCountIs(2, debugString); // search 4 result = doSubtreeSearch(conn, "(&(employeeNumber=*)(cn=A*)(employeeNumber>=0)(employeeNumber<=z))", attribs); debugString = getDebugString(result); assertFalse(debugString.contains("NOT-INDEXED")); assertResultsCountIs(12, debugString); // search 5 result = doSubtreeSearch(conn, "(&(employeeNumber<=z)(cn<=Abbey Abbie)(cn>=0)(|(cn>=Abahri Abazari)(employeeNumber<=9)))", attribs); debugString = getDebugString(result); assertFalse(debugString.contains("NOT-INDEXED")); assertResultsCountIs(11, debugString); // search 6 result = doSubtreeSearch(conn, "(cn~=Aartjan)", attribs); debugString = getDebugString(result); assertFalse(debugString.contains("NOT-INDEXED")); assertResultsCountIs(1, debugString); } private void assertResultsCountIs(int expectedCount, String debugString) { int finalStartPos = debugString.indexOf("final=") + 13; int finalEndPos = debugString.indexOf("]", finalStartPos); int finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, expectedCount); } /** Returns the debug string from a search result. */ private String getDebugString(List<SearchResultEntry> result) { return result.get(0).getAttribute("debugsearchindex").get(0).toString(); } /** Returns the results of subtree search on provided connection with provided filter. */ private List<SearchResultEntry> doSubtreeSearch(InternalClientConnection conn, String filter, Set<String> attribs) throws Exception { InternalSearchOperation search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, @@ -663,111 +717,9 @@ 0, 0, false, LDAPFilter.decode("(&(cn=Aaccf Amar)(cn=Ardyth Bainton))").toSearchFilter(), LDAPFilter.decode(filter).toSearchFilter(), attribs); List<SearchResultEntry> result = search.getSearchEntries(); assertEquals(result.size(), 0); attribs.add(ATTR_DEBUG_SEARCH_INDEX); search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(&(cn=Aaccf Amar)(employeeNumber=222))").toSearchFilter(), attribs); result = search.getSearchEntries(); //Only one index should be used because it is below the FILTER_CANDIDATEassertEquals(ec.getDN2URI().)_THRESHOLD. debugString = result.get(0).getAttribute("debugsearchindex").get(0).toString(); assertTrue(debugString.split("cn").length <= 3); finalStartPos = debugString.indexOf("final=") + 13; finalEndPos = debugString.indexOf("]", finalStartPos); finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, 1); search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(|(cn=Aaccf Amar)(cn=Ardyth Bainton))").toSearchFilter(), attribs); result = search.getSearchEntries(); debugString = result.get(0).getAttribute("debugsearchindex").get(0).toString(); assertTrue(!debugString.contains("NOT-INDEXED")); finalStartPos = debugString.indexOf("final=") + 13; finalEndPos = debugString.indexOf("]", finalStartPos); finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, 2); search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(&(employeeNumber=*)(cn=A*)(employeeNumber>=0)(employeeNumber<=z))").toSearchFilter(), attribs); result = search.getSearchEntries(); debugString = result.get(0).getAttribute("debugsearchindex").get(0).toString(); assertTrue(!debugString.contains("NOT-INDEXED")); finalStartPos = debugString.indexOf("final=") + 13; finalEndPos = debugString.indexOf("]", finalStartPos); finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, 12); search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(&(employeeNumber<=z)(cn<=Abbey Abbie)(cn>=0)(|(cn>=Abahri Abazari)(employeeNumber<=9)))").toSearchFilter(), attribs); result = search.getSearchEntries(); debugString = result.get(0).getAttribute("debugsearchindex").get(0).toString(); assertTrue(!debugString.contains("NOT-INDEXED")); finalStartPos = debugString.indexOf("final=") + 13; finalEndPos = debugString.indexOf("]", finalStartPos); finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, 11); search = conn.processSearch(DN.valueOf("dc=test,dc=com"), SearchScope.WHOLE_SUBTREE, DereferenceAliasesPolicy.NEVER, 0, 0, false, LDAPFilter.decode("(cn~=Aartjan)").toSearchFilter(), attribs); result = search.getSearchEntries(); debugString = result.get(0).getAttribute("debugsearchindex").get(0).toString(); assertTrue(!debugString.contains("NOT-INDEXED")); finalStartPos = debugString.indexOf("final=") + 13; finalEndPos = debugString.indexOf("]", finalStartPos); finalCount = Integer.valueOf(debugString.substring(finalStartPos, finalEndPos)); assertEquals(finalCount, 1); return search.getSearchEntries(); } @Test(dependsOnMethods = {"testAdd", "testSearchIndex", opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/types/SearchFilterTests.java
@@ -918,9 +918,12 @@ // These should be case insensitive {"(SN=Smith)", "(sn=Smith)", true, true}, {"(sn=smith)", "(sn=Smith)", true, false}, {"(SN=S*th)", "(sn=S*th)", true, true}, // We no longer normalize assertion values, // so these filters are not equal {"(sn=smith)", "(sn=Smith)", false, false}, {"(sn:caseExactMatch:=Smith)", "(sn:caseExactMatch:=Smith)", true, true}, // This demonstrates bug 704. @@ -939,8 +942,10 @@ {"(sn;lang-en=Smith)", "(sn=Smith)", false, false}, // This demonstrates bug 705. {"(sn=s*t*h)", "(sn=S*T*H)", true, false}, // This was initially to demonstrates bug 705. // But we reverted back to old behavior, // because we no longer normalize assertion values. {"(sn=s*t*h)", "(sn=S*T*H)", false, false}, // These should be case sensitive {"(labeledURI=http://opends.org)", "(labeledURI=http://OpenDS.org)", false, false},