Changed the btree page split to use tuples sizes in order to determine which tuples are going to move to the new page and added a test case.
git-svn-id: https://hyracks.googlecode.com/svn/branches/hyracks_lsm_tree@2355 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMInteriorFrame.java b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMInteriorFrame.java
index ef47a64..61fed72 100644
--- a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMInteriorFrame.java
+++ b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMInteriorFrame.java
@@ -180,14 +180,28 @@
ByteBuffer right = rightFrame.getBuffer();
int tupleCount = getTupleCount();
- // Find split point, and determine into which frame the new tuple should be inserted into.
- int tuplesToLeft = (tupleCount / 2) + (tupleCount % 2);
+ // Find split point, and determine into which frame the new tuple should
+ // be inserted into.
+ int tuplesToLeft;
ITreeIndexFrame targetFrame = null;
- frameTuple.resetByTupleIndex(this, tuplesToLeft - 1);
- if (cmp.compare(tuple, frameTuple) <= 0) {
- targetFrame = this;
- } else {
+
+ int totalSize = 0;
+ int halfPageSize = buf.capacity() / 2 - getPageHeaderSize();
+ int i;
+ for (i = 0; i < tupleCount; ++i) {
+ frameTuple.resetByTupleIndex(this, i);
+ totalSize += tupleWriter.bytesRequired(frameTuple) + slotManager.getSlotSize();
+ if (totalSize >= halfPageSize) {
+ break;
+ }
+ }
+
+ if (cmp.compare(tuple, frameTuple) > 0) {
+ tuplesToLeft = i;
targetFrame = rightFrame;
+ } else {
+ tuplesToLeft = i + 1;
+ targetFrame = this;
}
int tuplesToRight = tupleCount - tuplesToLeft;
@@ -208,7 +222,8 @@
// Copy the split key to be inserted.
// We must do so because setting the new split key will overwrite the
- // old split key, and we cannot insert the existing split key at this point.
+ // old split key, and we cannot insert the existing split key at this
+ // point.
ISplitKey savedSplitKey = splitKey.duplicate(tupleWriter.createTupleReference());
// Set split key to be highest value in left page.
@@ -230,7 +245,8 @@
// Insert the saved split key.
int targetTupleIndex;
- // it's safe to catch this exception since it will have been caught before reaching here
+ // it's safe to catch this exception since it will have been caught
+ // before reaching here
try {
targetTupleIndex = ((BTreeNSMInteriorFrame) targetFrame).findInsertTupleIndex(savedSplitKey.getTuple());
} catch (TreeIndexException e) {
diff --git a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMLeafFrame.java b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMLeafFrame.java
index a493226..3883b80 100644
--- a/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMLeafFrame.java
+++ b/hyracks-storage-am-btree/src/main/java/edu/uci/ics/hyracks/storage/am/btree/frames/BTreeNSMLeafFrame.java
@@ -87,7 +87,8 @@
public int findUpsertTupleIndex(ITupleReference tuple) throws TreeIndexException {
int tupleIndex = slotManager.findTupleIndex(tuple, frameTuple, cmp, FindTupleMode.INCLUSIVE,
FindTupleNoExactMatchPolicy.HIGHER_KEY);
- // Just return the found tupleIndex. The caller will make the final decision whether to insert or update.
+ // Just return the found tupleIndex. The caller will make the final
+ // decision whether to insert or update.
return tupleIndex;
}
@@ -95,14 +96,16 @@
public ITupleReference getMatchingKeyTuple(ITupleReference searchTuple, int targetTupleIndex) {
// Examine the tuple index to determine whether it is valid or not.
if (targetTupleIndex != slotManager.getGreatestKeyIndicator()) {
- // We need to check the key to determine whether it's an insert or an update/delete
+ // We need to check the key to determine whether it's an insert or
+ // an update/delete
frameTuple.resetByTupleIndex(this, targetTupleIndex);
if (cmp.compare(searchTuple, frameTuple) == 0) {
// The keys match, it's an update/delete
return frameTuple;
}
}
- // Either the tuple index is a special indicator, or the keys don't match.
+ // Either the tuple index is a special indicator, or the keys don't
+ // match.
// In those cases, we are definitely dealing with an insert.
return null;
}
@@ -138,17 +141,26 @@
ByteBuffer right = rightFrame.getBuffer();
int tupleCount = getTupleCount();
- // Find split point, and determine into which frame the new tuple should be inserted into.
+ // Find split point, and determine into which frame the new tuple should
+ // be inserted into.
int tuplesToLeft;
- int mid = tupleCount / 2;
ITreeIndexFrame targetFrame = null;
- int tupleOff = slotManager.getTupleOff(slotManager.getSlotEndOff() + slotManager.getSlotSize() * mid);
- frameTuple.resetByTupleOffset(buf, tupleOff);
+ int totalSize = 0;
+ int halfPageSize = buf.capacity() / 2 - getPageHeaderSize();
+ int i;
+ for (i = 0; i < tupleCount; ++i) {
+ frameTuple.resetByTupleIndex(this, i);
+ totalSize += tupleWriter.getCopySpaceRequired(frameTuple) + slotManager.getSlotSize();
+ if (totalSize >= halfPageSize) {
+ break;
+ }
+ }
+
if (cmp.compare(tuple, frameTuple) >= 0) {
- tuplesToLeft = mid + (tupleCount % 2);
+ tuplesToLeft = i + 1;
targetFrame = rightFrame;
} else {
- tuplesToLeft = mid;
+ tuplesToLeft = i;
targetFrame = this;
}
int tuplesToRight = tupleCount - tuplesToLeft;
@@ -173,7 +185,8 @@
// Insert the new tuple.
int targetTupleIndex;
- // it's safe to catch this exception since it will have been caught before reaching here
+ // it's safe to catch this exception since it will have been caught
+ // before reaching here
try {
targetTupleIndex = ((BTreeNSMLeafFrame) targetFrame).findInsertTupleIndex(tuple);
} catch (TreeIndexException e) {
@@ -182,8 +195,12 @@
targetFrame.insert(tuple, targetTupleIndex);
// Set the split key to be highest key in the left page.
- tupleOff = slotManager.getTupleOff(slotManager.getSlotEndOff());
+ int tupleOff = slotManager.getTupleOff(slotManager.getSlotEndOff());
+ try {
frameTuple.resetByTupleOffset(buf, tupleOff);
+ } catch (Exception e) {
+ throw new IllegalStateException(e);
+ }
int splitKeySize = tupleWriter.bytesRequired(frameTuple, 0, cmp.getKeyFieldCount());
splitKey.initData(splitKeySize);
tupleWriter.writeTupleFields(frameTuple, 0, cmp.getKeyFieldCount(), splitKey.getBuffer().array(), 0);
diff --git a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexTupleWriter.java b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexTupleWriter.java
index 30e8f39..069ede8 100644
--- a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexTupleWriter.java
+++ b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/api/ITreeIndexTupleWriter.java
@@ -36,4 +36,9 @@
// the main idea is that the format of the written tuple may not be the same
// as the format written by this writer
public ITreeIndexTupleReference createTupleReference();
+
+ // This method is only used by the BTree leaf frame split method since tuples
+ // in the LSM-BTree can be either matter or anti-matter tuple and we want to
+ // to calculate the size of all tuples in the frame.
+ public int getCopySpaceRequired(ITupleReference tuple);
}
diff --git a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/SimpleTupleWriter.java b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/SimpleTupleWriter.java
index f5ec5f3..8cd8d98 100644
--- a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/SimpleTupleWriter.java
+++ b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/SimpleTupleWriter.java
@@ -23,12 +23,12 @@
public class SimpleTupleWriter implements ITreeIndexTupleWriter {
- // Write short in little endian to target byte array at given offset.
- private static void writeShortL(short s, byte[] buf, int targetOff) {
- buf[targetOff] = (byte)(s >> 8);
- buf[targetOff + 1] = (byte)(s >> 0);
- }
-
+ // Write short in little endian to target byte array at given offset.
+ private static void writeShortL(short s, byte[] buf, int targetOff) {
+ buf[targetOff] = (byte) (s >> 8);
+ buf[targetOff + 1] = (byte) (s >> 0);
+ }
+
@Override
public int bytesRequired(ITupleReference tuple) {
int bytes = getNullFlagsBytes(tuple) + getFieldSlotsBytes(tuple);
@@ -56,10 +56,10 @@
public int writeTuple(ITupleReference tuple, ByteBuffer targetBuf, int targetOff) {
return writeTuple(tuple, targetBuf.array(), targetOff);
}
-
+
@Override
- public int writeTuple(ITupleReference tuple, byte[] targetBuf, int targetOff) {
- int runner = targetOff;
+ public int writeTuple(ITupleReference tuple, byte[] targetBuf, int targetOff) {
+ int runner = targetOff;
int nullFlagsBytes = getNullFlagsBytes(tuple);
int fieldSlotsBytes = getFieldSlotsBytes(tuple);
for (int i = 0; i < nullFlagsBytes; i++) {
@@ -68,18 +68,16 @@
runner += fieldSlotsBytes;
int fieldEndOff = 0;
for (int i = 0; i < tuple.getFieldCount(); i++) {
- System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner,
- tuple.getFieldLength(i));
+ System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner, tuple.getFieldLength(i));
fieldEndOff += tuple.getFieldLength(i);
runner += tuple.getFieldLength(i);
writeShortL((short) fieldEndOff, targetBuf, targetOff + nullFlagsBytes + i * 2);
}
return runner - targetOff;
- }
+ }
@Override
- public int writeTupleFields(ITupleReference tuple, int startField, int numFields, byte[] targetBuf,
- int targetOff) {
+ public int writeTupleFields(ITupleReference tuple, int startField, int numFields, byte[] targetBuf, int targetOff) {
int runner = targetOff;
int nullFlagsBytes = getNullFlagsBytes(tuple, startField, numFields);
for (int i = 0; i < nullFlagsBytes; i++) {
@@ -90,10 +88,9 @@
int fieldEndOff = 0;
int fieldCounter = 0;
for (int i = startField; i < startField + numFields; i++) {
- System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner,
- tuple.getFieldLength(i));
+ System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner, tuple.getFieldLength(i));
fieldEndOff += tuple.getFieldLength(i);
- runner += tuple.getFieldLength(i);
+ runner += tuple.getFieldLength(i);
writeShortL((short) fieldEndOff, targetBuf, targetOff + nullFlagsBytes + fieldCounter * 2);
fieldCounter++;
}
@@ -115,5 +112,9 @@
protected int getFieldSlotsBytes(ITupleReference tuple, int startField, int numFields) {
return numFields * 2;
- }
+ }
+
+ public int getCopySpaceRequired(ITupleReference tuple) {
+ return bytesRequired(tuple);
+ }
}
diff --git a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/TypeAwareTupleWriter.java b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/TypeAwareTupleWriter.java
index 9730346..ab14441 100644
--- a/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/TypeAwareTupleWriter.java
+++ b/hyracks-storage-am-common/src/main/java/edu/uci/ics/hyracks/storage/am/common/tuples/TypeAwareTupleWriter.java
@@ -87,8 +87,7 @@
}
@Override
- public int writeTupleFields(ITupleReference tuple, int startField, int numFields, byte[] targetBuf,
- int targetOff) {
+ public int writeTupleFields(ITupleReference tuple, int startField, int numFields, byte[] targetBuf, int targetOff) {
int runner = targetOff;
int nullFlagsBytes = getNullFlagsBytes(numFields);
// write null indicator bits
@@ -106,8 +105,7 @@
runner = encDec.getPos();
for (int i = startField; i < startField + numFields; i++) {
- System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner,
- tuple.getFieldLength(i));
+ System.arraycopy(tuple.getFieldData(i), tuple.getFieldStart(i), targetBuf, runner, tuple.getFieldLength(i));
runner += tuple.getFieldLength(i);
}
@@ -149,4 +147,8 @@
public void setTypeTraits(ITypeTraits[] typeTraits) {
this.typeTraits = typeTraits;
}
+
+ public int getCopySpaceRequired(ITupleReference tuple) {
+ return bytesRequired(tuple);
+ }
}
diff --git a/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/tuples/LSMBTreeTupleWriter.java b/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/tuples/LSMBTreeTupleWriter.java
index dd8d2b9..5943a82 100644
--- a/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/tuples/LSMBTreeTupleWriter.java
+++ b/hyracks-storage-am-lsm-btree/src/main/java/edu/uci/ics/hyracks/storage/am/lsm/btree/tuples/LSMBTreeTupleWriter.java
@@ -41,6 +41,11 @@
}
@Override
+ public int getCopySpaceRequired(ITupleReference tuple) {
+ return super.bytesRequired(tuple);
+ }
+
+ @Override
public ITreeIndexTupleReference createTupleReference() {
return new LSMBTreeTupleReference(typeTraits, numKeyFields);
}
diff --git a/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/storage/am/btree/OrderedIndexExamplesTest.java b/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/storage/am/btree/OrderedIndexExamplesTest.java
index 3962d06..759a292 100644
--- a/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/storage/am/btree/OrderedIndexExamplesTest.java
+++ b/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/storage/am/btree/OrderedIndexExamplesTest.java
@@ -38,7 +38,6 @@
import edu.uci.ics.hyracks.storage.am.btree.impls.RangePredicate;
import edu.uci.ics.hyracks.storage.am.btree.util.BTreeUtils;
import edu.uci.ics.hyracks.storage.am.common.TestOperationCallback;
-import edu.uci.ics.hyracks.storage.am.common.api.UnsortedInputException;
import edu.uci.ics.hyracks.storage.am.common.api.IIndexAccessor;
import edu.uci.ics.hyracks.storage.am.common.api.IIndexBulkLoader;
import edu.uci.ics.hyracks.storage.am.common.api.IIndexCursor;
@@ -46,6 +45,7 @@
import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexAccessor;
import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexCursor;
import edu.uci.ics.hyracks.storage.am.common.api.TreeIndexException;
+import edu.uci.ics.hyracks.storage.am.common.api.UnsortedInputException;
import edu.uci.ics.hyracks.storage.am.common.impls.TreeIndexDiskOrderScanCursor;
import edu.uci.ics.hyracks.storage.am.common.ophelpers.MultiComparator;
@@ -58,10 +58,9 @@
throws TreeIndexException;
/**
- * Fixed-Length Key,Value Example.
- * Create a tree index with one fixed-length key field and one fixed-length value
- * field. Fill index with random values using insertions (not bulk load).
- * Perform scans and range search.
+ * Fixed-Length Key,Value Example. Create a tree index with one fixed-length
+ * key field and one fixed-length value field. Fill index with random values
+ * using insertions (not bulk load). Perform scans and range search.
*/
@Test
public void fixedLengthKeyValueExample() throws Exception {
@@ -136,10 +135,79 @@
}
/**
- * Composite Key Example (Non-Unique Index).
- * Create a tree index with two fixed-length key fields and one fixed-length
- * value field. Fill index with random values using insertions (not bulk
- * load) Perform scans and range search.
+ * This test the btree page split. Originally this test didn't pass since
+ * the btree was spliting by cardinality and not size. Now, it split page by
+ * size.
+ */
+ @Test
+ public void pageSplitTestExample() throws Exception {
+ if (LOGGER.isLoggable(Level.INFO)) {
+ LOGGER.info("BTree page split test.");
+ }
+
+ // Declare fields.
+ int fieldCount = 2;
+ ITypeTraits[] typeTraits = new ITypeTraits[fieldCount];
+ typeTraits[0] = UTF8StringPointable.TYPE_TRAITS;
+ typeTraits[1] = UTF8StringPointable.TYPE_TRAITS;
+ // Declare field serdes.
+ ISerializerDeserializer[] fieldSerdes = { UTF8StringSerializerDeserializer.INSTANCE,
+ UTF8StringSerializerDeserializer.INSTANCE };
+
+ // Declare keys.
+ int keyFieldCount = 1;
+ IBinaryComparatorFactory[] cmpFactories = new IBinaryComparatorFactory[keyFieldCount];
+ cmpFactories[0] = PointableBinaryComparatorFactory.of(UTF8StringPointable.FACTORY);
+
+ ITreeIndex treeIndex = createTreeIndex(typeTraits, cmpFactories);
+ treeIndex.create();
+ treeIndex.activate();
+
+ ArrayTupleBuilder tb = new ArrayTupleBuilder(fieldCount);
+ ArrayTupleReference tuple = new ArrayTupleReference();
+ IIndexAccessor indexAccessor = (IIndexAccessor) treeIndex.createAccessor(TestOperationCallback.INSTANCE,
+ TestOperationCallback.INSTANCE);
+
+ String key = "111";
+ String data = "XXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ key = "222";
+ data = "XXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ key = "333";
+ data = "XXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ key = "444";
+ data = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ key = "555";
+ data = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ key = "666";
+ data = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+ TupleUtils.createTuple(tb, tuple, fieldSerdes, key, data);
+ indexAccessor.insert(tuple);
+
+ treeIndex.validate();
+ treeIndex.deactivate();
+ treeIndex.destroy();
+ }
+
+ /**
+ * Composite Key Example (Non-Unique Index). Create a tree index with two
+ * fixed-length key fields and one fixed-length value field. Fill index with
+ * random values using insertions (not bulk load) Perform scans and range
+ * search.
*/
@Test
public void twoFixedLengthKeysOneFixedLengthValueExample() throws Exception {
@@ -297,10 +365,10 @@
}
/**
- * Deletion Example.
- * Create a BTree with one variable-length key field and one variable-length
- * value field. Fill B-tree with random values using insertions, then delete
- * entries one-by-one. Repeat procedure a few times on same BTree.
+ * Deletion Example. Create a BTree with one variable-length key field and
+ * one variable-length value field. Fill B-tree with random values using
+ * insertions, then delete entries one-by-one. Repeat procedure a few times
+ * on same BTree.
*/
@Test
public void deleteExample() throws Exception {
@@ -399,10 +467,10 @@
}
/**
- * Update example.
- * Create a BTree with one variable-length key field and one variable-length
- * value field. Fill B-tree with random values using insertions, then update
- * entries one-by-one. Repeat procedure a few times on same BTree.
+ * Update example. Create a BTree with one variable-length key field and one
+ * variable-length value field. Fill B-tree with random values using
+ * insertions, then update entries one-by-one. Repeat procedure a few times
+ * on same BTree.
*/
@Test
public void updateExample() throws Exception {
@@ -486,9 +554,8 @@
}
/**
- * Bulk load example.
- * Load a tree with 100,000 tuples. BTree has a composite key to "simulate"
- * non-unique index creation.
+ * Bulk load example. Load a tree with 100,000 tuples. BTree has a composite
+ * key to "simulate" non-unique index creation.
*/
@Test
public void bulkLoadExample() throws Exception {
@@ -554,11 +621,11 @@
treeIndex.deactivate();
treeIndex.destroy();
}
-
+
/**
- * Bulk load failure example.
- * Repeatedly loads a tree with 1,000 tuples, of which one tuple at each possible position
- * does not conform to the expected order. We expect the bulk load to fail with an exception.
+ * Bulk load failure example. Repeatedly loads a tree with 1,000 tuples, of
+ * which one tuple at each possible position does not conform to the
+ * expected order. We expect the bulk load to fail with an exception.
*/
@Test
public void bulkOrderVerificationExample() throws Exception {
@@ -581,38 +648,38 @@
ArrayTupleReference tuple = new ArrayTupleReference();
int ins = 1000;
for (int i = 1; i < ins; i++) {
- ITreeIndex treeIndex = createTreeIndex(typeTraits, cmpFactories);
+ ITreeIndex treeIndex = createTreeIndex(typeTraits, cmpFactories);
treeIndex.create();
treeIndex.activate();
// Load sorted records, and expect to fail at tuple i.
IIndexBulkLoader bulkLoader = treeIndex.createBulkLoader(0.7f, true);
for (int j = 0; j < ins; j++) {
- if (j > i) {
- fail("Bulk load failure test unexpectedly succeeded past tuple: " + j);
- }
- int key = j;
- if (j == i) {
- int swapElementCase = Math.abs(rnd.nextInt()) % 2;
- if (swapElementCase == 0) {
- // Element equal to previous element.
- key--;
- } else {
- // Element smaller than previous element.
- key -= Math.abs(Math.random() % (ins-1)) + 1;
- }
- }
- TupleUtils.createIntegerTuple(tb, tuple, key, 5);
- try {
- bulkLoader.add(tuple);
- } catch (UnsortedInputException e) {
- if (j != i) {
- fail("Unexpected exception: " + e.getMessage());
- }
- // Success.
- break;
- }
- }
+ if (j > i) {
+ fail("Bulk load failure test unexpectedly succeeded past tuple: " + j);
+ }
+ int key = j;
+ if (j == i) {
+ int swapElementCase = Math.abs(rnd.nextInt()) % 2;
+ if (swapElementCase == 0) {
+ // Element equal to previous element.
+ key--;
+ } else {
+ // Element smaller than previous element.
+ key -= Math.abs(Math.random() % (ins - 1)) + 1;
+ }
+ }
+ TupleUtils.createIntegerTuple(tb, tuple, key, 5);
+ try {
+ bulkLoader.add(tuple);
+ } catch (UnsortedInputException e) {
+ if (j != i) {
+ fail("Unexpected exception: " + e.getMessage());
+ }
+ // Success.
+ break;
+ }
+ }
treeIndex.deactivate();
treeIndex.destroy();