| | |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.HashSet; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.schema.Schema; |
| | | import org.forgerock.opendj.ldap.spi.Indexer; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.types.AttributeValue; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class is registered with a Backend and it provides call- backs |
| | | * for indexing attribute values. An index implementation will use |
| | |
| | | mayInstantiate = false, |
| | | mayExtend = true, |
| | | mayInvoke = false) |
| | | public abstract class ExtensibleIndexer |
| | | public abstract class ExtensibleIndexer implements Indexer |
| | | { |
| | | /** |
| | | * Returns the index name preferred by this indexer. This name |
| | | * appended with the identifier returned from |
| | | * {@link #getExtensibleIndexID()} will be used as the index |
| | | * database name. |
| | | * |
| | | * @return The name of the index for this indexer. |
| | | */ |
| | | public abstract String getPreferredIndexName(); |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns an index identifier associated with this indexer. An |
| | |
| | | * @param keys |
| | | * The set into which the generated keys will be inserted. |
| | | */ |
| | | public abstract void getKeys(AttributeValue value, |
| | | Set<byte[]> keys); |
| | | public abstract void getKeys(AttributeValue value, Set<byte[]> keys); |
| | | |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void createKeys(Schema schema, ByteSequence value, |
| | | IndexingOptions options, Collection<ByteString> keys) |
| | | throws DecodeException |
| | | { |
| | | throw new RuntimeException("Not implemented yet"); |
| | | } |
| | | |
| | | /** |
| | | * Generates a map of index keys and a boolean flag indicating |
| | | * whether the corresponding key will be inserted or deleted. |
| | | * |
| | | * @param value |
| | | * @param attrValue |
| | | * The attribute for which keys are required. |
| | | * @param modifiedKeys |
| | | * A map containing the keys and a boolean. Keys |
| | | * corresponding to the boolean value <code>true |
| | | * </code> |
| | | * corresponding to the boolean value <code>true</code> |
| | | * should be inserted and <code>false</code> should be |
| | | * deleted. |
| | | * @param insert |
| | | * <code>true</code> if generated keys should be inserted |
| | | * or <code>false</code> otherwise. |
| | | */ |
| | | public abstract void getKeys(AttributeValue value, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert); |
| | | public void getKeys(AttributeValue attrValue, Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | { |
| | | final Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(attrValue, keys); |
| | | computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | |
| | | /** |
| | | * Computes the modified keys by an indexer. |
| | | * |
| | | * @param modifiedKeys |
| | | * A map containing the keys and a boolean. Keys |
| | | * corresponding to the boolean value <code>true</code> |
| | | * should be inserted and <code>false</code> should be |
| | | * deleted. |
| | | * @param insert |
| | | * <code>true</code> if generated keys should be inserted |
| | | * or <code>false</code> otherwise. |
| | | * @param keys |
| | | * the newly generated keys that will be added or removed from the Map |
| | | */ |
| | | public static void computeModifiedKeys(Map<byte[], Boolean> modifiedKeys, |
| | | Boolean insert, final Set<byte[]> keys) |
| | | { |
| | | for (byte[] key : keys) |
| | | { |
| | | Boolean cInsert = modifiedKeys.get(key); |
| | | if (cInsert == null) |
| | | { |
| | | modifiedKeys.put(key, insert); |
| | | } |
| | | else if (!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(key); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.api; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.types.IndexConfig; |
| | | |
| | | |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | /** |
| | | * This interface defines the set of methods that must be |
| | |
| | | public interface ExtensibleMatchingRule extends MatchingRule |
| | | { |
| | | /** |
| | | * Returns a collection of extensible indexers associated with this |
| | | * matching rule. |
| | | * Returns a collection of extensible indexers associated with this matching |
| | | * rule. |
| | | * |
| | | * @param config |
| | | * The index configuration to be used by this matching |
| | | * rule. |
| | | * @return The collection of extensible indexers associated with |
| | | * this matching rule. |
| | | * @param indexingOptions |
| | | * The indexing options to be used by this matching rule. |
| | | * @return The collection of extensible indexers associated with this matching |
| | | * rule. |
| | | */ |
| | | Collection<ExtensibleIndexer> getIndexers( |
| | | IndexConfig config); |
| | | Collection<ExtensibleIndexer> getIndexers(IndexingOptions indexingOptions); |
| | | |
| | | |
| | | |
| | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.api.ApproximateMatchingRule; |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.types.*; |
| | | |
| | | /** |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = |
| | | approximateRule.normalizeAttributeValue(value.getValue()).toByteArray(); |
| | | getKeys(value, keys); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | keys.add(keyBytes); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | private void getKeys(AttributeValue value, Set<byte[]> keys) |
| | | { |
| | | try |
| | | { |
| | | byte[] keyBytes = |
| | | approximateRule.normalizeAttributeValue(value.getValue()).toByteArray(); |
| | | |
| | | keys.add(keyBytes); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = approximateRule |
| | | .normalizeAttributeValue(value.getValue()).toByteArray(); |
| | | |
| | | Boolean cInsert = modifiedKeys.get(keyBytes); |
| | | if(cInsert == null) |
| | | { |
| | | modifiedKeys.put(keyBytes, insert); |
| | | } |
| | | else if(!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(keyBytes); |
| | | } |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | getKeys(value, modifiedKeys, insert); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys, |
| | | Boolean insert) |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(value, keys); |
| | | ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | } |
| | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.meta.LocalDBIndexCfgDefn; |
| | | import org.opends.server.admin.std.server.LocalDBIndexCfg; |
| | |
| | | String name = |
| | | entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); |
| | | int indexEntryLimit = indexConfig.getIndexEntryLimit(); |
| | | JEIndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength()); |
| | | |
| | | if (indexConfig.getIndexType().contains( |
| | | LocalDBIndexCfgDefn.IndexType.EQUALITY)) |
| | |
| | | throw new ConfigException(ERR_CONFIG_INDEX_TYPE_NEEDS_MATCHING_RULE.get(attrType, "substring")); |
| | | } |
| | | |
| | | Indexer substringIndexer = new SubstringIndexer(attrType, |
| | | indexConfig.getSubstringLength()); |
| | | Indexer substringIndexer = new SubstringIndexer(attrType, config); |
| | | this.substringIndex = new Index(name + ".substring", |
| | | substringIndexer, |
| | | state, |
| | |
| | | //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. |
| | | IndexConfig config = new JEIndexConfig(indexConfig.getSubstringLength()); |
| | | for(String ruleName:extensibleRules) |
| | | { |
| | | ExtensibleMatchingRule rule = |
| | |
| | | Map<String,Index> indexMap = new HashMap<String,Index>(); |
| | | for(ExtensibleIndexer indexer : rule.getIndexers(config)) |
| | | { |
| | | String indexerId = indexer.getExtensibleIndexID(); |
| | | String indexID = |
| | | attrType.getNameOrOID() + "." |
| | | + indexer.getPreferredIndexName() |
| | | + "." + indexerId; |
| | | String indexID = attrType.getNameOrOID() + "." + indexer.getIndexID(); |
| | | if(!extensibleIndexes.isIndexPresent(indexID)) |
| | | { |
| | | //There is no index available for this index id. Create a new index. |
| | |
| | | indexMap.put(indexer.getExtensibleIndexID(), |
| | | extensibleIndexes.getIndex(indexID)); |
| | | } |
| | | IndexQueryFactory<IndexQuery> factory = |
| | | new IndexQueryFactoryImpl(indexMap); |
| | | extensibleIndexes.addQueryFactory(rule, factory); |
| | | IndexQueryFactory<IndexQuery> factory = |
| | | new IndexQueryFactoryImpl(indexMap, config); |
| | | extensibleIndexes.addQueryFactory(rule, factory); |
| | | } |
| | | } |
| | | } |
| | |
| | | */ |
| | | Set<ByteString> substringKeys(byte[] value) |
| | | { |
| | | // FIXME replace this code with SDK's |
| | | // AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys() |
| | | |
| | | // 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 |
| | |
| | | Set<ByteString> set = new HashSet<ByteString>(); |
| | | |
| | | int substrLength = indexConfig.getSubstringLength(); |
| | | byte[] keyBytes; |
| | | |
| | | // Example: The value is ABCDE and the substring length is 3. |
| | | // We produce the keys ABC BCD CDE DE E |
| | |
| | | for (int i = 0, remain = value.length; remain > 0; i++, remain--) |
| | | { |
| | | int len = Math.min(substrLength, remain); |
| | | keyBytes = makeSubstringKey(value, i, len); |
| | | byte[] keyBytes = makeSubstringKey(value, i, len); |
| | | set.add(ByteString.wrap(keyBytes)); |
| | | } |
| | | |
| | |
| | | */ |
| | | 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 |
| | |
| | | for (int first = 0, last = substrLength; |
| | | last <= bytes.length; first++, last++) |
| | | { |
| | | byte[] keyBytes; |
| | | keyBytes = makeSubstringKey(bytes, first, substrLength); |
| | | set.add(keyBytes); |
| | | set.add(makeSubstringKey(bytes, first, substrLength)); |
| | | } |
| | | |
| | | EntryIDSet results = new EntryIDSet(); |
| | |
| | | */ |
| | | 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. |
| | |
| | | String name = |
| | | entryContainer.getDatabasePrefix() + "_" + attrType.getNameOrOID(); |
| | | int indexEntryLimit = cfg.getIndexEntryLimit(); |
| | | JEIndexConfig config = new JEIndexConfig(cfg.getSubstringLength()); |
| | | |
| | | if (cfg.getIndexType().contains(LocalDBIndexCfgDefn.IndexType.EQUALITY)) |
| | | { |
| | |
| | | { |
| | | if(substringIndex == null) |
| | | { |
| | | Indexer substringIndexer = new SubstringIndexer( |
| | | attrType, cfg.getSubstringLength()); |
| | | Indexer substringIndexer = new SubstringIndexer(attrType, config); |
| | | substringIndex = new Index(name + ".substring", |
| | | substringIndexer, |
| | | state, |
| | |
| | | if(indexConfig.getSubstringLength() != |
| | | cfg.getSubstringLength()) |
| | | { |
| | | Indexer substringIndexer = new SubstringIndexer( |
| | | attrType, cfg.getSubstringLength()); |
| | | Indexer substringIndexer = new SubstringIndexer(attrType, config); |
| | | this.substringIndex.setIndexer(substringIndexer); |
| | | } |
| | | } |
| | |
| | | { |
| | | extensibleIndexes = new ExtensibleMatchingRuleIndex(); |
| | | } |
| | | IndexConfig config = new JEIndexConfig(cfg.getSubstringLength()); |
| | | for(String ruleName:extensibleRules) |
| | | { |
| | | ExtensibleMatchingRule rule = |
| | |
| | | Map<String,Index> indexMap = new HashMap<String,Index>(); |
| | | for(ExtensibleIndexer indexer: rule.getIndexers(config)) |
| | | { |
| | | String indexerId = indexer.getExtensibleIndexID(); |
| | | String indexID = |
| | | attrType.getNameOrOID() + "." |
| | | + indexer.getPreferredIndexName() |
| | | + "." + indexerId; |
| | | String indexID = attrType.getNameOrOID() + "." + indexer.getIndexID(); |
| | | if(!extensibleIndexes.isIndexPresent(indexID)) |
| | | { |
| | | Indexer extensibleIndexer = |
| | |
| | | } |
| | | } |
| | | extensibleIndexes.addRule(indexID, rule); |
| | | indexMap.put(indexerId,extensibleIndexes.getIndex(indexID)); |
| | | indexMap.put(indexer.getExtensibleIndexID(), extensibleIndexes.getIndex(indexID)); |
| | | } |
| | | IndexQueryFactory<IndexQuery> factory = |
| | | new IndexQueryFactoryImpl(indexMap); |
| | | new IndexQueryFactoryImpl(indexMap, config); |
| | | extensibleIndexes.addQueryFactory(rule, factory); |
| | | } |
| | | //Some rules might have been removed from the configuration. |
| | |
| | | List<String> ids = new ArrayList<String>(); |
| | | for(ExtensibleIndexer indexer: rule.getIndexers(config)) |
| | | { |
| | | String id = attrType.getNameOrOID() + "." |
| | | + indexer.getPreferredIndexName() |
| | | + "." + indexer.getExtensibleIndexID(); |
| | | String id = attrType.getNameOrOID() + "." + indexer.getIndexID(); |
| | | rules.addAll(extensibleIndexes.getRules(id)); |
| | | ids.add(id); |
| | | } |
| | |
| | | if(debugBuffer != null) |
| | | { |
| | | debugBuffer.append("[INDEX:"); |
| | | IndexConfig config = |
| | | JEIndexConfig config = |
| | | new JEIndexConfig(indexConfig.getSubstringLength()); |
| | | for(ExtensibleIndexer indexer : rule.getIndexers(config)) |
| | | { |
| | | debugBuffer.append(" ") |
| | | .append(extensibleFilter.getAttributeType().getNameOrOID()) |
| | | .append(".") |
| | | .append(indexer.getPreferredIndexName()) |
| | | .append(".") |
| | | .append(indexer.getExtensibleIndexID()); |
| | | .append(indexer.getIndexID()); |
| | | } |
| | | debugBuffer.append("]"); |
| | | } |
| | |
| | | /** |
| | | * This class extends the IndexConfig for JE Backend. |
| | | */ |
| | | private class JEIndexConfig extends IndexConfig |
| | | private class JEIndexConfig implements IndexingOptions |
| | | { |
| | | /** The length of the substring index. */ |
| | | private int substringLength; |
| | |
| | | this.substringLength = substringLength; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Returns the length of the substring. |
| | | * @return the length of the substring. |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public int getSubstringLength() |
| | | public int substringKeySize() |
| | | { |
| | | return substringLength; |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import java.util.*; |
| | | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | |
| | | import java.util.*; |
| | | |
| | | /** |
| | | * An implementation of an Indexer for attribute equality. |
| | | */ |
| | |
| | | * used to name an index created using this object. |
| | | * @return A string representation of this object. |
| | | */ |
| | | @Override |
| | | public String toString() |
| | | { |
| | | return attributeType.getNameOrOID() + ".equality"; |
| | |
| | | * |
| | | * @return A byte array comparator. |
| | | */ |
| | | @Override |
| | | public Comparator<byte[]> getComparator() |
| | | { |
| | | return comparator; |
| | |
| | | * @param entry The entry. |
| | | * @param keys The set into which the generated keys will be inserted. |
| | | */ |
| | | @Override |
| | | public void indexEntry(Entry entry, Set<byte[]> keys) |
| | | { |
| | | List<Attribute> attrList = |
| | |
| | | * @param newEntry The new entry contents. |
| | | * @param modifiedKeys The map into which the modified keys will be inserted. |
| | | */ |
| | | @Override |
| | | public void replaceEntry(Entry oldEntry, Entry newEntry, |
| | | Map<byte[], Boolean> modifiedKeys) |
| | | { |
| | |
| | | * @param mods The set of modifications that were applied to the entry. |
| | | * @param modifiedKeys The map into which the modified keys will be inserted. |
| | | */ |
| | | @Override |
| | | public void modifyEntry(Entry oldEntry, Entry newEntry, |
| | | List<Modification> mods, |
| | | Map<byte[], Boolean> modifiedKeys) |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = value.getNormalizedValue().toByteArray(); |
| | | getKeys(value, keys); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | keys.add(keyBytes); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | private void getKeys(AttributeValue value, Set<byte[]> keys) |
| | | { |
| | | try |
| | | { |
| | | keys.add(value.getNormalizedValue().toByteArray()); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = value.getNormalizedValue().toByteArray(); |
| | | |
| | | Boolean cInsert = modifiedKeys.get(keyBytes); |
| | | if(cInsert == null) |
| | | { |
| | | modifiedKeys.put(keyBytes, insert); |
| | | } |
| | | else if(!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(keyBytes); |
| | | } |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | logger.traceException(e); |
| | | getKeys(value, modifiedKeys, insert); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys, |
| | | Boolean insert) |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(value, keys); |
| | | ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | } |
| | |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | |
| | | |
| | | import com.sleepycat.je.DatabaseEntry; |
| | | import com.sleepycat.je.LockMode; |
| | | import java.util.Collection; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.opends.server.api.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | |
| | | import static org.opends.messages.JebMessages. |
| | | INFO_JEB_INDEX_FILTER_INDEX_LIMIT_EXCEEDED; |
| | | import static org.opends.messages.JebMessages. |
| | | INFO_JEB_INDEX_FILTER_INDEX_NOT_TRUSTED; |
| | | import static org.opends.messages.JebMessages. |
| | | INFO_JEB_INDEX_FILTER_INDEX_REBUILD_IN_PROGRESS; |
| | | import com.sleepycat.je.DatabaseEntry; |
| | | import com.sleepycat.je.LockMode; |
| | | |
| | | import static org.opends.messages.JebMessages.*; |
| | | |
| | | /** |
| | | * This class is an implementation of IndexQueryFactory which creates |
| | |
| | | public final class IndexQueryFactoryImpl implements |
| | | IndexQueryFactory<IndexQuery> |
| | | { |
| | | |
| | | /** |
| | | * The Map containing the string type identifier and the corresponding |
| | | * index. |
| | | * The Map containing the string type identifier and the corresponding index. |
| | | */ |
| | | private Map<String, Index> indexMap; |
| | | |
| | | |
| | | private final Map<String, Index> indexMap; |
| | | private final IndexingOptions indexingOptions; |
| | | |
| | | /** |
| | | * Creates a new IndexQueryFactoryImpl object. |
| | | * |
| | | * @param indexMap |
| | | * A map containing the index id and the corresponding index. |
| | | * @param indexingOptions |
| | | * The options to use for indexing |
| | | */ |
| | | public IndexQueryFactoryImpl(Map<String, Index> indexMap) |
| | | public IndexQueryFactoryImpl(Map<String, Index> indexMap, IndexingOptions indexingOptions) |
| | | { |
| | | this.indexMap = indexMap; |
| | | this.indexingOptions = indexingOptions; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public IndexQuery createExactMatchQuery(final String indexID, |
| | | final ByteSequence value) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public IndexQuery createRangeMatchQuery(final String indexID, |
| | | final ByteSequence lowerBound, final ByteSequence upperBound, |
| | | final boolean includeLowerBound, final boolean includeUpperBound) |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public IndexQuery createIntersectionQuery( |
| | | Collection<IndexQuery> subqueries) |
| | | { |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public IndexQuery createUnionQuery(Collection<IndexQuery> subqueries) |
| | | { |
| | | return IndexQuery.createUnionIndexQuery(subqueries); |
| | |
| | | * It returns an empty EntryIDSet object when either all or no record |
| | | * sets are requested. |
| | | */ |
| | | @Override |
| | | public IndexQuery createMatchAllQuery() |
| | | { |
| | | return new IndexQuery() |
| | |
| | | } |
| | | }; |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public IndexingOptions getIndexingOptions() |
| | | { |
| | | return indexingOptions; |
| | | } |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | * Portions Copyright 2014 ForgeRock AS |
| | | */ |
| | | |
| | | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.api.ExtensibleMatchingRule; |
| | | import org.opends.server.types.Attribute; |
| | | |
| | | |
| | | import java.util.Comparator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.api.ExtensibleMatchingRule; |
| | | import org.opends.server.types.AttributeType; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.Attribute; |
| | | |
| | | /** |
| | | *This class implements an Indexer for extensible matching rules in JE Backend. |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | extensibleIndexer.getKeys(value, keys); |
| | | for (AttributeValue value : attr) |
| | | { |
| | | extensibleIndexer.getKeys(value, keys); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | extensibleIndexer.getKeys(value,modifiedKeys,insert); |
| | | for (AttributeValue value : attr) |
| | | { |
| | | extensibleIndexer.getKeys(value, modifiedKeys, insert); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.api.OrderingMatchingRule; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.AttributeType; |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = orderingRule.normalizeAttributeValue(value.getValue()) |
| | | .toByteArray(); |
| | | getKeys(value, keys); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | keys.add(keyBytes); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | private void getKeys(AttributeValue value, Set<byte[]> keys) |
| | | { |
| | | try |
| | | { |
| | | keys.add(orderingRule.normalizeAttributeValue(value.getValue()).toByteArray()); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] keyBytes = |
| | | orderingRule.normalizeAttributeValue(value.getValue()).toByteArray(); |
| | | |
| | | Boolean cInsert = modifiedKeys.get(keyBytes); |
| | | if(cInsert == null) |
| | | { |
| | | modifiedKeys.put(keyBytes, insert); |
| | | } |
| | | else if(!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(keyBytes); |
| | | } |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | getKeys(value, modifiedKeys, insert); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void getKeys(AttributeValue value, Map<byte[], Boolean> modifiedKeys, |
| | | Boolean insert) |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(value, keys); |
| | | ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | } |
| | |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import java.util.Comparator; |
| | | import java.util.HashSet; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Set; |
| | | |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.api.ExtensibleIndexer; |
| | | import org.opends.server.api.SubstringMatchingRule; |
| | | import org.opends.server.types.*; |
| | | |
| | |
| | | * generate index keys. |
| | | */ |
| | | private AttributeType attributeType; |
| | | |
| | | /** |
| | | * The substring length. |
| | | */ |
| | | private int substrLength; |
| | | private IndexingOptions indexingOptions; |
| | | |
| | | /** |
| | | * Create a new attribute substring indexer for the given index configuration. |
| | | * @param attributeType The attribute type for which an indexer is |
| | | * required. |
| | | * @param substringLength The decomposed substring length. |
| | | * |
| | | * @param attributeType |
| | | * The attribute type for which an indexer is required. |
| | | * @param indexingOptions |
| | | * The decomposed substring length. |
| | | */ |
| | | public SubstringIndexer(AttributeType attributeType, int substringLength) |
| | | public SubstringIndexer(AttributeType attributeType, |
| | | IndexingOptions indexingOptions) |
| | | { |
| | | this.attributeType = attributeType; |
| | | this.substrLength = substringLength; |
| | | this.indexingOptions = indexingOptions; |
| | | } |
| | | |
| | | /** |
| | |
| | | if (attrList == null) return; |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | //Get the substring matching rule. |
| | | SubstringMatchingRule rule = |
| | | attr.getAttributeType().getSubstringMatchingRule(); |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | SubstringMatchingRule rule = |
| | | attr.getAttributeType().getSubstringMatchingRule(); |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] normalizedBytes = rule.normalizeAttributeValue(value.getValue()). |
| | | toByteArray(); |
| | | |
| | | substringKeys(normalizedBytes, keys); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | getKeys(rule, value, 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 |
| | | * @param set A set into which the keys will be inserted. |
| | | * @param attrValue A byte array containing the normalized attribute value |
| | | * @param keys A set into which the keys will be inserted. |
| | | */ |
| | | private void substringKeys(byte[] value, Set<byte[]> set) |
| | | { |
| | | 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. |
| | | for (int i = 0, remain = value.length; remain > 0; i++, remain--) |
| | | private void getKeys(SubstringMatchingRule rule, AttributeValue attrValue, |
| | | Set<byte[]> keys) |
| | | { // TODO merge with ExtensibleIndexer.getKeys(attrValue, keys); |
| | | try |
| | | { |
| | | int len = Math.min(substrLength, remain); |
| | | keyBytes = makeSubstringKey(value, i, len); |
| | | set.add(keyBytes); |
| | | byte[] value = rule.normalizeAttributeValue(attrValue.getValue()).toByteArray(); |
| | | |
| | | // 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. |
| | | final int substringKeySize = indexingOptions.substringKeySize(); |
| | | for (int i = 0, remain = value.length; remain > 0; i++, remain--) |
| | | { |
| | | int len = Math.min(substringKeySize, remain); |
| | | keys.add(makeSubstringKey(value, i, len)); |
| | | } |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | for (Attribute attr : attrList) |
| | | { |
| | | if (attr.isVirtual()) |
| | | if (!attr.isVirtual()) |
| | | { |
| | | continue; |
| | | } |
| | | //Get the substring matching rule. |
| | | SubstringMatchingRule rule = |
| | | attr.getAttributeType().getSubstringMatchingRule(); |
| | | |
| | | for (AttributeValue value : attr) |
| | | { |
| | | try |
| | | SubstringMatchingRule rule = |
| | | attr.getAttributeType().getSubstringMatchingRule(); |
| | | for (AttributeValue value : attr) |
| | | { |
| | | byte[] normalizedBytes = rule.normalizeAttributeValue(value.getValue()) |
| | | .toByteArray(); |
| | | |
| | | substringKeys(normalizedBytes, modifiedKeys, insert); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | logger.traceException(e); |
| | | getKeys(rule, value, modifiedKeys, insert); |
| | | } |
| | | } |
| | | } |
| | |
| | | * @param insert <code>true</code> if generated keys should |
| | | * be inserted or <code>false</code> otherwise. |
| | | */ |
| | | private void substringKeys(byte[] value, |
| | | Map<byte[], Boolean> modifiedKeys, |
| | | Boolean insert) |
| | | { |
| | | 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. |
| | | for (int i = 0, remain = value.length; remain > 0; i++, remain--) |
| | | { |
| | | int len = Math.min(substrLength, remain); |
| | | keyBytes = makeSubstringKey(value, i, len); |
| | | Boolean cInsert = modifiedKeys.get(keyBytes); |
| | | if(cInsert == null) |
| | | { |
| | | modifiedKeys.put(keyBytes, insert); |
| | | } |
| | | else if(!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(keyBytes); |
| | | } |
| | | } |
| | | private void getKeys(SubstringMatchingRule rule, AttributeValue value, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | { // TODO merge with ExtensibleIndexer.getKeys(attrValue, modifiedKeys, insert); |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(rule, value, keys); |
| | | ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | |
| | | /** |
| | | * Return the substring length for an indexer. |
| | | * |
| | | * @return The substring length configured for an sub string indexer. |
| | | */ |
| | | public int getSubStringLen() |
| | | { |
| | | return substrLength; |
| | | } |
| | | } |
| | |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.meta.CollationMatchingRuleCfgDefn.MatchingRuleType; |
| | | import org.opends.server.admin.std.server.CollationMatchingRuleCfg; |
| | |
| | | import org.opends.server.backends.jeb.AttributeIndex; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.*; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | | import static org.opends.messages.ConfigMessages.*; |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Collection<ExtensibleIndexer> getIndexers(IndexConfig config) |
| | | public Collection<ExtensibleIndexer> getIndexers( |
| | | IndexingOptions indexingOptions) |
| | | { |
| | | if (indexer == null) |
| | | { |
| | |
| | | @Override |
| | | public ConditionResult valuesMatch(ByteSequence attributeValue, |
| | | ByteSequence assertionValue) |
| | | { |
| | | { // FIXME Code similar to |
| | | // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.matches() |
| | | int valueLength = attributeValue.length() - 4; |
| | | int valuePos = 0; // position in the value bytes array. |
| | | |
| | |
| | | */ |
| | | @Override |
| | | public final Collection<ExtensibleIndexer> getIndexers( |
| | | IndexConfig config) |
| | | IndexingOptions indexingOptions) |
| | | { |
| | | Collection<ExtensibleIndexer> indexers = |
| | | new ArrayList<ExtensibleIndexer>(); |
| | | int substrLength = 6; // Default substring length; |
| | | if (subIndexer == null) |
| | | { |
| | | if (config != null) |
| | | if (indexingOptions != null) |
| | | { |
| | | substrLength = config.getSubstringLength(); |
| | | substrLength = indexingOptions.substringKeySize(); |
| | | } |
| | | subIndexer = |
| | | new CollationSubstringExtensibleIndexer(this, substrLength); |
| | | } |
| | | else |
| | | else if (indexingOptions != null |
| | | && indexingOptions.substringKeySize() != subIndexer |
| | | .getSubstringLength()) |
| | | { |
| | | if (config != null) |
| | | { |
| | | if (config.getSubstringLength() != subIndexer |
| | | .gerSubstringLength()) |
| | | { |
| | | subIndexer.setSubstringLength(substrLength); |
| | | } |
| | | } |
| | | subIndexer.setSubstringLength(substrLength); |
| | | } |
| | | |
| | | if (indexer == null) |
| | |
| | | * @param set |
| | | * A set into which the keys will be inserted. |
| | | */ |
| | | private void subtringKeys(ByteString attValue, Set<byte[]> keys) |
| | | { |
| | | private void substringKeys(ByteString attValue, Set<byte[]> keys) |
| | | { // TODO merge with ExtensibleIndexer.getKeys(attrValue, keys); |
| | | // TODO and with AbstractSubstringMatchingRuleImpl.SubstringIndexer.createKeys(); |
| | | String value = attValue.toString(); |
| | | int keyLength = subIndexer.gerSubstringLength(); |
| | | int keyLength = subIndexer.getSubstringLength(); |
| | | for (int i = 0, remain = value.length(); remain > 0; i++, remain--) |
| | | { |
| | | int len = Math.min(keyLength, remain); |
| | | byte[] keyBytes = makeSubstringKey(value, i, len); |
| | | keys.add(keyBytes); |
| | | keys.add(makeSubstringKey(value, i, len)); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private void substringKeys(ByteString attValue, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | { |
| | | String value = attValue.toString(); |
| | | int keyLength = subIndexer.gerSubstringLength(); |
| | | for (int i = 0, remain = value.length(); remain > 0; i++, remain--) |
| | | { |
| | | int len = Math.min(keyLength, remain); |
| | | byte[] keyBytes = makeSubstringKey(value, i, len); |
| | | Boolean cinsert = modifiedKeys.get(keyBytes); |
| | | if (cinsert == null) |
| | | { |
| | | modifiedKeys.put(keyBytes, insert); |
| | | } |
| | | else if (!cinsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(keyBytes); |
| | | } |
| | | } |
| | | { // TODO merge with ExtensibleIndexer.getKeys(attrValue, modifiedKeys, insert); |
| | | Set<byte[]> keys = new TreeSet<byte[]>(); |
| | | substringKeys(attValue, keys); |
| | | ExtensibleIndexer.computeModifiedKeys(modifiedKeys, insert, keys); |
| | | } |
| | | |
| | | |
| | |
| | | */ |
| | | private <T> T matchInitialSubstring(String value, |
| | | IndexQueryFactory<T> factory) |
| | | { |
| | | { // FIXME Code similar to |
| | | // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.rangeMatch() |
| | | byte[] lower = makeSubstringKey(value, 0, value.length()); |
| | | byte[] upper = new byte[lower.length]; |
| | | System.arraycopy(lower, 0, upper, 0, lower.length); |
| | |
| | | */ |
| | | private <T> T matchSubstring(String value, |
| | | IndexQueryFactory<T> factory) |
| | | { |
| | | { // FIXME Code similar to |
| | | // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.substringMatch() |
| | | T intersectionQuery; |
| | | int substrLength = subIndexer.gerSubstringLength(); |
| | | int substrLength = subIndexer.getSubstringLength(); |
| | | |
| | | if (value.length() < substrLength) |
| | | { |
| | |
| | | last <= value.length(); |
| | | first++, last++) |
| | | { |
| | | byte[] keyBytes; |
| | | keyBytes = makeSubstringKey(value, first, substrLength); |
| | | set.add(keyBytes); |
| | | set.add(makeSubstringKey(value, first, substrLength)); |
| | | } |
| | | |
| | | for (byte[] keyBytes : set) |
| | | { |
| | | T single = |
| | | factory.createExactMatchQuery(subIndexer |
| | | .getExtensibleIndexID(), ByteString.wrap(keyBytes)); |
| | | queryList.add(single); |
| | | queryList.add(factory.createExactMatchQuery( |
| | | subIndexer.getExtensibleIndexID(), ByteString.wrap(keyBytes))); |
| | | } |
| | | intersectionQuery = factory.createIntersectionQuery(queryList); |
| | | } |
| | |
| | | @Override |
| | | public <T> T createIndexQuery(ByteSequence assertionValue, |
| | | IndexQueryFactory<T> factory) throws DecodeException |
| | | { |
| | | { // FIXME Code similar to |
| | | // AbstractSubstringMatchingRuleImpl.DefaultSubstringAssertion.createIndexQuery()? |
| | | Assertion assertion = parseAssertion(assertionValue); |
| | | String subInitial = assertion.getInitial(); |
| | | List<String> subAny = assertion.getAny(); |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final void getKeys(AttributeValue value, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | public String getIndexID() |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(value, keys); |
| | | for (byte[] key : keys) |
| | | { |
| | | Boolean cInsert = modifiedKeys.get(key); |
| | | if (cInsert == null) |
| | | { |
| | | modifiedKeys.put(key, insert); |
| | | } |
| | | else if (!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getPreferredIndexName() |
| | | { |
| | | return matchingRule.getIndexName(); |
| | | return matchingRule.getIndexName() + "." + getExtensibleIndexID(); |
| | | } |
| | | } |
| | | |
| | |
| | | @Override |
| | | public void getKeys(AttributeValue value, Set<byte[]> keys) |
| | | { |
| | | matchingRule.subtringKeys(value.getValue(), keys); |
| | | matchingRule.substringKeys(value.getValue(), keys); |
| | | } |
| | | |
| | | |
| | |
| | | public void getKeys(AttributeValue attValue, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | { |
| | | matchingRule.substringKeys(attValue.getValue(), modifiedKeys, |
| | | insert); |
| | | matchingRule.substringKeys(attValue.getValue(), modifiedKeys, insert); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public String getPreferredIndexName() |
| | | public String getIndexID() |
| | | { |
| | | return matchingRule.getIndexName(); |
| | | return matchingRule.getIndexName() + "." + getExtensibleIndexID(); |
| | | } |
| | | |
| | | |
| | |
| | | * |
| | | * @return The length of the substring. |
| | | */ |
| | | private int gerSubstringLength() |
| | | { |
| | | private int getSubstringLength() |
| | | {// TODO JNR remove |
| | | return substringLen; |
| | | } |
| | | |
| | |
| | | * The substring length. |
| | | */ |
| | | private void setSubstringLength(int substringLen) |
| | | { |
| | | {// TODO JNR remove |
| | | this.substringLen = substringLen; |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.spi.IndexQueryFactory; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.admin.std.server.MatchingRuleCfg; |
| | | import org.opends.server.api.*; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.types.AttributeValue; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.IndexConfig; |
| | | import org.opends.server.types.InitializationException; |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Collection<ExtensibleIndexer> getIndexers(IndexConfig config) |
| | | public Collection<ExtensibleIndexer> getIndexers( |
| | | IndexingOptions indexingOptions) |
| | | { |
| | | if(indexer == null) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public final void getKeys(AttributeValue value, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | public String getIndexID() |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(value, keys); |
| | | for (byte[] key : keys) |
| | | { |
| | | Boolean cInsert = modifiedKeys.get(key); |
| | | if (cInsert == null) |
| | | { |
| | | modifiedKeys.put(key, insert); |
| | | } |
| | | else if (!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getPreferredIndexName() |
| | | { |
| | | return RELATIVE_TIME_INDEX_NAME; |
| | | return RELATIVE_TIME_INDEX_NAME + "." + getExtensibleIndexID(); |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | private final class PartialDateAndTimeMatchingRule |
| | | extends TimeBasedMatchingRule |
| | | implements ExtensibleMatchingRule |
| | | { |
| | | /** |
| | | * Indexer associated with this instance. |
| | |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Collection<ExtensibleIndexer> getIndexers(IndexConfig config) |
| | | public Collection<ExtensibleIndexer> getIndexers( |
| | | IndexingOptions indexingOptions) |
| | | { |
| | | if(indexer == null) |
| | | { |
| | |
| | | matchingRule.timeKeys(value.getValue(), keys); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public void getKeys(AttributeValue attValue, |
| | | Map<byte[], Boolean> modifiedKeys, Boolean insert) |
| | | public String getIndexID() |
| | | { |
| | | Set<byte[]> keys = new HashSet<byte[]>(); |
| | | getKeys(attValue, keys); |
| | | for (byte[] key : keys) |
| | | { |
| | | Boolean cInsert = modifiedKeys.get(key); |
| | | if (cInsert == null) |
| | | { |
| | | modifiedKeys.put(key, insert); |
| | | } |
| | | else if (!cInsert.equals(insert)) |
| | | { |
| | | modifiedKeys.remove(key); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public String getPreferredIndexName() |
| | | { |
| | | return PARTIAL_DATE_TIME_INDEX_NAME; |
| | | return PARTIAL_DATE_TIME_INDEX_NAME + "." + getExtensibleIndexID(); |
| | | } |
| | | |
| | | |
| | |
| | | import org.forgerock.opendj.ldap.ConditionResult; |
| | | import org.forgerock.opendj.ldap.DereferenceAliasesPolicy; |
| | | import org.forgerock.opendj.ldap.ModificationType; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.forgerock.opendj.ldap.spi.IndexingOptions; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta.LocalDBBackendCfgDefn; |
| | |
| | | import org.opends.server.protocols.internal.InternalSearchOperation; |
| | | import org.opends.server.protocols.ldap.LDAPFilter; |
| | | import org.opends.server.types.*; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | 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; |
| | |
| | | |
| | | import static org.assertj.core.api.Assertions.*; |
| | | import static org.forgerock.opendj.ldap.ConditionResult.*; |
| | | import static org.mockito.Mockito.*; |
| | | import static org.testng.Assert.*; |
| | | |
| | | /** |
| | |
| | | assertIndexContainsID(equalityIndexer, entry, index.equalityIndex, |
| | | entryID, FALSE); |
| | | |
| | | Indexer substringIndexer = |
| | | new SubstringIndexer(index.getAttributeType(), |
| | | index.getConfiguration().getSubstringLength()); |
| | | Indexer substringIndexer = newSubstringIndexer(index); |
| | | assertIndexContainsID(substringIndexer, entry, index.substringIndex, |
| | | entryID, FALSE); |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | private SubstringIndexer newSubstringIndexer(AttributeIndex index) |
| | | { |
| | | final IndexingOptions options = mock(IndexingOptions.class); |
| | | when(options.substringKeySize()).thenReturn( |
| | | index.getConfiguration().getSubstringLength()); |
| | | return new SubstringIndexer(index.getAttributeType(), options); |
| | | } |
| | | |
| | | private void assertIndexContainsID(Indexer indexer, Entry entry, Index index, |
| | | EntryID entryID) |
| | | { |
| | |
| | | assertIndexContainsID(orderingIndexer, oldEntry, index.orderingIndex, |
| | | entryID, FALSE); |
| | | |
| | | Indexer substringIndexer = new SubstringIndexer(index.getAttributeType(), |
| | | index.getConfiguration().getSubstringLength()); |
| | | Indexer substringIndexer = newSubstringIndexer(index); |
| | | assertIndexContainsID(substringIndexer, entry, index.substringIndex, |
| | | entryID, TRUE); |
| | | assertIndexContainsID(substringIndexer, oldEntry, index.substringIndex, |
| | |
| | | equalityIndexer = new EqualityIndexer(nameIndex.getAttributeType()); |
| | | assertIndexContainsID(equalityIndexer, entry, nameIndex.equalityIndex, entryID); |
| | | |
| | | substringIndexer = new SubstringIndexer(titleIndex.getAttributeType(), |
| | | titleIndex.getConfiguration().getSubstringLength()); |
| | | substringIndexer = newSubstringIndexer(titleIndex); |
| | | assertIndexContainsID(substringIndexer, entry, titleIndex.substringIndex, entryID); |
| | | |
| | | substringIndexer = new SubstringIndexer(nameIndex.getAttributeType(), |
| | | nameIndex.getConfiguration().getSubstringLength()); |
| | | substringIndexer = newSubstringIndexer(nameIndex); |
| | | assertIndexContainsID(substringIndexer, entry, nameIndex.substringIndex, entryID); |
| | | } |
| | | finally |