| | |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.slf4j.LocalizedLogger; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.forgerock.opendj.ldap.ByteStringBuilder; |
| | | import org.forgerock.opendj.ldap.ByteSequence; |
| | | import org.forgerock.opendj.ldap.DecodeException; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldap.SearchScope.Enum; |
| | | import org.forgerock.opendj.ldap.SearchScope; |
| | | import org.opends.server.admin.server.ConfigurationChangeListener; |
| | | import org.opends.server.admin.std.meta.LocalDBVLVIndexCfgDefn.Scope; |
| | | import org.opends.server.admin.std.server.LocalDBVLVIndexCfg; |
| | | import org.opends.server.api.MatchingRule; |
| | | import org.opends.server.api.OrderingMatchingRule; |
| | | import org.forgerock.opendj.config.server.ConfigException; |
| | | import org.opends.server.controls.ServerSideSortRequestControl; |
| | | import org.opends.server.controls.VLVRequestControl; |
| | | import org.opends.server.controls.VLVResponseControl; |
| | |
| | | import org.opends.server.core.SearchOperation; |
| | | import org.opends.server.protocols.ldap.LDAPResultCode; |
| | | import org.opends.server.types.*; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.opends.server.types.Attribute; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | import org.opends.server.types.SortKey; |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | | import com.sleepycat.je.*; |
| | |
| | | * not required. |
| | | * @param entryID The entry ID to use. |
| | | * @param values The values to use. |
| | | * @param types The types of the values to use. |
| | | * @return The SortValuesSet that should contain the entry with the given |
| | | * information. |
| | | * @throws DatabaseException If an error occurs during an operation on a |
| | |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | public SortValuesSet getSortValuesSet(Transaction txn, long entryID, |
| | | AttributeValue[] values) |
| | | throws DatabaseException, DirectoryException |
| | | AttributeValue[] values, AttributeType[] types) throws DatabaseException, |
| | | DirectoryException |
| | | { |
| | | SortValuesSet sortValuesSet = null; |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | |
| | | |
| | | try |
| | | { |
| | | key.setData(encodeKey(entryID, values)); |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | |
| | | if(status != OperationStatus.SUCCESS) |
| | |
| | | * @param txn The JE transaction to use for database updates. |
| | | * @param entryID The entry ID to search for. |
| | | * @param values The values to search for. |
| | | * @param types The types of the values to search for. |
| | | * @return The index of the entry ID matching the values or -1 if its not |
| | | * found. |
| | | * @throws DatabaseException If an error occurs during an operation on a |
| | |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | public boolean containsValues(Transaction txn, long entryID, |
| | | AttributeValue[] values) |
| | | throws JebException, DatabaseException, DirectoryException |
| | | AttributeValue[] values, AttributeType[] types) throws JebException, |
| | | DatabaseException, DirectoryException |
| | | { |
| | | SortValuesSet valuesSet = getSortValuesSet(txn, entryID, values); |
| | | int pos = valuesSet.binarySearch(entryID, values); |
| | | if(pos < 0) |
| | | { |
| | | return false; |
| | | } |
| | | return true; |
| | | SortValuesSet valuesSet = getSortValuesSet(txn, entryID, values, types); |
| | | int pos = valuesSet.binarySearch(entryID, values, types); |
| | | return pos >= 0; |
| | | } |
| | | |
| | | private boolean insertValues(Transaction txn, long entryID, Entry entry) |
| | | throws JebException, DatabaseException, DirectoryException |
| | | { |
| | | SortValuesSet sortValuesSet; |
| | | AttributeValue[] values = getSortValues(entry); |
| | | AttributeType[] types = getSortTypes(); |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | boolean success = true; |
| | | |
| | | Cursor cursor = openCursor(txn, CursorConfig.READ_COMMITTED); |
| | | |
| | | try |
| | | { |
| | | key.setData(encodeKey(entryID, values)); |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | } |
| | | finally |
| | |
| | | cursor.close(); |
| | | } |
| | | |
| | | SortValuesSet sortValuesSet; |
| | | if(status != OperationStatus.SUCCESS) |
| | | { |
| | | // There are no records in the database |
| | |
| | | |
| | | |
| | | |
| | | success = sortValuesSet.add(entryID, values); |
| | | boolean success = sortValuesSet.add(entryID, values, types); |
| | | |
| | | int newSize = sortValuesSet.size(); |
| | | if(newSize >= sortedSetCapacity) |
| | |
| | | return success; |
| | | } |
| | | |
| | | /** |
| | | * Gets the types of the attribute values to sort. |
| | | * |
| | | * @return The types of the attribute values to sort on. |
| | | */ |
| | | AttributeType[] getSortTypes() |
| | | { |
| | | SortKey[] sortKeys = sortOrder.getSortKeys(); |
| | | AttributeType[] types = new AttributeType[sortKeys.length]; |
| | | for (int i = 0; i < sortKeys.length; i++) |
| | | { |
| | | SortKey sortKey = sortKeys[i]; |
| | | types[i] = sortKey.getAttributeType(); |
| | | } |
| | | return types; |
| | | } |
| | | |
| | | private boolean removeValues(Transaction txn, long entryID, Entry entry) |
| | | throws JebException, DatabaseException, DirectoryException |
| | | { |
| | | SortValuesSet sortValuesSet; |
| | | AttributeValue[] values = getSortValues(entry); |
| | | AttributeType[] types = getSortTypes(); |
| | | DatabaseEntry key = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | LockMode lockMode = LockMode.RMW; |
| | |
| | | |
| | | try |
| | | { |
| | | key.setData(encodeKey(entryID, values)); |
| | | key.setData(encodeKey(entryID, values, types)); |
| | | status = cursor.getSearchKeyRange(key, data,lockMode); |
| | | } |
| | | finally |
| | |
| | | } |
| | | sortValuesSet = new SortValuesSet(key.getData(), data.getData(), |
| | | this); |
| | | boolean success = sortValuesSet.remove(entryID, values); |
| | | boolean success = sortValuesSet.remove(entryID, values, types); |
| | | byte[] after = sortValuesSet.toDatabase(); |
| | | |
| | | if(after == null) |
| | |
| | | |
| | | return success; |
| | | } |
| | | else |
| | | { |
| | | return false; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | |
| | | // Start from the smallest values from either set. |
| | | if(av.compareTo(dv) < 0) |
| | | { |
| | | key.setData(encodeKey(av.getEntryID(), av.getValues())); |
| | | key.setData(encodeKey(av)); |
| | | } |
| | | else |
| | | { |
| | | key.setData(encodeKey(dv.getEntryID(), dv.getValues())); |
| | | key.setData(encodeKey(dv)); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | key.setData(encodeKey(av.getEntryID(), av.getValues())); |
| | | key.setData(encodeKey(av)); |
| | | } |
| | | } |
| | | else if(dv != null) |
| | | { |
| | | key.setData(encodeKey(dv.getEntryID(), dv.getValues())); |
| | | key.setData(encodeKey(dv)); |
| | | } |
| | | else |
| | | { |
| | |
| | | // This is the last unbounded set. |
| | | while(av != null) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues()); |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | aValues.remove(); |
| | | if(aValues.hasNext()) |
| | | { |
| | |
| | | |
| | | while(dv != null) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues(), dv.getTypes()); |
| | | dValues.remove(); |
| | | if(dValues.hasNext()) |
| | | { |
| | |
| | | |
| | | while(av != null && av.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues()); |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | aValues.remove(); |
| | | if(aValues.hasNext()) |
| | | { |
| | |
| | | |
| | | while(dv != null && dv.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues(), dv.getTypes()); |
| | | dValues.remove(); |
| | | if(dValues.hasNext()) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private byte[] encodeKey(SortValues sv) throws DirectoryException |
| | | { |
| | | return encodeKey(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | | } |
| | | |
| | | /** |
| | | * Evaluate a search with sort control using this VLV index. |
| | | * |
| | |
| | | } |
| | | SortValuesSet sortValuesSet = |
| | | new SortValuesSet(key.getData(), data.getData(), this); |
| | | AttributeValue[] assertionValue = new AttributeValue[1]; |
| | | assertionValue[0] = |
| | | AttributeType type = sortOrder.getSortKeys()[0].getAttributeType(); |
| | | AttributeValue[] assertionValue = new AttributeValue[] { |
| | | AttributeValues.create( |
| | | sortOrder.getSortKeys()[0].getAttributeType(), |
| | | vlvRequest.getGreaterThanOrEqualAssertion()); |
| | | type, vlvRequest.getGreaterThanOrEqualAssertion()) |
| | | }; |
| | | AttributeType[] assertionType = new AttributeType[] { type }; |
| | | |
| | | int adjustedTargetOffset = |
| | | sortValuesSet.binarySearch(-1, assertionValue); |
| | | sortValuesSet.binarySearch(-1, assertionValue, assertionType); |
| | | if(adjustedTargetOffset < 0) |
| | | { |
| | | // For a negative return value r, the vlvIndex -(r+1) gives the |
| | |
| | | * |
| | | * @param entryID The entry ID to encode. |
| | | * @param values The values to encode. |
| | | * @param types The types of the values to encode. |
| | | * @return The encoded bytes. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | byte[] encodeKey(long entryID, AttributeValue[] values) |
| | | byte[] encodeKey(long entryID, AttributeValue[] values, AttributeType[] types) |
| | | throws DirectoryException |
| | | { |
| | | ByteStringBuilder builder = new ByteStringBuilder(); |
| | | |
| | | for (AttributeValue v : values) |
| | | try |
| | | { |
| | | if(v == null) |
| | | { |
| | | builder.appendBERLength(0); |
| | | } |
| | | else |
| | | { |
| | | builder.appendBERLength(v.getNormalizedValue().length()); |
| | | builder.append(v.getNormalizedValue()); |
| | | } |
| | | } |
| | | builder.append(entryID); |
| | | builder.trimToSize(); |
| | | final ByteStringBuilder builder = new ByteStringBuilder(); |
| | | |
| | | return builder.getBackingArray(); |
| | | for (int i = 0; i < values.length; i++) |
| | | { |
| | | final AttributeValue v = values[i]; |
| | | if (v == null) |
| | | { |
| | | builder.appendBERLength(0); |
| | | } |
| | | else |
| | | { |
| | | final MatchingRule eqRule = types[i].getEqualityMatchingRule(); |
| | | final ByteString nv = eqRule.normalizeAttributeValue(v.getValue()); |
| | | builder.appendBERLength(nv.length()); |
| | | builder.append(nv); |
| | | } |
| | | } |
| | | builder.append(entryID); |
| | | builder.trimToSize(); |
| | | |
| | | return builder.getBackingArray(); |
| | | } |
| | | catch (DecodeException e) |
| | | { |
| | | throw new DirectoryException( |
| | | ResultCode.INVALID_ATTRIBUTE_SYNTAX, e.getMessageObject(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | public boolean shouldInclude(Entry entry) throws DirectoryException |
| | | { |
| | | DN entryDN = entry.getName(); |
| | | if(entryDN.matchesBaseAndScope(baseDN, scope) && filter.matchesEntry(entry)) |
| | | { |
| | | return true; |
| | | } |
| | | return false; |
| | | return entryDN.matchesBaseAndScope(baseDN, scope) |
| | | && filter.matchesEntry(entry); |
| | | } |
| | | |
| | | /** |