mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

dugan
07.51.2008 50b5f3c4c4d80598ea5761b987b183e3202cc47f
Import performance commits:

- improve hash calculation of buffer elements
- run id2children/id2subtree changes through buffer manager
- detect index undefined change and add change to buffer cache

No issue.
6 files modified
281 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/Index.java 4 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/BufferManager.java 106 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/ImportIDSet.java 15 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/IntegerImportIDSet.java 120 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/LongImportIDSet.java 33 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/backends/jeb/importLDIF/WorkThread.java 3 ●●●● patch | view | raw | blame | history
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);
  }
  /**