Resolves an issue in Import due to entries with multiple RDNs.
This patch changes the key format used by the DN2ID database. Rebuilding the index is required.
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import com.sleepycat.je.*; |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.util.StaticUtils; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | |
| | |
| | | /** |
| | | * The key comparator used for the DN database. |
| | | */ |
| | | private Comparator<byte[]> dn2idComparator; |
| | | private final Comparator<byte[]> comparator; |
| | | |
| | | private final int prefixRDNComponents; |
| | | |
| | | /** |
| | | * Create a DN2ID instance for the DN database in a given entryContainer. |
| | |
| | | { |
| | | super(name, env, entryContainer); |
| | | |
| | | dn2idComparator = new EntryContainer.KeyReverseComparator(); |
| | | comparator = new AttributeIndex.KeyComparator(); |
| | | prefixRDNComponents = entryContainer.getBaseDN().getNumComponents(); |
| | | DatabaseConfig dn2idConfig = new DatabaseConfig(); |
| | | |
| | | if(env.getConfig().getReadOnly()) |
| | |
| | | } |
| | | |
| | | this.dbConfig = dn2idConfig; |
| | | this.dbConfig.setKeyPrefixing(true); |
| | | |
| | | //This line causes an unchecked cast error if the SuppressWarnings |
| | | //annotation is removed at the beginning of this method. |
| | | this.dbConfig.setBtreeComparator((Class<? extends Comparator<byte[]>>) |
| | | dn2idComparator.getClass()); |
| | | comparator.getClass()); |
| | | } |
| | | |
| | | /** |
| | | * Create a DN database key from an entry DN. |
| | | * @param dn The entry DN. |
| | | * @return A DatabaseEntry containing the key. |
| | | */ |
| | | private static DatabaseEntry DNdata(DN dn) |
| | | { |
| | | byte[] normDN = StaticUtils.getBytes(dn.toNormalizedString()); |
| | | return new DatabaseEntry(normDN); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Insert a new record into the DN database. |
| | |
| | | public boolean insert(Transaction txn, DN dn, EntryID id) |
| | | throws DatabaseException |
| | | { |
| | | DatabaseEntry key = DNdata(dn); |
| | | DatabaseEntry key = new DatabaseEntry( |
| | | JebFormat.dnToDNKey(dn, prefixRDNComponents)); |
| | | DatabaseEntry data = id.getDatabaseEntry(); |
| | | |
| | | OperationStatus status; |
| | |
| | | public boolean put(Transaction txn, DN dn, EntryID id) |
| | | throws DatabaseException |
| | | { |
| | | DatabaseEntry key = DNdata(dn); |
| | | DatabaseEntry key = new DatabaseEntry( |
| | | JebFormat.dnToDNKey(dn, prefixRDNComponents)); |
| | | DatabaseEntry data = id.getDatabaseEntry(); |
| | | |
| | | OperationStatus status; |
| | |
| | | * @throws DatabaseException If an error occurred while attempting to write |
| | | * the record. |
| | | */ |
| | | public boolean putRaw(Transaction txn, DatabaseEntry key, DatabaseEntry data) |
| | | public OperationStatus put(Transaction txn, DatabaseEntry key, |
| | | DatabaseEntry data) |
| | | throws DatabaseException |
| | | { |
| | | OperationStatus status; |
| | | status = put(txn, key, data); |
| | | if (status != OperationStatus.SUCCESS) |
| | | { |
| | | return false; |
| | | } |
| | | return true; |
| | | return super.put(txn, key, data); |
| | | } |
| | | |
| | | /** |
| | |
| | | public boolean remove(Transaction txn, DN dn) |
| | | throws DatabaseException |
| | | { |
| | | DatabaseEntry key = DNdata(dn); |
| | | DatabaseEntry key = new DatabaseEntry( |
| | | JebFormat.dnToDNKey(dn, prefixRDNComponents) |
| | | ); |
| | | |
| | | OperationStatus status = delete(txn, key); |
| | | if (status != OperationStatus.SUCCESS) |
| | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | protected OperationStatus delete(Transaction txn, DatabaseEntry key) |
| | | throws DatabaseException |
| | | { |
| | | return super.delete(txn, key); |
| | | } |
| | | |
| | | /** |
| | | * Fetch the entry ID for a given DN. |
| | | * @param txn A JE database transaction to be used for the database read, or |
| | | * null if none is required. |
| | |
| | | public EntryID get(Transaction txn, DN dn, LockMode lockMode) |
| | | throws DatabaseException |
| | | { |
| | | DatabaseEntry key = DNdata(dn); |
| | | DatabaseEntry key = new DatabaseEntry( |
| | | JebFormat.dnToDNKey(dn, prefixRDNComponents) |
| | | ); |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | |
| | | OperationStatus status; |
| | |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public OperationStatus read(Transaction txn, |
| | | DatabaseEntry key, DatabaseEntry data, |
| | | LockMode lockMode) |
| | | { |
| | | return super.read(txn, key, data, lockMode); |
| | | } |
| | | |
| | | /** |
| | | * Gets the comparator for records stored in this database. |
| | | * |
| | | * @return The comparator for records stored in this database. |
| | | */ |
| | | public Comparator<byte[]> getComparator() |
| | | { |
| | | return dn2idComparator; |
| | | return comparator; |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.ArrayList; |
| | | import java.util.Comparator; |
| | | import java.util.LinkedHashSet; |
| | | import java.util.List; |
| | | import java.util.Set; |
| | | import java.util.*; |
| | | |
| | | import static org.opends.server.util.ServerConstants.ATTR_REFERRAL_URL; |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | |
| | | /** |
| | | * The key comparator used for the DN database. |
| | | */ |
| | | private Comparator<byte[]> dn2uriComparator; |
| | | private final Comparator<byte[]> dn2uriComparator; |
| | | |
| | | |
| | | private final int prefixRDNComponents; |
| | | |
| | | |
| | | /** |
| | |
| | | { |
| | | super(name, env, entryContainer); |
| | | |
| | | dn2uriComparator = new EntryContainer.KeyReverseComparator(); |
| | | dn2uriComparator = new AttributeIndex.KeyComparator(); |
| | | prefixRDNComponents = entryContainer.getBaseDN().getNumComponents(); |
| | | DatabaseConfig dn2uriConfig = new DatabaseConfig(); |
| | | |
| | | if(env.getConfig().getReadOnly()) |
| | |
| | | * @return true if the record was inserted, false if it was not. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public boolean insert(Transaction txn, DN dn, String labeledURI) |
| | | private boolean insert(Transaction txn, DN dn, String labeledURI) |
| | | throws DatabaseException |
| | | { |
| | | byte[] normDN = StaticUtils.getBytes(dn.toNormalizedString()); |
| | | byte[] normDN = JebFormat.dnToDNKey(dn, prefixRDNComponents); |
| | | byte[] URIBytes = StaticUtils.getBytes(labeledURI); |
| | | DatabaseEntry key = new DatabaseEntry(normDN); |
| | | DatabaseEntry data = new DatabaseEntry(URIBytes); |
| | |
| | | public boolean delete(Transaction txn, DN dn) |
| | | throws DatabaseException |
| | | { |
| | | byte[] normDN = StaticUtils.getBytes(dn.toNormalizedString()); |
| | | byte[] normDN = JebFormat.dnToDNKey(dn, prefixRDNComponents); |
| | | DatabaseEntry key = new DatabaseEntry(normDN); |
| | | OperationStatus status; |
| | | |
| | |
| | | throws DatabaseException |
| | | { |
| | | CursorConfig cursorConfig = null; |
| | | byte[] normDN = StaticUtils.getBytes(dn.toNormalizedString()); |
| | | byte[] normDN = JebFormat.dnToDNKey(dn, prefixRDNComponents); |
| | | byte[] URIBytes = StaticUtils.getBytes(labeledURI); |
| | | DatabaseEntry key = new DatabaseEntry(normDN); |
| | | DatabaseEntry data = new DatabaseEntry(URIBytes); |
| | |
| | | dn = entryContainer.getParentWithinBase(dn)) |
| | | { |
| | | // Look for a record whose key matches the current DN. |
| | | String normDN = dn.toNormalizedString(); |
| | | key.setData(StaticUtils.getBytes(normDN)); |
| | | key.setData(JebFormat.dnToDNKey(dn, prefixRDNComponents)); |
| | | OperationStatus status = |
| | | cursor.getSearchKey(key, data, LockMode.DEFAULT); |
| | | if (status == OperationStatus.SUCCESS) |
| | |
| | | * find subordinates of the base entry from the top of the tree |
| | | * downwards. |
| | | */ |
| | | DN baseDN = searchOp.getBaseDN(); |
| | | String normBaseDN = baseDN.toNormalizedString(); |
| | | byte[] suffix = StaticUtils.getBytes("," + normBaseDN); |
| | | byte[] baseDN = JebFormat.dnToDNKey(searchOp.getBaseDN(), |
| | | prefixRDNComponents); |
| | | byte[] suffix = Arrays.copyOf(baseDN, baseDN.length+1); |
| | | suffix[suffix.length-1] = 0x00; |
| | | byte[] end = suffix.clone(); |
| | | end[end.length-1] = (byte) (end[end.length-1] + 1); |
| | | |
| | | /* |
| | | * Set the ending value to a value of equal length but slightly |
| | |
| | | * reverse order we must set the first byte (the comma). |
| | | * No possibility of overflow here. |
| | | */ |
| | | byte[] end = null; |
| | | |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | DatabaseEntry key = new DatabaseEntry(suffix); |
| | |
| | | status == OperationStatus.SUCCESS; |
| | | status = cursor.getNextNoDup(key, data, LockMode.DEFAULT)) |
| | | { |
| | | if (end == null) |
| | | { |
| | | end = suffix.clone(); |
| | | end[0] = (byte) (end[0] + 1); |
| | | } |
| | | |
| | | int cmp = dn2uriComparator.compare(key.getData(), end); |
| | | if (cmp >= 0) |
| | |
| | | } |
| | | |
| | | // We have found a subordinate referral. |
| | | DN dn = DN.decode(ByteString.wrap(key.getData())); |
| | | DN dn = JebFormat.dnFromDNKey(key.getData(), 0, key.getSize(), |
| | | entryContainer.getBaseDN()); |
| | | |
| | | // Make sure the referral is within scope. |
| | | if (searchOp.getScope() == SearchScope.SINGLE_LEVEL) |
| | | { |
| | | if ((dn.getNumComponents() != |
| | | baseDN.getNumComponents() + 1)) |
| | | if(JebFormat.findDNKeyParent(key.getData(), 0, |
| | | key.getSize()) == baseDN.length) |
| | | { |
| | | continue; |
| | | } |
| | |
| | | { |
| | | if (ldapurl.getBaseDN().isNullDN()) |
| | | { |
| | | |
| | | ldapurl.setBaseDN(dn); |
| | | } |
| | | ldapurl.getAttributes().clear(); |
| | |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * Gets the comparator for records stored in this database. |
| | | * |
| | | * @return The comparator used for records stored in this database. |
| | | */ |
| | | public Comparator<byte[]> getComparator() |
| | | { |
| | | return dn2uriComparator; |
| | | } |
| | | } |
| | |
| | | * "cn=joe,ou=people,dc=example,dc=com" will appear after the entry |
| | | * "ou=people,dc=example,dc=com". |
| | | */ |
| | | byte[] suffix = StaticUtils.getBytes("," + baseDN.toNormalizedString()); |
| | | byte[] baseDNKey = JebFormat.dnToDNKey(baseDN, |
| | | this.baseDN.getNumComponents()); |
| | | byte[] suffix = Arrays.copyOf(baseDNKey, baseDNKey.length+1); |
| | | suffix[suffix.length-1] = 0x00; |
| | | |
| | | /* |
| | | * Set the ending value to a value of equal length but slightly |
| | |
| | | * No possibility of overflow here. |
| | | */ |
| | | byte[] end = suffix.clone(); |
| | | end[0] = (byte) (end[0] + 1); |
| | | end[end.length-1] = (byte) (end[end.length-1] + 1); |
| | | |
| | | // Set the starting value. |
| | | byte[] begin; |
| | |
| | | // We have found a subordinate entry. |
| | | |
| | | EntryID entryID = new EntryID(data); |
| | | DN dn = DN.decode(ByteString.wrap(key.getData())); |
| | | |
| | | boolean isInScope = true; |
| | | if (searchScope == SearchScope.SINGLE_LEVEL) |
| | | { |
| | | // Check if this entry is an immediate child. |
| | | if ((dn.getNumComponents() != |
| | | baseDN.getNumComponents() + 1)) |
| | | if(JebFormat.findDNKeyParent(key.getData(), 0, |
| | | key.getSize()) == baseDNKey.length) |
| | | { |
| | | isInScope = false; |
| | | } |
| | |
| | | * find subordinates of the target entry from the top of the tree |
| | | * downwards. |
| | | */ |
| | | byte[] suffix = StaticUtils.getBytes("," + |
| | | entryDN.toNormalizedString()); |
| | | byte[] entryDNKey = JebFormat.dnToDNKey(entryDN, |
| | | this.baseDN.getNumComponents()); |
| | | byte[] suffix = Arrays.copyOf(entryDNKey, entryDNKey.length+1); |
| | | suffix[suffix.length-1] = 0x00; |
| | | |
| | | /* |
| | | * Set the ending value to a value of equal length but slightly |
| | | * greater than the suffix. |
| | | */ |
| | | byte[] end = suffix.clone(); |
| | | end[0] = (byte) (end[0] + 1); |
| | | end[end.length-1] = (byte) (end[end.length-1] + 1); |
| | | |
| | | int subordinateEntriesDeleted = 0; |
| | | |
| | |
| | | * we have been deleting from the bottom of the tree upwards. |
| | | */ |
| | | EntryID entryID = new EntryID(data); |
| | | DN subordinateDN = DN.decode(ByteString.wrap(key.getData())); |
| | | |
| | | // Invoke any subordinate delete plugins on the entry. |
| | | if (!deleteOperation.isSynchronizationOperation()) |
| | |
| | | { |
| | | Message message = |
| | | ERR_JEB_DELETE_ABORTED_BY_SUBORDINATE_PLUGIN.get( |
| | | subordinateDN.toString()); |
| | | JebFormat.dnFromDNKey(key.getData(), 0, 0, getBaseDN()). |
| | | toString()); |
| | | throw new DirectoryException( |
| | | DirectoryServer.getServerErrorResultCode(), message); |
| | | } |
| | | } |
| | | |
| | | deleteEntry(txn, indexBuffer, true, entryDN, subordinateDN, entryID); |
| | | deleteEntry(txn, indexBuffer, true, entryDN, key, entryID); |
| | | subordinateEntriesDeleted++; |
| | | |
| | | if(deleteOperation != null) |
| | |
| | | IndexBuffer indexBuffer, |
| | | boolean manageDsaIT, |
| | | DN targetDN, |
| | | DN leafDN, |
| | | DatabaseEntry leafDNKey, |
| | | EntryID leafID) |
| | | throws DatabaseException, DirectoryException, JebException |
| | | { |
| | | if(leafID == null || leafDN == null) |
| | | if(leafID == null || leafDNKey == null) |
| | | { |
| | | // Read the entry ID from dn2id. |
| | | leafDN = targetDN; |
| | | leafID = dn2id.get(txn, leafDN, LockMode.RMW); |
| | | if (leafID == null) |
| | | if(leafDNKey == null) |
| | | { |
| | | leafDNKey = |
| | | new DatabaseEntry(JebFormat.dnToDNKey( |
| | | targetDN, this.baseDN.getNumComponents())); |
| | | } |
| | | DatabaseEntry value = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | status = dn2id.read(txn, leafDNKey, value, LockMode.RMW); |
| | | if (status != OperationStatus.SUCCESS) |
| | | { |
| | | Message message = |
| | | ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString()); |
| | | ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDNKey.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | | } |
| | | leafID = new EntryID(value); |
| | | } |
| | | |
| | | // Remove from dn2id. |
| | | if (!dn2id.remove(txn, leafDN)) |
| | | if (dn2id.delete(txn, leafDNKey) != OperationStatus.SUCCESS) |
| | | { |
| | | // Do not expect to ever come through here. |
| | | Message message = ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDN.toString()); |
| | | Message message = ERR_JEB_DELETE_NO_SUCH_OBJECT.get(leafDNKey.toString()); |
| | | DN matchedDN = getMatchedDN(baseDN); |
| | | throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, |
| | | message, matchedDN, null); |
| | |
| | | EntryCache<?> entryCache = DirectoryServer.getEntryCache(); |
| | | if (entryCache != null) |
| | | { |
| | | entryCache.removeEntry(leafDN); |
| | | entryCache.removeEntry(entry.getDN()); |
| | | } |
| | | } |
| | | |
| | |
| | | * find subordinates of the target entry from the top of the tree |
| | | * downwards. |
| | | */ |
| | | byte[] suffix = StaticUtils.getBytes("," + |
| | | currentDN.toNormalizedString()); |
| | | byte[] currentDNKey = JebFormat.dnToDNKey(currentDN, |
| | | this.baseDN.getNumComponents()); |
| | | byte[] suffix = Arrays.copyOf(currentDNKey, currentDNKey.length+1); |
| | | suffix[suffix.length-1] = 0x00; |
| | | |
| | | /* |
| | | * Set the ending value to a value of equal length but slightly |
| | | * greater than the suffix. |
| | | */ |
| | | byte[] end = suffix.clone(); |
| | | end[0] = (byte) (end[0] + 1); |
| | | end[end.length-1] = (byte) (end[end.length-1] + 1); |
| | | |
| | | DatabaseEntry data = new DatabaseEntry(); |
| | | DatabaseEntry key = new DatabaseEntry(suffix); |
| | |
| | | } |
| | | |
| | | /** |
| | | * A lexicographic byte array comparator that compares in |
| | | * reverse byte order. This is used for the dn2id database. |
| | | * If we want to find all the entries in a subtree dc=com we know that |
| | | * all subordinate entries must have ,dc=com as a common suffix. In reversing |
| | | * the order of comparison we turn the subtree base into a common prefix |
| | | * and are able to iterate through the keys having that prefix. |
| | | */ |
| | | static public class KeyReverseComparator implements Comparator<byte[]> |
| | | { |
| | | /** |
| | | * Compares its two arguments for order. Returns a negative integer, |
| | | * zero, or a positive integer as the first argument is less than, equal |
| | | * to, or greater than the second. |
| | | * |
| | | * @param a the first object to be compared. |
| | | * @param b the second object to be compared. |
| | | * @return a negative integer, zero, or a positive integer as the |
| | | * first argument is less than, equal to, or greater than the |
| | | * second. |
| | | */ |
| | | public int compare(byte[] a, byte[] b) |
| | | { |
| | | for (int ai = a.length - 1, bi = b.length - 1; |
| | | ai >= 0 && bi >= 0; ai--, bi--) |
| | | { |
| | | if (a[ai] > b[bi]) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (a[ai] < b[bi]) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | if (a.length == b.length) |
| | | { |
| | | return 0; |
| | | } |
| | | if (a.length > b.length) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Insert a new entry into the attribute indexes. |
| | | * |
| | | * @param txn The database transaction to be used for the updates. |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | import org.opends.messages.Message; |
| | |
| | | * @return true if the entry was written, false if it was not. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public boolean putRaw(Transaction txn, DatabaseEntry key, DatabaseEntry data) |
| | | public OperationStatus put(Transaction txn, DatabaseEntry key, |
| | | DatabaseEntry data) |
| | | throws DatabaseException |
| | | { |
| | | OperationStatus status; |
| | | status = put(txn, key, data); |
| | | if (status != OperationStatus.SUCCESS) |
| | | { |
| | | return false; |
| | | } |
| | | return true; |
| | | return super.put(txn, key, data); |
| | | } |
| | | |
| | | /** |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | | import static org.opends.server.loggers.debug.DebugLogger.*; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.RDN; |
| | | import org.opends.server.types.ByteStringBuilder; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.util.StaticUtils; |
| | | |
| | | import java.util.TreeSet; |
| | | import java.util.Iterator; |
| | | |
| | | /** |
| | | * Handles the disk representation of LDAP data. |
| | |
| | | |
| | | return bytes; |
| | | } |
| | | |
| | | /** |
| | | * Decode a DN value from its database key representation. |
| | | * |
| | | * @param dnKey The database key value of the DN. |
| | | * @param offset Starting position in the database key data. |
| | | * @param length The length of the database key data. |
| | | * @param prefix The DN to prefix the deocded DN value. |
| | | * @return The decoded DN value. |
| | | * @throws DirectoryException if an error occurs while decoding the DN value. |
| | | */ |
| | | public static DN dnFromDNKey(byte[] dnKey, int offset, int length, DN prefix) |
| | | throws DirectoryException |
| | | { |
| | | DN dn = prefix; |
| | | int start = offset; |
| | | boolean escaped = false; |
| | | ByteStringBuilder buffer = new ByteStringBuilder(); |
| | | for(int i = start; i < length; i++) |
| | | { |
| | | if(dnKey[i] == 0x5C) |
| | | { |
| | | escaped = true; |
| | | continue; |
| | | } |
| | | else if(!escaped && dnKey[i] == 0x01) |
| | | { |
| | | buffer.append(0x01); |
| | | escaped = false; |
| | | continue; |
| | | } |
| | | else if(!escaped && dnKey[i] == 0x00) |
| | | { |
| | | if(buffer.length() > 0) |
| | | { |
| | | dn = dn.concat(RDN.decode(buffer.toString())); |
| | | buffer.clear(); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if(escaped) |
| | | { |
| | | buffer.append(0x5C); |
| | | escaped = false; |
| | | } |
| | | buffer.append(dnKey[i]); |
| | | } |
| | | } |
| | | |
| | | if(buffer.length() > 0) |
| | | { |
| | | dn = dn.concat(RDN.decode(buffer.toString())); |
| | | } |
| | | |
| | | return dn; |
| | | } |
| | | |
| | | /** |
| | | * Find the length of bytes that represents the superior DN of the given |
| | | * DN key. The superior DN is represented by the initial bytes of the DN key. |
| | | * |
| | | * @param dnKey The database key value of the DN. |
| | | * @param offset Starting position in the database key data. |
| | | * @param length The length of the database key data. |
| | | * @return The length of the superior DN or -1 if the given dn is the |
| | | * root DN or 0 if the superior DN is removed. |
| | | */ |
| | | public static int findDNKeyParent(byte[] dnKey, int offset, int length) |
| | | { |
| | | if(length == 0) |
| | | { |
| | | // This is the root or base DN |
| | | return -1; |
| | | } |
| | | |
| | | // We will walk backwords through the buffer and find the first |
| | | // unescaped comma |
| | | for(int i = offset+length - 1; i >= offset; i--) |
| | | { |
| | | if(dnKey[i] == 0x00 && i-1 >= offset && dnKey[i-1] != 0x5C) |
| | | { |
| | | return i; |
| | | } |
| | | } |
| | | return offset; |
| | | } |
| | | |
| | | /** |
| | | * Create a DN database key from an entry DN. |
| | | * @param dn The entry DN. |
| | | * @param prefixRDNs The number of prefix RDNs to remove from the encoded |
| | | * representation. |
| | | * @return A DatabaseEntry containing the key. |
| | | */ |
| | | public static byte[] dnToDNKey(DN dn, int prefixRDNs) |
| | | { |
| | | StringBuilder buffer = new StringBuilder(); |
| | | for (int i = dn.getNumComponents() - prefixRDNs - 1; i >= 0; i--) |
| | | { |
| | | buffer.append('\u0000'); |
| | | formatRDNKey(dn.getRDN(i), buffer); |
| | | } |
| | | |
| | | return StaticUtils.getBytes(buffer.toString()); |
| | | } |
| | | |
| | | private static void formatRDNKey(RDN rdn, StringBuilder buffer) |
| | | { |
| | | if (!rdn.isMultiValued()) |
| | | { |
| | | rdn.toNormalizedString(buffer); |
| | | } |
| | | else |
| | | { |
| | | TreeSet<String> rdnElementStrings = new TreeSet<String>(); |
| | | |
| | | for (int i=0; i < rdn.getNumValues(); i++) |
| | | { |
| | | StringBuilder b2 = new StringBuilder(); |
| | | rdn.getAVAString(i, b2); |
| | | rdnElementStrings.add(b2.toString()); |
| | | } |
| | | |
| | | Iterator<String> iterator = rdnElementStrings.iterator(); |
| | | buffer.append(iterator.next().replace("\u0001", "\\\u0001")); |
| | | |
| | | while (iterator.hasNext()) |
| | | { |
| | | buffer.append('\u0001'); |
| | | buffer.append(iterator.next().replace("\u0001", "\\\u0001")); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | import org.opends.messages.Message; |
| | |
| | | { |
| | | keyCount++; |
| | | |
| | | DN dn; |
| | | try |
| | | { |
| | | dn = DN.decode(ByteString.wrap(key.getData())); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | errorCount++; |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | |
| | | TRACER.debugError("File dn2id has malformed key %s.%n", |
| | | StaticUtils.bytesToHex(key.getData())); |
| | | } |
| | | continue; |
| | | } |
| | | |
| | | EntryID entryID; |
| | | try |
| | | { |
| | |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | |
| | | TRACER.debugError("File dn2id has malformed ID for DN <%s>:%n%s%n", |
| | | dn.toNormalizedString(), |
| | | new String(key.getData()), |
| | | StaticUtils.bytesToHex(data.getData())); |
| | | } |
| | | continue; |
| | |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugError("File dn2id has DN <%s> referencing unknown " + |
| | | "ID %d%n", dn.toNormalizedString(), entryID.longValue()); |
| | | "ID %d%n", new String(key.getData()), entryID.longValue()); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (!entry.getDN().equals(dn)) |
| | | if (!Arrays.equals(JebFormat.dnToDNKey( |
| | | entry.getDN(), verifyConfig.getBaseDN().getNumComponents()), |
| | | key.getData())) |
| | | { |
| | | errorCount++; |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugError("File dn2id has DN <%s> referencing entry " + |
| | | "with wrong DN <%s>%n", dn.toNormalizedString(), |
| | | "with wrong DN <%s>%n", new String(key.getData()), |
| | | entry.getDN().toNormalizedString()); |
| | | } |
| | | } |
| | |
| | | |
| | | //The DN attribute type. |
| | | private static AttributeType dnType; |
| | | |
| | | //Comparators for DN and indexes respectively. |
| | | private static final IndexBuffer.DNComparator dnComparator |
| | | = new IndexBuffer.DNComparator(); |
| | | private static final IndexBuffer.IndexComparator indexComparator = |
| | | new IndexBuffer.IndexComparator(); |
| | | |
| | |
| | | entryContainer.getDN2ID().getComparator(); |
| | | try { |
| | | for(DN excludedDN : suffix.getExcludeBranches()) { |
| | | byte[] bytes = |
| | | StaticUtils.getBytes(excludedDN.toNormalizedString()); |
| | | byte[] bytes = JebFormat.dnToDNKey( |
| | | excludedDN, suffix.getBaseDN().getNumComponents()); |
| | | key.setData(bytes); |
| | | status = cursor.getSearchKeyRange(key, data, lockMode); |
| | | if(status == OperationStatus.SUCCESS && |
| | |
| | | // This is the base entry for a branch that was excluded in the |
| | | // import so we must migrate all entries in this branch over to |
| | | // the new entry container. |
| | | byte[] end = StaticUtils.getBytes("," + |
| | | excludedDN.toNormalizedString()); |
| | | end[0] = (byte) (end[0] + 1); |
| | | byte[] end = Arrays.copyOf(bytes, bytes.length+1); |
| | | end[end.length-1] = 0x01; |
| | | |
| | | while(status == OperationStatus.SUCCESS && |
| | | comparator.compare(key.getData(), end) < 0 && |
| | |
| | | public Void call() throws Exception |
| | | { |
| | | for(Suffix suffix : dnSuffixMap.values()) { |
| | | List<byte[]> includeBranches = |
| | | new ArrayList<byte[]>(suffix.getIncludeBranches().size()); |
| | | for(DN includeBranch : suffix.getIncludeBranches()) |
| | | { |
| | | if(includeBranch.isDescendantOf(suffix.getBaseDN())) |
| | | { |
| | | includeBranches.add(JebFormat.dnToDNKey( |
| | | includeBranch, suffix.getBaseDN().getNumComponents())); |
| | | } |
| | | } |
| | | |
| | | EntryContainer entryContainer = suffix.getSrcEntryContainer(); |
| | | if(entryContainer != null && |
| | | !suffix.getIncludeBranches().isEmpty()) { |
| | |
| | | status = cursor.getFirst(key, data, lockMode); |
| | | while(status == OperationStatus.SUCCESS && |
| | | !importConfiguration.isCancelled() && !isPhaseOneCanceled) { |
| | | DN dn = DN.decode(ByteString.wrap(key.getData())); |
| | | if(!suffix.getIncludeBranches().contains(dn)) { |
| | | |
| | | boolean found = false; |
| | | for(byte[] includeBranch : includeBranches) |
| | | { |
| | | if(Arrays.equals(includeBranch, key.getData())) |
| | | { |
| | | found = true; |
| | | break; |
| | | } |
| | | } |
| | | if(!found) { |
| | | EntryID id = new EntryID(data); |
| | | Entry entry = |
| | | entryContainer.getID2Entry().get(null, |
| | |
| | | * (the comma). |
| | | * No possibility of overflow here. |
| | | */ |
| | | byte[] begin = |
| | | StaticUtils.getBytes("," + dn.toNormalizedString()); |
| | | begin[0] = (byte) (begin[0] + 1); |
| | | byte[] begin = Arrays.copyOf(key.getData(), key.getSize()+1); |
| | | begin[begin.length-1] = 0x01; |
| | | key.setData(begin); |
| | | status = cursor.getSearchKeyRange(key, data, lockMode); |
| | | } |
| | |
| | | IndexBuffer indexBuffer = e.getValue(); |
| | | setIterator.remove(); |
| | | ImportIndexType indexType = indexKey.getIndexType(); |
| | | if(indexType.equals(ImportIndexType.DN)) |
| | | { |
| | | indexBuffer.setComparator(dnComparator); |
| | | } |
| | | else |
| | | { |
| | | indexBuffer.setComparator(indexComparator); |
| | | } |
| | | indexBuffer.setComparator(indexComparator); |
| | | indexBuffer.setIndexKey(indexKey); |
| | | indexBuffer.setDiscard(); |
| | | Future<Void> future = |
| | |
| | | void processDN2ID(Suffix suffix, DN dn, EntryID entryID) |
| | | throws ConfigException, InterruptedException |
| | | { |
| | | DatabaseContainer dn2id = suffix.getDN2ID(); |
| | | byte[] dnBytes = StaticUtils.getBytes(dn.toNormalizedString()); |
| | | int id = processKey(dn2id, dnBytes, entryID, dnComparator, |
| | | DN2ID dn2id = suffix.getDN2ID(); |
| | | byte[] dnBytes = |
| | | JebFormat.dnToDNKey(dn, suffix.getBaseDN().getNumComponents()); |
| | | int id = processKey(dn2id, dnBytes, entryID, indexComparator, |
| | | new IndexKey(dnType, ImportIndexType.DN, 1), true); |
| | | idECMap.putIfAbsent(id, suffix.getEntryContainer()); |
| | | } |
| | |
| | | { |
| | | private final int DN_STATE_CACHE_SIZE = 64 * KB; |
| | | |
| | | private DN parentDN, lastDN; |
| | | private ByteBuffer parentDN, lastDN; |
| | | private EntryID parentID, lastID, entryID; |
| | | private final DatabaseEntry DNKey, DNValue; |
| | | private final TreeMap<DN, EntryID> parentIDMap = |
| | | new TreeMap<DN, EntryID>(); |
| | | private final TreeMap<ByteBuffer, EntryID> parentIDMap; |
| | | private final EntryContainer entryContainer; |
| | | private final Map<byte[], ImportIDSet> id2childTree; |
| | | private final Map<byte[], ImportIDSet> id2subtreeTree; |
| | |
| | | DNState(EntryContainer entryContainer) |
| | | { |
| | | this.entryContainer = entryContainer; |
| | | parentIDMap = new TreeMap<ByteBuffer, EntryID>(); |
| | | Comparator<byte[]> childComparator = |
| | | entryContainer.getID2Children().getComparator(); |
| | | id2childTree = new TreeMap<byte[], ImportIDSet>(childComparator); |
| | |
| | | id2subtreeTree = new TreeMap<byte[], ImportIDSet>(subComparator); |
| | | DNKey = new DatabaseEntry(); |
| | | DNValue = new DatabaseEntry(); |
| | | lastDN = ByteBuffer.allocate(BYTE_BUFFER_CAPACITY); |
| | | } |
| | | |
| | | |
| | | private ByteBuffer getParent(ByteBuffer buffer) |
| | | { |
| | | int parentIndex = |
| | | JebFormat.findDNKeyParent(buffer.array(), 0, buffer.limit()); |
| | | if(parentIndex < 0) |
| | | { |
| | | // This is the root or base DN |
| | | return null; |
| | | } |
| | | ByteBuffer parent = buffer.duplicate(); |
| | | parent.limit(parentIndex); |
| | | return parent; |
| | | } |
| | | |
| | | private ByteBuffer deepCopy(ByteBuffer srcBuffer, ByteBuffer destBuffer) |
| | | { |
| | | if(destBuffer == null || |
| | | destBuffer.clear().remaining() < srcBuffer.limit()) |
| | | { |
| | | byte[] bytes = new byte[srcBuffer.limit()]; |
| | | System.arraycopy(srcBuffer.array(), 0, bytes, 0, |
| | | srcBuffer.limit()); |
| | | return ByteBuffer.wrap(bytes); |
| | | } |
| | | else |
| | | { |
| | | destBuffer.put(srcBuffer); |
| | | destBuffer.flip(); |
| | | return destBuffer; |
| | | } |
| | | } |
| | | |
| | | // Why do we still need this if we are checking parents in the first |
| | | // phase? |
| | | private boolean checkParent(ImportIDSet record) throws DirectoryException, |
| | | DatabaseException |
| | | { |
| | | DN dn = DN.decode(new String(record.getKey().array(), 0 , |
| | | record.getKey().limit())); |
| | | DNKey.setData(record.getKey().array(), 0 , record.getKey().limit()); |
| | | byte[] v = record.toDatabase(); |
| | | long v1 = JebFormat.entryIDFromDatabase(v); |
| | | DNValue.setData(v); |
| | | |
| | | entryID = new EntryID(v1); |
| | | parentDN = getParent(record.getKey()); |
| | | |
| | | //Bypass the cache for append data, lookup the parent in DN2ID and |
| | | //return. |
| | | if(importConfiguration != null && |
| | | importConfiguration.appendToExistingData()) |
| | | { |
| | | parentDN = entryContainer.getParentWithinBase(dn); |
| | | //If null is returned than this is a suffix DN. |
| | | if(parentDN != null) |
| | | { |
| | | parentID = |
| | | entryContainer.getDN2ID().get(null, parentDN, LockMode.DEFAULT); |
| | | DatabaseEntry key = new DatabaseEntry(parentDN.array()); |
| | | DatabaseEntry value = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | status = |
| | | entryContainer.getDN2ID().read(null, key, value, |
| | | LockMode.DEFAULT); |
| | | if(status == OperationStatus.SUCCESS) |
| | | { |
| | | parentID = new EntryID(value); |
| | | } |
| | | else |
| | | { |
| | | // We have a missing parent. Maybe parent checking was turned off? |
| | | // Just ignore. |
| | | parentID = null; |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if(parentIDMap.isEmpty()) |
| | | { |
| | | parentIDMap.put(dn, entryID); |
| | | parentIDMap.put(deepCopy(record.getKey(), null), entryID); |
| | | return true; |
| | | } |
| | | else if(lastDN != null && lastDN.isAncestorOf(dn)) |
| | | else if(lastDN != null && lastDN.equals(parentDN)) |
| | | { |
| | | parentIDMap.put(lastDN, lastID); |
| | | parentDN = lastDN; |
| | | parentIDMap.put(deepCopy(lastDN, null), lastID); |
| | | parentID = lastID; |
| | | lastDN = dn; |
| | | lastDN = deepCopy(record.getKey(), lastDN); |
| | | lastID = entryID; |
| | | return true; |
| | | } |
| | | else if(parentIDMap.lastKey().isAncestorOf(dn)) |
| | | else if(parentIDMap.lastKey().equals(parentDN)) |
| | | { |
| | | parentDN = parentIDMap.lastKey(); |
| | | parentID = parentIDMap.get(parentDN); |
| | | lastDN = dn; |
| | | lastDN = deepCopy(record.getKey(), lastDN); |
| | | lastID = entryID; |
| | | return true; |
| | | } |
| | | else |
| | | { |
| | | DN newParentDN = entryContainer.getParentWithinBase(dn); |
| | | if(parentIDMap.containsKey(newParentDN)) |
| | | if(parentIDMap.containsKey(parentDN)) |
| | | { |
| | | EntryID newParentID = parentIDMap.get(newParentDN); |
| | | DN lastDN = parentIDMap.lastKey(); |
| | | while(!newParentDN.equals(lastDN)) { |
| | | parentIDMap.remove(lastDN); |
| | | lastDN = parentIDMap.lastKey(); |
| | | EntryID newParentID = parentIDMap.get(parentDN); |
| | | ByteBuffer key = parentIDMap.lastKey(); |
| | | while(!parentDN.equals(key)) { |
| | | parentIDMap.remove(key); |
| | | key = parentIDMap.lastKey(); |
| | | } |
| | | parentIDMap.put(dn, entryID); |
| | | parentDN = newParentDN; |
| | | parentIDMap.put(deepCopy(record.getKey(), null), entryID); |
| | | parentID = newParentID; |
| | | lastDN = dn; |
| | | lastDN = deepCopy(record.getKey(), lastDN); |
| | | lastID = entryID; |
| | | } |
| | | else |
| | | { |
| | | Message message = |
| | | NOTE_JEB_IMPORT_LDIF_DN_NO_PARENT.get(dn.toString()); |
| | | Entry e = new Entry(dn, null, null, null); |
| | | reader.rejectEntry(e, message); |
| | | // We have a missing parent. Maybe parent checking was turned off? |
| | | // Just ignore. |
| | | parentID = null; |
| | | return false; |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | |
| | | private EntryID getParentID(DN dn) throws DatabaseException |
| | | private EntryID getParentID(ByteBuffer dn) throws DatabaseException |
| | | { |
| | | EntryID nodeID; |
| | | //Bypass the cache for append data, lookup the parent DN in the DN2ID |
| | |
| | | if (importConfiguration != null && |
| | | importConfiguration.appendToExistingData()) |
| | | { |
| | | nodeID = entryContainer.getDN2ID().get(null, dn, LockMode.DEFAULT); |
| | | DatabaseEntry key = new DatabaseEntry(dn.array()); |
| | | DatabaseEntry value = new DatabaseEntry(); |
| | | OperationStatus status; |
| | | status = |
| | | entryContainer.getDN2ID().read(null, key, value, |
| | | LockMode.DEFAULT); |
| | | if(status == OperationStatus.SUCCESS) |
| | | { |
| | | nodeID = new EntryID(value); |
| | | } |
| | | else |
| | | { |
| | | nodeID = null; |
| | | } |
| | | } |
| | | else |
| | | { |
| | |
| | | idSet = id2subtreeTree.get(parentID.getDatabaseEntry().getData()); |
| | | } |
| | | idSet.addEntryID(childID); |
| | | for (DN dn = entryContainer.getParentWithinBase(parentDN); dn != null; |
| | | dn = entryContainer.getParentWithinBase(dn)) |
| | | // TODO: |
| | | // Instead of doing this, we can just walk to parent cache if available |
| | | for (ByteBuffer dn = getParent(parentDN); dn != null; |
| | | dn = getParent(dn)) |
| | | { |
| | | EntryID nodeID = getParentID(dn); |
| | | if(nodeID == null) |
| | |
| | | |
| | | public void writeToDB() throws DatabaseException, DirectoryException |
| | | { |
| | | entryContainer.getDN2ID().putRaw(null, DNKey, DNValue); |
| | | entryContainer.getDN2ID().put(null, DNKey, DNValue); |
| | | indexMgr.addTotDNCount(1); |
| | | if(parentDN != null) |
| | | { |
| | |
| | | { |
| | | getIndexID(); |
| | | } |
| | | if(indexMgr.isDN2ID()) |
| | | { |
| | | rc = dnComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | cKey.array(), cKey.limit()); |
| | | } |
| | | else |
| | | { |
| | | rc = indexComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | rc = indexComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | cKey.array(), cKey.limit()); |
| | | } |
| | | if(rc != 0) { |
| | | returnCode = 1; |
| | | } |
| | |
| | | int returnCode; |
| | | byte[] oKey = o.getKeyBuf().array(); |
| | | int oLen = o.getKeyBuf().limit(); |
| | | if(indexMgr.isDN2ID()) |
| | | { |
| | | returnCode = dnComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | oKey, oLen); |
| | | } |
| | | else |
| | | { |
| | | returnCode = indexComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | returnCode = indexComparator.compare(keyBuf.array(), 0, keyBuf.limit(), |
| | | oKey, oLen); |
| | | } |
| | | if(returnCode == 0) |
| | | { |
| | | if(indexID.intValue() == o.getIndexID().intValue()) |
| | |
| | | { |
| | | int pLen = PackedInteger.getReadIntLength(bytes, pos); |
| | | len = PackedInteger.readInt(bytes, pos); |
| | | if(dnComparator.compare(bytes, pos + pLen, len, dnBytes, |
| | | if(indexComparator.compare(bytes, pos + pLen, len, dnBytes, |
| | | dnBytes.length) == 0) |
| | | { |
| | | return true; |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009 Sun Microsystems, Inc. |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | |
| | |
| | | |
| | | /** |
| | | * Implementation of ComparatorBuffer interface. Used to compare keys when |
| | | * they are DN index is being processed. |
| | | */ |
| | | public static |
| | | class DNComparator implements IndexBuffer.ComparatorBuffer<byte[]> |
| | | { |
| | | |
| | | /** |
| | | * Compare two offsets in an byte array using the DN compare algorithm. |
| | | * The specified index ID is used in the comparision if the byte arrays |
| | | * are equal. |
| | | * |
| | | * @param b The byte array. |
| | | * @param offset The first offset. |
| | | * @param length The first length. |
| | | * @param indexID The first index id. |
| | | * @param otherOffset The second offset. |
| | | * @param otherLength The second length. |
| | | * @param otherIndexID The second index id. |
| | | * @return a negative integer, zero, or a positive integer as the first |
| | | * offset value is less than, equal to, or greater than the second. |
| | | */ |
| | | public int compare(byte[] b, int offset, int length, int indexID, |
| | | int otherOffset, int otherLength, int otherIndexID) |
| | | { |
| | | for (int i = length - 1, j = otherLength - 1; |
| | | i >= 0 && j >= 0; i--, j--) { |
| | | if (b[offset + i] > b[otherOffset + j]) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (b[offset + i] < b[otherOffset + j]) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | //The arrays are equal, make sure they are in the same index since |
| | | //multiple suffixes might have the same key. |
| | | if(length == otherLength) |
| | | { |
| | | if(indexID == otherIndexID) |
| | | { |
| | | return 0; |
| | | } |
| | | else if(indexID > otherIndexID) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | if(length > otherLength) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Compare an offset in an byte array with the specified byte array, |
| | | * using the DN compare algorithm. The specified index ID is used in the |
| | | * comparision if the byte arrays are equal. |
| | | * |
| | | * @param b The byte array. |
| | | * @param offset The first offset. |
| | | * @param length The first length. |
| | | * @param indexID The first index id. |
| | | * @param other The second byte array to compare to. |
| | | * @param otherLength The second object's length. |
| | | * @param otherIndexID The second index id. |
| | | * @return a negative integer, zero, or a positive integer as the first |
| | | * offset value is less than, equal to, or greater than the second |
| | | * byte array. |
| | | */ |
| | | public int compare(byte[] b, int offset, int length, int indexID, |
| | | byte[]other, int otherLength, int otherIndexID) |
| | | { |
| | | for (int i = length - 1, j = otherLength - 1; |
| | | i >= 0 && j >= 0; i--, j--) { |
| | | if (b[offset + i] > other[j]) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (b[offset + i] < other[j]) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | //The arrays are equal, make sure they are in the same index since |
| | | //multiple suffixes might have the same key. |
| | | if(length == otherLength) |
| | | { |
| | | if(indexID == otherIndexID) |
| | | { |
| | | return 0; |
| | | } |
| | | else if(indexID > otherIndexID) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | if(length > otherLength) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Compare an offset in an byte array with the specified byte array, |
| | | * using the DN compare algorithm. |
| | | * |
| | | * @param b The byte array. |
| | | * @param offset The first offset. |
| | | * @param length The first length. |
| | | * @param other The second byte array to compare to. |
| | | * @param otherLength The second object's length. |
| | | * @return a negative integer, zero, or a positive integer as the first |
| | | * offset value is less than, equal to, or greater than the |
| | | * second byte array. |
| | | */ |
| | | public int compare(byte[] b, int offset, int length, byte[] other, |
| | | int otherLength) |
| | | { |
| | | for (int i = length - 1, j = otherLength - 1; |
| | | i >= 0 && j >= 0; i--, j--) { |
| | | if (b[offset + i] > other[j]) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (b[offset + i] < other[j]) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | if(length == otherLength) |
| | | { |
| | | return 0; |
| | | } |
| | | if(length > otherLength) |
| | | { |
| | | return 1; |
| | | } |
| | | else |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Implementation of ComparatorBuffer interface. Used to compare keys when |
| | | * they are non-DN indexes. |
| | | */ |
| | | public static |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.tools; |
| | | |
| | |
| | | OperationStatus status; |
| | | Comparator<byte[]> defaultComparator = |
| | | new AttributeIndex.KeyComparator(); |
| | | Comparator<byte[]> dnComparator = |
| | | new EntryContainer.KeyReverseComparator(); |
| | | byte[] start = null; |
| | | byte[] end = null; |
| | | int minSize = -1; |
| | |
| | | { |
| | | if(databaseContainer instanceof DN2ID) |
| | | { |
| | | if(dnComparator.compare(key.getData(), end) > 0) |
| | | if(defaultComparator.compare(key.getData(), end) > 0) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | else if(databaseContainer instanceof DN2URI) |
| | | { |
| | | if(dnComparator.compare(key.getData(), end) > 0) |
| | | if(defaultComparator.compare(key.getData(), end) > 0) |
| | | { |
| | | break; |
| | | } |
| | |
| | | { |
| | | try |
| | | { |
| | | formatedKey = DN.decode(ByteString.wrap(key.getData())). |
| | | toNormalizedString(); |
| | | formatedKey = JebFormat.dnFromDNKey( |
| | | key.getData(), 0, key.getSize(), ec.getBaseDN()). |
| | | toNormalizedString(); |
| | | keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get(); |
| | | } |
| | | catch(Exception e) |
| | |
| | | { |
| | | try |
| | | { |
| | | formatedKey = DN.decode(ByteString.wrap( |
| | | key.getData())).toNormalizedString(); |
| | | formatedKey = new String(key.getData()); |
| | | keyLabel = INFO_LABEL_DBTEST_ENTRY_DN.get(); |
| | | } |
| | | catch(Exception e) |
| | |
| | | |
| | | if (attributeNames.length == 1) |
| | | { |
| | | buffer.append( |
| | | attributeTypes[0].getNormalizedPrimaryNameOrOID()); |
| | | buffer.append('='); |
| | | |
| | | try |
| | | { |
| | | String s = attributeValues[0].getNormalizedValue().toString(); |
| | | buffer.append(getDNValue(s)); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | String s = attributeValues[0].getValue().toString(); |
| | | buffer.append(getDNValue(s)); |
| | | } |
| | | getAVAString(0, buffer); |
| | | } |
| | | else |
| | | { |
| | |
| | | for (int i=0; i < attributeNames.length; i++) |
| | | { |
| | | StringBuilder b2 = new StringBuilder(); |
| | | b2.append(attributeTypes[i].getNormalizedPrimaryNameOrOID()); |
| | | b2.append('='); |
| | | |
| | | try |
| | | { |
| | | String s = |
| | | attributeValues[i].getNormalizedValue().toString(); |
| | | b2.append(getDNValue(s)); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | String s = attributeValues[i].getValue().toString(); |
| | | b2.append(getDNValue(s)); |
| | | } |
| | | |
| | | getAVAString(i, b2); |
| | | rdnElementStrings.add(b2.toString()); |
| | | } |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Appends a normalized string representation of this RDN to the |
| | | * provided buffer. |
| | | * |
| | | * @param pos The position of the attribute type and value to |
| | | * retrieve. |
| | | * @param buffer The buffer to which to append the information. |
| | | */ |
| | | public void getAVAString(int pos, StringBuilder buffer) |
| | | { |
| | | buffer.append( |
| | | attributeTypes[pos].getNormalizedPrimaryNameOrOID()); |
| | | buffer.append('='); |
| | | |
| | | try |
| | | { |
| | | String s = |
| | | attributeValues[pos].getNormalizedValue().toString(); |
| | | buffer.append(getDNValue(s)); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | String s = attributeValues[pos].getValue().toString(); |
| | | buffer.append(getDNValue(s)); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Compares this RDN with the provided RDN based on an alphabetic |
| | | * comparison of the attribute names and values. |
| | | * |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | private String beID="userRoot"; |
| | | private BackendImpl be; |
| | | |
| | | private static final String ldifString = "dn: dc=com\n" |
| | | + "objectClass: top\n" + "objectClass: domain\n" + "\n" |
| | | + "dn: dc=example,dc=com\n" + "objectClass: top\n" |
| | | private static final String ldifString = "dn: dc=example,dc=com\n" |
| | | + "objectClass: top\n" |
| | | + "objectClass: domain\n" + "\n" |
| | | + "dn: ou=People,dc=example,dc=com\n" + "objectClass: top\n" |
| | | + "objectClass: organizationalUnit\n" + "\n" |
| | |
| | | + "telephoneNumber: 216-564-6748\n" + "employeeNumber: 1\n" |
| | | + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n" |
| | | + "userPassword: password\n" + "initials: AA\n" + "\n" |
| | | + "dn: o=Airius\n" + "objectClass: top\n" |
| | | + "dn: o=Airius,dc=example,dc=com\n" + "objectClass: top\n" |
| | | + "objectClass: organization\n" + "\n" |
| | | + "dn:: b3U95Za25qWt6YOoLG89QWlyaXVz\n" |
| | | + "dn:: b3U95Za25qWt6YOoLG89QWlyaXVzLGRjPWV4YW1wbGUsZGM9Y29t\n" |
| | | + "# dn:: ou=<JapaneseOU>,o=Airius\n" + "objectclass: top\n" |
| | | + "objectclass: organizationalUnit\n" + "ou:: 5Za25qWt6YOo\n" |
| | | + "# ou:: <JapaneseOU>\n" + "ou;lang-ja:: 5Za25qWt6YOo\n" |
| | |
| | | + "ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2\n" |
| | | + "# ou;lang-ja:: <JapaneseOU_in_phonetic_representation>\n" |
| | | + "ou;lang-en: Sales\n" + "description: Japanese office\n" + "\n" |
| | | + "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz\n" |
| | | + "dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVzLGRjPWV4YW1wbGUsZGM9Y29t\n" |
| | | + "# dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius\n" |
| | | + "userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=\n" |
| | | + "objectclass: top\n" + "objectclass: person\n" |
| | |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Copyright 2006-2010 Sun Microsystems, Inc. |
| | | */ |
| | | package org.opends.server.backends.jeb; |
| | | |
| | |
| | | new DatabaseEntry(StaticUtils.getBytes(badDN)); |
| | | DatabaseEntry data = |
| | | new EntryID(37).getDatabaseEntry(); |
| | | assertTrue(dn2id.putRaw(txn, key, data)); |
| | | assertEquals(dn2id.put(txn, key, data), OperationStatus.SUCCESS); |
| | | //Add DN key with malformed entryID |
| | | key=new DatabaseEntry(StaticUtils.getBytes(junkDN2)); |
| | | data= new DatabaseEntry(new byte[3]); |
| | | assertTrue(dn2id.putRaw(txn, key, data)); |
| | | assertEquals(dn2id.put(txn, key, data), OperationStatus.SUCCESS); |
| | | //Try to break JebFormat version |
| | | addID2EntryReturnKey(junkDN3, 20, true); |
| | | id=new EntryID(20); |
| | |
| | | ID2Entry.entryToDatabase(testEntry, |
| | | new DataConfig(false, false, null)); |
| | | DatabaseEntry data= new DatabaseEntry(entryBytes.toByteArray()); |
| | | assertTrue(id2entry.putRaw(txn, key, data)); |
| | | assertEquals(id2entry.put(txn, key, data), OperationStatus.SUCCESS); |
| | | |
| | | //add entry with ramdom bytes |
| | | DatabaseEntry key1= new EntryID(4).getDatabaseEntry(); |
| | |
| | | //set version correctly |
| | | eBytes[0]=0x01; |
| | | DatabaseEntry data1= new DatabaseEntry(eBytes); |
| | | assertTrue(id2entry.putRaw(txn, key1, data1)); |
| | | assertEquals(id2entry.put(txn, key1, data1), OperationStatus.SUCCESS); |
| | | performBECompleteVerify("telephoneNumber", 3); |
| | | } |
| | | finally |
| | |
| | | if(trashFormat) |
| | | entryBytes[0] = 0x67; |
| | | DatabaseEntry data= new DatabaseEntry(entryBytes); |
| | | assertTrue(id2entry.putRaw(txn, key, data)); |
| | | assertEquals(id2entry.put(txn, key, data), OperationStatus.SUCCESS); |
| | | return key; |
| | | } |
| | | |