opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Index.java
@@ -280,8 +280,8 @@ status = read(txn, key, data, LockMode.RMW); if(status == OperationStatus.SUCCESS) { ImportIDSet newImportIDSet = new IntegerImportIDSet(); if (newImportIDSet.merge(data.getData(), importIdSet, indexEntryLimit)) { if (newImportIDSet.merge(data.getData(), importIdSet, indexEntryLimit, maintainCount)) { entryLimitExceededCount++; } data.setData(newImportIDSet.toDatabase()); opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/BufferManager.java
@@ -73,7 +73,7 @@ //Overhead values determined from using JHAT. They appear to be the same //for both 32 and 64 bit machines. Close enough. private final static int TREEMAP_ENTRY_OVERHEAD = 29; private final static int KEY_ELEMENT_OVERHEAD = 28; private final static int KEY_ELEMENT_OVERHEAD = 32; /** @@ -98,13 +98,53 @@ * @throws DatabaseException If a problem happened during a flushAll cycle. */ void insert(Index index, Entry entry, EntryID entryID, Transaction txn) throws DatabaseException { int entryLimit = index.getIndexEntryLimit(); Set<byte[]> keySet = new HashSet<byte[]>(); index.indexer.indexEntry(txn, entry, keySet); EntryID entryID, Transaction txn) throws DatabaseException { Set<byte[]> keySet = new HashSet<byte[]>(); index.indexer.indexEntry(txn, entry, keySet); synchronized(elementMap) { for(byte[] key : keySet) { insertKeySet(keySet, index, entryID); //If over the memory limit and import hasn't completed //flush some keys from the cache to make room. if(memoryUsage > memoryLimit) { flushUntilUnderLimit(); } } } /** * Special case for id2children and id2subtree. * Insert an entry ID into the buffer using the both the specified index and * entry to build a key set. * @param id2children The id2children index. * @param id2subtree The id2subtree index. * @param entry The entry to used to build the keyset. * @param entryID The entry ID to insert into the key set. * @param txn A transaction. * @throws DatabaseException If a problem happens formating the keyset. */ void insert(Index id2children, Index id2subtree, Entry entry, EntryID entryID, Transaction txn) throws DatabaseException { Set<byte[]> childKeySet = new HashSet<byte[]>(); id2children.indexer.indexEntry(txn, entry, childKeySet); Set<byte[]> subKeySet = new HashSet<byte[]>(); id2subtree.indexer.indexEntry(txn, entry, subKeySet); synchronized(elementMap) { insertKeySet(childKeySet, id2children, entryID); insertKeySet(subKeySet, id2subtree, entryID); } } /** * Insert a keySet into the element map using the provided index and entry ID. * @param keySet The key set to add to the map. * @param index The index that eventually will contain the entry IDs. * @param entryID The entry ID to add to the entry ID set. */ private void insertKeySet(Set<byte[]> keySet, Index index, EntryID entryID) { int entryLimit = index.getIndexEntryLimit(); for(byte[] key : keySet) { KeyHashElement elem = new KeyHashElement(key, index, entryID); total++; if(!elementMap.containsKey(elem)) { @@ -112,7 +152,7 @@ memoryUsage += TREEMAP_ENTRY_OVERHEAD + elem.getMemorySize(); } else { KeyHashElement curElem = elementMap.get(elem); if(curElem.isDefined()) { if(curElem.isDefined() || index.getMaintainCount()) { int oldSize = curElem.getMemorySize(); curElem.addEntryID(entryID, entryLimit); int newSize = curElem.getMemorySize(); @@ -121,13 +161,7 @@ hit++; } } } //If over the memory limit and import hasn't completed //flush some keys from the cache to make room. if(memoryUsage > memoryLimit) { flushUntilUnderLimit(); } } } } /** @@ -215,6 +249,9 @@ //The set of IDs related to the key. private ImportIDSet importIDSet; //Used to speed up lookup. private int keyHashCode; /** * Create instance of an element for the specified key and index, the add * the specified entry ID to the ID set. @@ -232,6 +269,7 @@ //Used if there when there are conflicts if two or more indexes have //the same key. this.indexHashCode = System.identityHashCode(index); this.keyHashCode = Arrays.hashCode(key); } /** @@ -241,7 +279,7 @@ * @param entryLimit The entry limit */ void addEntryID(EntryID entryID, int entryLimit) { importIDSet.addEntryID(entryID, entryLimit); importIDSet.addEntryID(entryID, entryLimit, index.getMaintainCount()); } /** @@ -263,6 +301,15 @@ } /** * Return value of the key hash code. * * @return The key hash code value. */ int getKeyHashCode() { return keyHashCode; } /** * Return the ID set. * @return The import ID set. */ @@ -280,7 +327,8 @@ } /** * Compare the bytes of two keys. * Compare the bytes of two keys. The is slow, only use if the hashcode * had a collision. * * @param a Key a. * @param b Key b. @@ -309,6 +357,27 @@ } /** * Compare two element keys. First check the precomputed hashCode. If * the hashCodes are equal, do a second byte per byte comparision in case * there was a collision. * * @param elem The element to compare. * @return 0 if the keys are equal, -1 if key a is less than key b, 1 if * key a is greater than key b. */ private int compare(KeyHashElement elem) { if(keyHashCode == elem.getKeyHashCode()) { return compare(key, elem.key); } else { if(keyHashCode < elem.getKeyHashCode()) { return -1; } else { return 1; } } } /** * Compare the specified object to the current object. If the keys are * equal, then the indexHashCode value is used as a tie-breaker. * @@ -321,7 +390,8 @@ throw new NullPointerException(); } KeyHashElement inElem = (KeyHashElement) o; int keyCompare = compare(key, inElem.key); // int keyCompare = compare(key, inElem.key); int keyCompare = compare(inElem); if(keyCompare == 0) { if(indexHashCode == inElem.indexHashCode) { return 0; opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/ImportIDSet.java
@@ -39,8 +39,10 @@ * * @param entryID The entry ID to add. * @param entryLimit The entry limit. * @param maintainCount Maintain count of IDs if in undefined mode. */ public void addEntryID(EntryID entryID, int entryLimit); public void addEntryID(EntryID entryID, int entryLimit, boolean maintainCount); /** * Return if a set is defined or not. @@ -76,13 +78,22 @@ * @param dbBytes The byte array read from DB. * @param bufImportIDSet The import ID set to merge. * @param entryLimit The entry limit. * @param maintainCount Maintain count of iDs if in undefined mode. * @return <CODE>True</CODE> if the merged set is undefined. */ public boolean merge(byte[] dbBytes, ImportIDSet bufImportIDSet, int entryLimit); int entryLimit, boolean maintainCount); /** * Set the import ID set to the undefined state. */ public void setUndefined(); /** * Return the undefined size. * * @return The undefined count. */ public long getUndefinedSize(); } opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/IntegerImportIDSet.java
@@ -36,7 +36,7 @@ public class IntegerImportIDSet implements ImportIDSet { //Gleamed from JHAT. The same for 32/64 bit. private final static int THIS_OVERHEAD = 17; private final static int THIS_OVERHEAD = 25; /** * The internal array where elements are stored. @@ -53,6 +53,10 @@ //Boolean to keep track if the instance is defined or not. private boolean isDefined=true; //Size of the undefines. private long undefinedSize = 0; /** * Create an empty import set. */ @@ -78,6 +82,12 @@ return isDefined; } /** * {@inheritDoc} */ public long getUndefinedSize() { return undefinedSize; } /** * {@inheritDoc} @@ -103,22 +113,62 @@ /** * {@inheritDoc} */ public boolean merge(byte[] dBbytes, ImportIDSet importIdSet, int limit) { public void addEntryID(EntryID entryID, int limit, boolean maintainCount) { if(!isDefined()) { if(maintainCount) { undefinedSize++; } return; } if(isDefined() && ((count + 1) > limit)) { isDefined = false; array = null; if(maintainCount) { undefinedSize = count + 1; } else { undefinedSize = Long.MAX_VALUE; } count = 0; } else { add((int)entryID.longValue()); } } /** * More complicated version of merge below that keeps track of the undefined * sizes when in undefined mode or moving to undefined mode. * * @param dBbytes The bytes read from jeb. * @param importIdSet * @param limit * @return */ private boolean mergeCount(byte[] dBbytes, ImportIDSet importIdSet, int limit) { boolean incrLimitCount=false; boolean dbUndefined = ((dBbytes[0] & 0x80) == 0x80); if(dbUndefined) { isDefined=false; if(dbUndefined && (!importIdSet.isDefined())) { undefinedSize = JebFormat.entryIDUndefinedSizeFromDatabase(dBbytes) + importIdSet.getUndefinedSize(); isDefined=false; } else if(dbUndefined && (importIdSet.isDefined())) { undefinedSize = JebFormat.entryIDUndefinedSizeFromDatabase(dBbytes) + importIdSet.size(); importIdSet.setUndefined(); isDefined=false; } else if(!importIdSet.isDefined()) { isDefined=false; incrLimitCount=true; int dbSize = JebFormat.entryIDListFromDatabase(dBbytes).length; undefinedSize= dbSize + importIdSet.getUndefinedSize(); isDefined=false; incrLimitCount = true; } else { array = JebFormat.intArrayFromDatabaseBytes(dBbytes); if(array.length + importIdSet.size() > limit) { isDefined=false; incrLimitCount=true; count = 0; importIdSet.setUndefined(); undefinedSize = array.length + importIdSet.size(); importIdSet.setUndefined(); isDefined=false; incrLimitCount=true; } else { count = array.length; addAll((IntegerImportIDSet) importIdSet); @@ -128,6 +178,38 @@ } /** * {@inheritDoc} */ public boolean merge(byte[] dBbytes, ImportIDSet importIdSet, int limit, boolean maintainCount) { boolean incrLimitCount=false; if(maintainCount) { incrLimitCount = mergeCount(dBbytes, importIdSet, limit); } else { boolean dbUndefined = ((dBbytes[0] & 0x80) == 0x80); if(dbUndefined) { isDefined=false; importIdSet.setUndefined(); } else if(!importIdSet.isDefined()) { isDefined=false; incrLimitCount=true; } else { array = JebFormat.intArrayFromDatabaseBytes(dBbytes); if(array.length + importIdSet.size() > limit) { isDefined=false; incrLimitCount=true; count = 0; importIdSet.setUndefined(); } else { count = array.length; addAll((IntegerImportIDSet) importIdSet); } } } return incrLimitCount; } /** * Add all of the specified import ID set to the import set. * * @param that The import ID set to add. @@ -222,22 +304,6 @@ /** * {@inheritDoc} */ public void addEntryID(EntryID entryID, int limit) { if(!isDefined()) { return; } if(isDefined() && ((count + 1) > limit)) { isDefined = false; array = null; count = 0; } else { add((int)entryID.longValue()); } } /** * Add the specified integer to the import set. * * @param v The integer value to add. @@ -330,7 +396,7 @@ if(isDefined) { return encode(null); } else { return JebFormat.entryIDUndefinedSizeToDatabase(Long.MAX_VALUE); return JebFormat.entryIDUndefinedSizeToDatabase(undefinedSize); } } opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/LongImportIDSet.java
@@ -58,6 +58,11 @@ //Boolean to keep track if the instance is defined or not. boolean isDefined=true; //Size of the undefines. private long undefinedSize = 0; static { if(RuntimeInformation.is64Bit()) { LONGS_OVERHEAD = LONGS_OVERHEAD_64; @@ -99,6 +104,12 @@ isDefined = false; } /** * {@inheritDoc} */ public long getUndefinedSize() { return undefinedSize; } /** * {@inheritDoc} @@ -115,7 +126,8 @@ /** * {@inheritDoc} */ public boolean merge(byte[] DBbytes, ImportIDSet importIdSet, int limit) { public boolean merge(byte[] DBbytes, ImportIDSet importIdSet, int limit, boolean maintainCount) { boolean incrLimitCount=false; boolean dbUndefined = ((DBbytes[0] & 0x80) == 0x80); @@ -142,13 +154,21 @@ /** * {@inheritDoc} */ public void addEntryID(EntryID entryID, int limit) { public void addEntryID(EntryID entryID, int limit, boolean maintainCount) { if(!isDefined()) { return; if(maintainCount) { undefinedSize++; } return; } if(isDefined() && ((count + 1) > limit)) { isDefined = false; array = null; if(maintainCount) { undefinedSize = count + 1; } else { undefinedSize = Long.MAX_VALUE; } count = 0; } else { add(entryID.longValue()); @@ -160,8 +180,11 @@ * {@inheritDoc} */ public byte[] toDatabase() { if (isDefined()) return encode(null); else return JebFormat.entryIDUndefinedSizeToDatabase(Long.MAX_VALUE); if (isDefined()) { return encode(null); } else { return JebFormat.entryIDUndefinedSizeToDatabase(undefinedSize); } } /** opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java
@@ -272,8 +272,7 @@ } Index id2children = context.getEntryContainer().getID2Children(); Index id2subtree = context.getEntryContainer().getID2Subtree(); insert(id2children, entry, entryID, txn); insert(id2subtree, entry, entryID, txn); bufferMgr.insert(id2children, id2subtree, entry, entryID, txn); } /**