OPENDJ-1308 Migrate schema support
Started using SDK's index query factory into OpenDJ server code.
Made common code glaringly evident.
Prepared for more work on this suggest and added TODO's and FIXME's.
IndexQueryFactory.java: REMOVED
Replaced by the SDK class with the same name.
IndexConfig.java: REMOVED
Replaced by SDK's IndexingOptions.
ExtensibleMatchingRule.java:
Consequence of replacing IndexConfig.
ExtensibleIndexer.java:
Now implements Indexer.
Removed getPreferredIndexName(), replaced by getIndexID().
Implemented the empty createKeys().
Pulled up getKeys() + extracted static method computeModifiedKeys() to be able to reuse it.
ApproximateIndexer.java, EqualityIndexer.java, OrderingIndexer.java:
Extracted methods getKeys() + reworked the code a bit to make it all look similar.
SubstringIndexer.java:
Extracted methods getKeys() + reworked the code a bit to make it all look similar.
Replaced int substrLength field with indexingOptions field + Modified ctor + Removed getSubStringLen()
TestBackendImpl.java:
Consequence of the changes to SubstringIndexer.
CollationMatchingRuleFactory.java, TimeBasedMatchingRuleFactory.java:
Consequence of replacing IndexConfig.
Reworked the code a bit to make it all look similar.
Implemented getIndexID() in inner classes.
Pulled up one getKeys() method from inner classes.
JEExtensibleIndexer.java:
Made the code look similar to the other indexers.
AttributeIndex.java:
Used Indexer.getIndexID().
Consequence of replacing IndexConfig.
Changed the code to pass in JEIndexConfig to SubstringIndexer.
IndexQueryFactoryImpl.java:
Consequence of replacing IndexQueryFactory.
Implemented getIndexingOptions() + Added indexingOptions field + modified Ctor.
12 files modified
2 files deleted
| | |
| | | * |
| | | * |
| | | * 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 |