From 7c6b1f8176561447f0cdb0de118f1bd27a767b09 Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Fri, 20 Mar 2015 14:27:32 +0000
Subject: [PATCH] OPENDJ-1867: Consider removing ImportIDSet and using EntryIDSet instead
---
opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ImportIDSet.java | 444 ++++++++-----------------------------------------------
1 files changed, 68 insertions(+), 376 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ImportIDSet.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ImportIDSet.java
index 658cd9c..7db706d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ImportIDSet.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/pluggable/ImportIDSet.java
@@ -26,11 +26,11 @@
*/
package org.opends.server.backends.pluggable;
+import static org.forgerock.util.Reject.*;
import static org.opends.server.backends.pluggable.EntryIDSet.*;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteStringBuilder;
/**
* This class manages the set of ID that are to be eventually added to an index
@@ -38,446 +38,138 @@
* the configured ID limit. If the limit it reached, the class stops tracking
* individual IDs and marks the set as undefined. This class is not thread safe.
*/
-class ImportIDSet {
+final class ImportIDSet {
- /** The internal array where elements are stored. */
- private long[] array;
- /** The number of valid elements in the array. */
- private int count;
- /** Boolean to keep track if the instance is defined or not. */
- private boolean isDefined = true;
+ /** The encapsulated entryIDSet where elements are stored until reaching the limit. */
+ private EntryIDSet entryIDSet;
/** Key related to an ID set. */
- private ByteSequence key;
+ private final ByteSequence key;
/** The index entry limit size. */
- private final int indexEntryLimit;
- /**
- * Set to true if a count of ids above the index entry limit should be kept, a.k.a
- * {@link #undefinedSize}.
- *
- * @see #undefinedSize
- */
+ private final int indexEntryLimitSize;
+ /** Set to true if a count of ids above the index entry limit should be kept. */
private final boolean maintainCount;
- /**
- * Size of the undefined id set, if count is maintained.
- *
- * @see #maintainCount
- */
- private long undefinedSize;
/**
- * Create an import ID set of the specified size, index limit and index
- * maintain count, plus an extra 128 slots.
+ * Create an import ID set managing the entry limit of the provided EntryIDSet.
*
* @param key The key associated to this ID set
- * @param size The size of the the underlying array, plus some extra space.
- * @param limit The index entry limit.
+ * @param entryIDSet The entryIDSet that will be managed by this object
+ * @param limit The index entry limit or 0 if unlimited.
* @param maintainCount whether to maintain the count when size is undefined.
+ * @throws NullPointerException if key or entryIDSet is null
+ * @throws IllegalArgumentException if limit is < 0
*/
- public ImportIDSet(ByteSequence key, int size, int limit, boolean maintainCount)
+ public ImportIDSet(ByteSequence key, EntryIDSet entryIDSet, int limit, boolean maintainCount)
{
+ checkNotNull(key, "key must not be null");
+ checkNotNull(entryIDSet, "entryIDSet must not be null");
+ ifFalse(limit >= 0, "limit must be >= 0");
+
this.key = key;
- this.array = new long[size + 128];
- // A limit of 0 means unlimited.
- this.indexEntryLimit = limit == 0 ? Integer.MAX_VALUE : limit;
+ this.entryIDSet = entryIDSet;
+ // FIXME: What to do if entryIDSet.size()> limit yet ?
+ this.indexEntryLimitSize = limit == 0 ? Integer.MAX_VALUE : limit;
this.maintainCount = maintainCount;
}
/**
- * Clear the set so it can be reused again. The boolean indexParam specifies
- * if the index parameters should be cleared also.
- */
- public void clear()
- {
- undefinedSize = 0;
- isDefined = true;
- count = 0;
- }
-
- /**
- * Return if an import ID set is defined or not.
- *
* @return <CODE>True</CODE> if an import ID set is defined.
*/
- public boolean isDefined()
+ boolean isDefined()
{
- return isDefined;
+ return entryIDSet.isDefined();
}
- /** Set an import ID set to undefined. */
private void setUndefined() {
- array = null;
- isDefined = false;
+ entryIDSet = newUndefinedSetWithKey(key);
}
/**
- * Add the specified entry id to an import ID set.
- *
- * @param entryID The entry ID to add to an import ID set.
+ * @param entryID The entry ID to add to an import ID set.
+ * @throws NullPointerException if entryID is null
*/
void addEntryID(EntryID entryID) {
addEntryID(entryID.longValue());
}
/**
- * Add the specified long value to an import ID set.
- *
* @param entryID The {@link EntryID} to add to an import ID set.
*/
- void addEntryID(long entryID) {
- if(!isDefined()) {
- if (maintainCount) {
- undefinedSize++;
- }
- return;
+ void addEntryID(long entryID)
+ {
+ if ((entryID < 0)|| (isDefined() && size() + 1 > indexEntryLimitSize)) {
+ entryIDSet = maintainCount ? newUndefinedSetWithSize(key, size() + 1) : newUndefinedSetWithKey(key);
+ } else if (isDefined() || maintainCount) {
+ entryIDSet.add(new EntryID(entryID));
}
- if (entryID < 0 || (isDefined() && count + 1 > indexEntryLimit))
- {
- setUndefined();
- if (maintainCount) {
- undefinedSize = count + 1;
- } else {
- undefinedSize = Long.MAX_VALUE;
- }
- count = 0;
- } else {
- add(entryID);
- }
- }
-
- private boolean mergeCount(ByteString dBbytes, ImportIDSet importIdSet) {
- boolean incrementLimitCount=false;
- boolean dbUndefined = isDBUndefined(dBbytes);
-
- if (dbUndefined && !importIdSet.isDefined()) {
- undefinedSize = decodeUndefinedSize(dBbytes) + importIdSet.undefinedSize;
- isDefined=false;
- } else if (dbUndefined && importIdSet.isDefined()) {
- undefinedSize = decodeUndefinedSize(dBbytes) + importIdSet.size();
- isDefined=false;
- } else if(!importIdSet.isDefined()) {
- int dbSize = decodeEntryIDSet(dBbytes).length;
- undefinedSize = dbSize + importIdSet.undefinedSize;
- isDefined = false;
- incrementLimitCount = true;
- } else {
- array = decodeEntryIDSet(dBbytes);
- if (array.length + importIdSet.size() > indexEntryLimit) {
- undefinedSize = array.length + importIdSet.size();
- isDefined=false;
- incrementLimitCount=true;
- } else {
- count = array.length;
- addAll(importIdSet);
- }
- }
- return incrementLimitCount;
}
/**
- * Remove the specified import ID set from the byte array read from the DB.
- *
- * @param bytes The byte array read from JEB.
* @param importIdSet The import ID set to delete.
+ * @throws NullPointerException if importIdSet is null
*/
- public void remove(ByteSequence bytes, ImportIDSet importIdSet)
+ void remove(ImportIDSet importIdSet)
{
- if (isDBUndefined(bytes)) {
- isDefined=false;
- importIdSet.setUndefined();
- undefinedSize = Long.MAX_VALUE;
- } else if(!importIdSet.isDefined()) {
- isDefined=false;
- undefinedSize = Long.MAX_VALUE;
- } else {
- array = decodeEntryIDSet(bytes);
- if (array.length - importIdSet.size() > indexEntryLimit) {
- isDefined=false;
- count = 0;
- importIdSet.setUndefined();
- undefinedSize = Long.MAX_VALUE;
- } else {
- count = array.length;
- removeAll(importIdSet);
- }
+ checkNotNull(importIdSet, "importIdSet must not be null");
+
+ if (!importIdSet.isDefined()) {
+ setUndefined();
+ } else if (isDefined() || maintainCount) {
+ entryIDSet.removeAll(importIdSet.entryIDSet);
}
}
/**
- * Merge the specified byte array read from a DB, with the specified import
- * ID set. The specified limit and maintain count parameters define
- * if the newly merged set is defined or not.
- *
- * @param bytes The byte array of IDs read from a DB.
* @param importIdSet The import ID set to merge the byte array with.
- * @return <CODE>True</CODE> if the import ID set started keeping a count as
- * a result of the merge.
+ * @return <CODE>true</CODE> if the import ID set reached the limit as a result of the merge.
+ * @throws NullPointerException if importIdSet is null
*/
- public boolean merge(ByteString bytes, ImportIDSet importIdSet)
+ boolean merge(ImportIDSet importIdSet)
{
- boolean incrementLimitCount=false;
- if (maintainCount) {
- incrementLimitCount = mergeCount(bytes, importIdSet);
- } else if (isDBUndefined(bytes)) {
- isDefined = false;
- importIdSet.setUndefined();
- undefinedSize = Long.MAX_VALUE;
- count = 0;
- } else if(!importIdSet.isDefined()) {
- isDefined = false;
- incrementLimitCount = true;
- undefinedSize = Long.MAX_VALUE;
- count = 0;
- } else {
- array = decodeEntryIDSet(bytes);
- if (array.length + importIdSet.size() > indexEntryLimit) {
- isDefined = false;
- incrementLimitCount = true;
- count = 0;
- importIdSet.setUndefined();
- undefinedSize = Long.MAX_VALUE;
- } else {
- count = array.length;
- addAll(importIdSet);
- }
+ checkNotNull(importIdSet, "importIdSet must not be null");
+
+ boolean definedBeforeMerge = isDefined();
+ final long mergedSize = size() + importIdSet.size();
+
+ if (!importIdSet.isDefined() || mergedSize > indexEntryLimitSize) {
+ entryIDSet = maintainCount ? newUndefinedSetWithSize(key, mergedSize) : newUndefinedSetWithKey(key);
+ return definedBeforeMerge;
+ } else if (isDefined() || maintainCount){
+ entryIDSet.addAll(importIdSet.entryIDSet);
}
- return incrementLimitCount;
- }
-
- private boolean isDBUndefined(ByteSequence bytes)
- {
- return (bytes.byteAt(0) & 0x80) == 0x80;
- }
-
- private void removeAll(ImportIDSet that) {
- long[] newArray = new long[array.length];
- int c = 0;
- for(int i=0; i < count; i++)
- {
- if(binarySearch(that.array, that.count, array[i]) < 0)
- {
- newArray[c++] = array[i];
- }
- }
- array = newArray;
- count = c;
- }
-
- private void addAll(ImportIDSet that) {
- resize(this.count+that.count);
-
- if (that.count == 0)
- {
- return;
- }
-
- // Optimize for the case where the two sets are sure to have no overlap.
- if (this.count == 0 || that.array[0] > this.array[this.count-1])
- {
- System.arraycopy(that.array, 0, this.array, this.count, that.count);
- count += that.count;
- return;
- }
-
- if (this.array[0] > that.array[that.count-1])
- {
- System.arraycopy(this.array, 0, this.array, that.count, this.count);
- System.arraycopy(that.array, 0, this.array, 0, that.count);
- count += that.count;
- return;
- }
-
- int destPos = binarySearch(this.array, this.count, that.array[0]);
- if (destPos < 0)
- {
- destPos = -(destPos+1);
- }
-
- // Make space for the copy.
- int aCount = this.count - destPos;
- int aPos = destPos + that.count;
- int aEnd = aPos + aCount;
- System.arraycopy(this.array, destPos, this.array, aPos, aCount);
-
- // Optimize for the case where there is no overlap.
- if (this.array[aPos] > that.array[that.count-1])
- {
- System.arraycopy(that.array, 0, this.array, destPos, that.count);
- count += that.count;
- return;
- }
-
- int bPos;
- for ( bPos = 0; aPos < aEnd && bPos < that.count; )
- {
- if ( this.array[aPos] < that.array[bPos] )
- {
- this.array[destPos++] = this.array[aPos++];
- }
- else if ( this.array[aPos] > that.array[bPos] )
- {
- this.array[destPos++] = that.array[bPos++];
- }
- else
- {
- this.array[destPos++] = this.array[aPos++];
- bPos++;
- }
- }
-
- // Copy any remainder.
- int aRemain = aEnd - aPos;
- if (aRemain > 0)
- {
- System.arraycopy(this.array, aPos, this.array, destPos, aRemain);
- destPos += aRemain;
- }
-
- int bRemain = that.count - bPos;
- if (bRemain > 0)
- {
- System.arraycopy(that.array, bPos, this.array, destPos, bRemain);
- destPos += bRemain;
- }
-
- count = destPos;
+ return false;
}
/**
- * Return the number of IDs in an import ID set.
- *
* @return The current size of an import ID set.
+ * @throws IllegalStateException if this set is undefined
*/
- public int size()
+ int size()
{
- return count;
- }
-
- private boolean add(long entryID)
- {
- resize(count+1);
-
- if (count == 0 || entryID > array[count-1])
- {
- array[count++] = entryID;
- return true;
+ if (!isDefined()) {
+ throw new IllegalStateException("This ImportIDSet is undefined");
}
-
- int pos = binarySearch(array, count, entryID);
- if (pos >=0)
- {
- return false;
- }
-
- // For a negative return value r, the index -(r+1) gives the array
- // index at which the specified value can be inserted to maintain
- // the sorted order of the array.
- pos = -(pos+1);
-
- System.arraycopy(array, pos, array, pos+1, count-pos);
- array[pos] = entryID;
- count++;
- return true;
- }
-
- private static int binarySearch(long[] a, int count, long key)
- {
- int low = 0;
- int high = count-1;
-
- while (low <= high)
- {
- int mid = low + high >> 1;
- long midVal = a[mid];
-
- if (midVal < key)
- {
- low = mid + 1;
- }
- else if (midVal > key)
- {
- high = mid - 1;
- }
- else
- {
- return mid; // key found
- }
- }
- return -(low + 1); // key not found.
- }
-
- private void resize(int size)
- {
- if (array == null)
- {
- array = new long[size];
- }
- else if (array.length < size)
- {
- // Expand the size of the array in powers of two.
- int newSize = array.length == 0 ? 1 : array.length;
- do
- {
- newSize *= 2;
- } while (newSize < size);
-
- long[] newBytes = new long[newSize];
- System.arraycopy(array, 0, newBytes, 0, count);
- array = newBytes;
- }
+ return (int) entryIDSet.size();
}
/**
- * Create a byte string representing this object's value that is suitable to write to a DB.
- *
- * @return A byte string representing this object's value
+ * @return The byte string containing the DB key related to this set.
*/
- public ByteString valueToByteString()
- {
- if(isDefined) {
- return encodeDefined();
- }
- return ByteString.valueOf(undefinedSize);
- }
-
- private ByteString encodeDefined()
- {
- int encodedSize = count * 8;
- ByteStringBuilder bytes = new ByteStringBuilder(encodedSize);
- for (int i = 0; i < count; i++)
- {
- bytes.append(array[i]);
- }
- return bytes.toByteString();
- }
-
- /**
- * Return the DB key related to an import ID set.
- *
- * @return The byte string containing the key.
- */
- public ByteSequence getKey()
+ ByteSequence getKey()
{
return key;
}
- /** {@inheritDoc} */
+ /**
+ * @return Binary representation of this ID set
+ */
+ ByteString valueToByteString() {
+ return entryIDSet.toByteString();
+ }
+
@Override
public String toString()
{
- final StringBuilder sb = new StringBuilder();
- if (isDefined())
- {
- sb.append("[COUNT:").append(size()).append("]");
- }
- else
- {
- sb.append("[LIMIT-EXCEEDED");
- if (undefinedSize < Long.MAX_VALUE)
- {
- sb.append(":").append(undefinedSize);
- }
- sb.append("]");
- }
- return sb.toString();
+ return entryIDSet.toString();
}
}
--
Gitblit v1.10.0