OPENDJ-1602 (CR-5566) New pluggable storage based backend
Simplified code.
+-----+
| JEB |
+-----+
SortValuesSet.java:
Added add(SortValues), changed remove(long, ByteString[]) into remove(SortValues).
jeb.VLVIndex.java:
Used SortValuesSet new methods.
TestVerifyJob.java:
Adapted the code to SortValuesSet.remove() new signature.
+-----------+
| Pluggable |
+-----------+
Did the same changes as in JEB.
EntryContainer.java:
Used EntryID.toByteString() instead of the less efficient ByteString.valueOf(EntryID.longValue()).
Removed calls to EntryId.longValue() in logging calls.
JebFormat.java:
Removed entryIDToDatabase(), replaced by calls to EntryID.toByteString().
SuffixContainer.java:
Removed unused imports.
VerifyJob.java:
Used vlvIndex.encodeKey(SortValues).
Fixed formatting.
VLVIndex.java:
Changed encodeKey() visibility to package private.
| | |
| | | import com.sleepycat.je.DatabaseException; |
| | | |
| | | /** |
| | | * This class represents a partial sorted set of sorted entries in a VLV |
| | | * index. |
| | | * This class represents a partial sorted set of sorted entries in a VLV index. |
| | | */ |
| | | public class SortValuesSet |
| | | { |
| | |
| | | {} |
| | | |
| | | /** |
| | | * Add the given entryID and values from this VLV idnex. |
| | | * Add the given entryID and values from these sort values. |
| | | * |
| | | * @param sv The sort values to add. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | void add(SortValues sv) throws DatabaseException, DirectoryException |
| | | { |
| | | add(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | | } |
| | | |
| | | /** |
| | | * Add the given entryID and values from this VLV index. |
| | | * |
| | | * @param entryID The entry ID to add. |
| | | * @param values The values to add. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Remove the given entryID and values from this VLV idnex. |
| | | * Remove the given entryID and values from these sort values. |
| | | * |
| | | * @param entryID The entry ID to remove. |
| | | * @param values The values to remove. |
| | | * @return True if the information was successfully removed or False |
| | | * otherwise. |
| | | * @param sv The sort values to remove. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | public boolean remove(long entryID, ByteString[] values) |
| | | throws DatabaseException, DirectoryException |
| | | void remove(SortValues sv) throws DatabaseException, DirectoryException |
| | | { |
| | | if(entryIDs == null || entryIDs.length == 0) |
| | | { |
| | | return false; |
| | | return; |
| | | } |
| | | |
| | | if(valuesBytesOffsets == null) |
| | |
| | | updateValuesBytesOffsets(); |
| | | } |
| | | |
| | | int pos = binarySearch(entryID, values); |
| | | int pos = binarySearch(sv.getEntryID(), sv.getValues()); |
| | | if(pos < 0) |
| | | { |
| | | // Not found. |
| | | return false; |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | |
| | | // Found it. |
| | | long[] updatedEntryIDs = new long[entryIDs.length - 1]; |
| | | System.arraycopy(entryIDs, 0, updatedEntryIDs, 0, pos); |
| | |
| | | valuesBytes.length - valuesPos - valuesLength); |
| | | |
| | | int[] updatedValuesBytesOffsets = new int[valuesBytesOffsets.length - 1]; |
| | | System.arraycopy(valuesBytesOffsets, 0, updatedValuesBytesOffsets, |
| | | 0, pos); |
| | | System.arraycopy(valuesBytesOffsets, 0, updatedValuesBytesOffsets, 0, pos); |
| | | // Update the rest of the offsets one by one - Expensive! |
| | | for(int i = pos + 1; i < valuesBytesOffsets.length; i++) |
| | | { |
| | | updatedValuesBytesOffsets[i-1] = |
| | | valuesBytesOffsets[i] - valuesLength; |
| | | updatedValuesBytesOffsets[i - 1] = valuesBytesOffsets[i] - valuesLength; |
| | | } |
| | | |
| | | entryIDs = updatedEntryIDs; |
| | | valuesBytes = updatedValuesBytes; |
| | | valuesBytesOffsets = updatedValuesBytesOffsets; |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | // This is the last unbounded set. |
| | | while(av != null) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | sortValuesSet.add(av); |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | |
| | | |
| | | while(av != null && av.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | sortValuesSet.add(av); |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null && dv.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | |
| | | // The cookie contains the ID of the next entry to be returned. |
| | | try |
| | | { |
| | | begin = new EntryID(pageRequest.getCookie().toLong()); |
| | | begin = new EntryID(pageRequest.getCookie()); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | indexRemoveEntry(indexBuffer, entry, leafID); |
| | | |
| | | // Remove the id2c and id2s records for this entry. |
| | | final ByteString leafIDKeyBytes = ByteString.valueOf(leafID.longValue()); |
| | | final ByteString leafIDKeyBytes = leafID.toByteString(); |
| | | id2children.delete(indexBuffer, leafIDKeyBytes); |
| | | id2subtree.delete(indexBuffer, leafIDKeyBytes); |
| | | |
| | |
| | | throw new JebException(ERR_JEB_MISSING_DN2ID_RECORD.get(parentDN)); |
| | | } |
| | | |
| | | ByteString parentIDBytes = ByteString.valueOf(parentID.longValue()); |
| | | ByteString parentIDBytes = parentID.toByteString(); |
| | | // Remove from id2children. |
| | | if (isParent) |
| | | { |
| | |
| | | { |
| | | logger.trace("Move of target entry requires renumbering" + "all entries in the subtree. " |
| | | + "Old DN: %s " + "New DN: %s " + "Old entry ID: %d " + "New entry ID: %d " |
| | | + "New Superior ID: %d" + oldApexEntry.getName(), entry.getName(), oldApexID.longValue(), |
| | | newApexID.longValue(), newSuperiorID.longValue()); |
| | | + "New Superior ID: %d" + oldApexEntry.getName(), entry.getName(), oldApexID, |
| | | newApexID, newSuperiorID); |
| | | } |
| | | } |
| | | } |
| | |
| | | |
| | | if (logger.isTraceEnabled()) |
| | | { |
| | | logger.trace("Move of subordinate entry requires " + "renumbering. " + "Old DN: %s " |
| | | + "New DN: %s " + "Old entry ID: %d " + "New entry ID: %d", oldEntry.getName(), newDN, oldID |
| | | .longValue(), newID.longValue()); |
| | | logger.trace("Move of subordinate entry requires renumbering. " |
| | | + "Old DN: %s New DN: %s Old entry ID: %d New entry ID: %d", |
| | | oldEntry.getName(), newDN, oldID, newID); |
| | | } |
| | | } |
| | | |
| | |
| | | dn = getParentWithinBase(dn)) |
| | | { |
| | | EntryID parentID = dn2id.get(txn, dn, false); |
| | | ByteString parentIDKeyBytes = ByteString.valueOf(parentID.longValue()); |
| | | ByteString parentIDKeyBytes = parentID.toByteString(); |
| | | if(isParent) |
| | | { |
| | | id2children.insertID(buffer, parentIDKeyBytes, newID); |
| | |
| | | for (DN dn = oldSuperiorDN; dn != null; dn = getParentWithinBase(dn)) |
| | | { |
| | | EntryID parentID = dn2id.get(txn, dn, false); |
| | | ByteString parentIDKeyBytes = ByteString.valueOf(parentID.longValue()); |
| | | ByteString parentIDKeyBytes = parentID.toByteString(); |
| | | if(isParent) |
| | | { |
| | | id2children.removeID(buffer, parentIDKeyBytes, oldID); |
| | |
| | | { |
| | | // All the subordinates will be renumbered so we have to rebuild |
| | | // id2c and id2s with the new ID. |
| | | ByteString oldIDKeyBytes = ByteString.valueOf(oldID.longValue()); |
| | | ByteString oldIDKeyBytes = oldID.toByteString(); |
| | | id2children.delete(buffer, oldIDKeyBytes); |
| | | id2subtree.delete(buffer, oldIDKeyBytes); |
| | | |
| | |
| | | for (DN dn = oldSuperiorDN; dn != null; dn = getParentWithinBase(dn)) |
| | | { |
| | | EntryID parentID = dn2id.get(txn, dn, false); |
| | | ByteString parentIDKeyBytes = ByteString.valueOf(parentID.longValue()); |
| | | ByteString parentIDKeyBytes = parentID.toByteString(); |
| | | id2subtree.removeID(buffer, parentIDKeyBytes, oldID); |
| | | } |
| | | } |
| | |
| | | { |
| | | // All the subordinates will be renumbered so we have to rebuild |
| | | // id2c and id2s with the new ID. |
| | | ByteString oldIDKeyBytes = ByteString.valueOf(oldID.longValue()); |
| | | ByteString oldIDKeyBytes = oldID.toByteString(); |
| | | id2children.delete(buffer, oldIDKeyBytes); |
| | | id2subtree.delete(buffer, oldIDKeyBytes); |
| | | |
| | |
| | | EntryID entryID = dn2id.get(null, baseDN, false); |
| | | if (entryID != null) |
| | | { |
| | | ByteString key = entryIDToDatabase(entryID.longValue()); |
| | | EntryIDSet entryIDSet = id2subtree.readKey(key, null); |
| | | EntryIDSet entryIDSet = id2subtree.readKey(entryID.toByteString(), null); |
| | | |
| | | long count = entryIDSet.size(); |
| | | if(count != Long.MAX_VALUE) |
| | |
| | | } |
| | | |
| | | /** |
| | | * Encode an entry ID value to its database representation. |
| | | * |
| | | * @param id The entry ID value to be encoded. |
| | | * @return The encoded database value of the entry ID. |
| | | * @see #entryIDFromDatabase(byte[]) |
| | | */ |
| | | public static ByteString entryIDToDatabase(long id) |
| | | { |
| | | return ByteString.valueOf(id); |
| | | } |
| | | |
| | | /** |
| | | * Encode an entry ID set count to its database representation. |
| | | * |
| | | * @param count The entry ID set count to be encoded. |
| | |
| | | * |
| | | * @param entryIDArray An array of entry ID values. |
| | | * @return The encoded database value. |
| | | * @see #entryIDListFromDatabase(byte[]) |
| | | */ |
| | | public static byte[] entryIDListToDatabase(long[] entryIDArray) |
| | | { |
| | |
| | | * @param prefixRDNs The number of prefix RDNs to remove from the encoded |
| | | * representation. |
| | | * @return A ByteString containing the key. |
| | | * @see #dnFromDNKey(byte[], int, int, DN) |
| | | */ |
| | | public static ByteString dnToDNKey(DN dn, int prefixRDNs) |
| | | { |
| | |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.SortKey; |
| | | |
| | | import static org.opends.server.backends.pluggable.JebFormat.*; |
| | | |
| | | |
| | | |
| | | /** |
| | | * This class represents a partial sorted set of sorted entries in a VLV |
| | | * index. |
| | | * This class represents a partial sorted set of sorted entries in a VLV index. |
| | | */ |
| | | public class SortValuesSet |
| | | { |
| | |
| | | {} |
| | | |
| | | /** |
| | | * Add the given entryID and values from these sort values. |
| | | * |
| | | * @param sv The sort values to add. |
| | | * @param types The types of the values to add. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws DatabaseException If an error occurs in the JE database. |
| | | */ |
| | | void add(SortValues sv) throws DirectoryException |
| | | { |
| | | add(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | | } |
| | | |
| | | /** |
| | | * Add the given entryID and values from this VLV index. |
| | | * |
| | | * @param entryID The entry ID to add. |
| | |
| | | } |
| | | |
| | | /** |
| | | * Remove the given entryID and values from this VLV index. |
| | | * Remove the given entryID and values from these sort values. |
| | | * |
| | | * @param entryID The entry ID to remove. |
| | | * @param values The values to remove. |
| | | * @return True if the information was successfully removed or False |
| | | * otherwise. |
| | | * @param sv The sort values to remove. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | * @throws StorageRuntimeException If an error occurs in the JE database. |
| | | */ |
| | | public boolean remove(long entryID, ByteString[] values) |
| | | throws StorageRuntimeException, DirectoryException |
| | | void remove(SortValues sv) throws DirectoryException |
| | | { |
| | | if(entryIDs == null || entryIDs.length == 0) |
| | | { |
| | | return false; |
| | | return; |
| | | } |
| | | |
| | | if(valuesBytesOffsets == null) |
| | |
| | | updateValuesBytesOffsets(); |
| | | } |
| | | |
| | | int pos = binarySearch(entryID, values); |
| | | int pos = binarySearch(sv.getEntryID(), sv.getValues()); |
| | | if(pos < 0) |
| | | { |
| | | // Not found. |
| | | return false; |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | |
| | | // Found it. |
| | | long[] updatedEntryIDs = new long[entryIDs.length - 1]; |
| | | System.arraycopy(entryIDs, 0, updatedEntryIDs, 0, pos); |
| | |
| | | valuesBytes.length - valuesPos - valuesLength); |
| | | |
| | | int[] updatedValuesBytesOffsets = new int[valuesBytesOffsets.length - 1]; |
| | | System.arraycopy(valuesBytesOffsets, 0, updatedValuesBytesOffsets, |
| | | 0, pos); |
| | | System.arraycopy(valuesBytesOffsets, 0, updatedValuesBytesOffsets, 0, pos); |
| | | // Update the rest of the offsets one by one - Expensive! |
| | | for(int i = pos + 1; i < valuesBytesOffsets.length; i++) |
| | | { |
| | | updatedValuesBytesOffsets[i-1] = |
| | | valuesBytesOffsets[i] - valuesLength; |
| | | updatedValuesBytesOffsets[i - 1] = valuesBytesOffsets[i] - valuesLength; |
| | | } |
| | | |
| | | entryIDs = updatedEntryIDs; |
| | | valuesBytes = updatedValuesBytes; |
| | | valuesBytesOffsets = updatedValuesBytesOffsets; |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | int vBytesPos = valuesBytesOffsets[valuesBytesOffsets.length - 1]; |
| | | int vBytesLength = valuesBytes.length - vBytesPos; |
| | | |
| | | ByteString idBytes = entryIDToDatabase(entryIDs[entryIDs.length - 1]); |
| | | ByteString idBytes = ByteString.valueOf(entryIDs[entryIDs.length - 1]); |
| | | ByteStringBuilder keyBytes = new ByteStringBuilder(vBytesLength + idBytes.length()); |
| | | keyBytes.append(valuesBytes, vBytesPos, vBytesLength); |
| | | keyBytes.append(idBytes); |
| | |
| | | import java.io.Closeable; |
| | | |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | | |
| | | /** |
| | | * Container for a whole suffix environment which stores all entries from the |
| | |
| | | // This is the last unbounded set. |
| | | while(av != null) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | sortValuesSet.add(av); |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | |
| | | |
| | | while(av != null && av.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.add(av.getEntryID(), av.getValues(), av.getTypes()); |
| | | sortValuesSet.add(av); |
| | | av = moveToNextSortValues(aValues); |
| | | } |
| | | |
| | | while(dv != null && dv.compareTo(maxValues) <= 0) |
| | | { |
| | | sortValuesSet.remove(dv.getEntryID(), dv.getValues()); |
| | | sortValuesSet.remove(dv); |
| | | dv = moveToNextSortValues(dValues); |
| | | } |
| | | } |
| | |
| | | return null; |
| | | } |
| | | |
| | | private ByteString encodeKey(SortValues sv) throws DirectoryException |
| | | { |
| | | return encodeKey(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | | } |
| | | |
| | | /** |
| | | * Evaluate a search with sort control using this VLV index. |
| | | * |
| | |
| | | } |
| | | |
| | | /** |
| | | * Encode a VLV database key with the provided sort values. |
| | | * |
| | | * @param sv the sort values to encode |
| | | * @return The encoded bytes. |
| | | * @throws DirectoryException If a Directory Server error occurs. |
| | | */ |
| | | ByteString encodeKey(SortValues sv) throws DirectoryException |
| | | { |
| | | return encodeKey(sv.getEntryID(), sv.getValues(), sv.getTypes()); |
| | | } |
| | | |
| | | /** |
| | | * Encode a VLV database key with the given information. |
| | | * |
| | | * @param entryID The entry ID to encode. |
| | |
| | | logger.traceException(e); |
| | | |
| | | logger.trace("File id2subtree has malformed ID list " + |
| | | "for ID %s:%n%s%n", entryID, |
| | | StaticUtils |
| | | .bytesToHex(value)); |
| | | "for ID %s:%n%s%n", entryID, StaticUtils.bytesToHex(value)); |
| | | } |
| | | continue; |
| | | } |
| | |
| | | { |
| | | logger.trace("File id2subtree has ID %d with DN <%s> " + |
| | | "referencing ID %d with non-subordinate DN <%s>%n", |
| | | entryID, entry.getName(), id, subordEntry |
| | | .getName()); |
| | | entryID, entry.getName(), id, subordEntry.getName()); |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | // If this is the last one in a bounded set, make sure it is the |
| | | // same as the database key. |
| | | ByteString encodedKey = vlvIndex.encodeKey( |
| | | values.getEntryID(), values.getValues(), values.getTypes()); |
| | | ByteString encodedKey = vlvIndex.encodeKey(values); |
| | | if (!key.equals(encodedKey)) |
| | | { |
| | | if(logger.isTraceEnabled()) |
| | |
| | | ByteString[] badValues = new ByteString[values.length]; |
| | | System.arraycopy(values, 1, badValues, 0, values.length - 1); |
| | | badValues[badValues.length-1] = values[0]; |
| | | svs.remove(id, values); |
| | | remove(svs, id, values); |
| | | svs.add(id, badValues, types); |
| | | |
| | | putSortValuesSet(vlvIndex, svs); |
| | |
| | | DatabaseEntry data= new DatabaseEntry(entryBytes.toByteArray()); |
| | | assertEquals(id2entry.put(txn, key, data), OperationStatus.SUCCESS); |
| | | |
| | | //add entry with ramdom bytes |
| | | // add entry with random bytes |
| | | DatabaseEntry key1= new EntryID(4).getDatabaseEntry(); |
| | | byte []eBytes = new byte[459]; |
| | | for(int i=0;i<459;i++) { |
| | |
| | | SortValuesSet svs = vlvIndex.getSortValuesSet(null, 0, new ByteString[3], types); |
| | | long id = svs.getEntryIDs()[0]; |
| | | Entry entry = eContainer.getID2Entry().get(null, new EntryID(id), LockMode.DEFAULT); |
| | | svs.remove(id, vlvIndex.getSortValues(entry)); |
| | | remove(svs, id, vlvIndex.getSortValues(entry)); |
| | | |
| | | // Add an incorrectly ordered values. |
| | | SortValuesSet svs2 = svs.split(2); |
| | |
| | | ByteString[] badValues = new ByteString[values.length]; |
| | | System.arraycopy(values, 1, badValues, 0, values.length - 1); |
| | | badValues[badValues.length-1] = values[0]; |
| | | svs.remove(id, values); |
| | | remove(svs, id, values); |
| | | svs.add(id, badValues, types); |
| | | |
| | | putSortValuesSet(vlvIndex, svs); |
| | |
| | | } |
| | | } |
| | | |
| | | private void remove(SortValuesSet svs, long id, ByteString[] values) throws DirectoryException |
| | | { |
| | | svs.remove(new SortValues(new EntryID(id), values, new SortOrder())); |
| | | } |
| | | |
| | | /** |
| | | * Put a sort values set in this VLV index. |
| | | * |