[NO ISSUE][STO] Only re-use compatible accessors in LSM Cursors
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Currently, when a search operation starts, using a previously
used LSMCursor, and the number of components didn't change, we
re-use cursors and accessors.
- However, we didn't check the type of the underlying component
and since disk cursors/accessors are incompatible with memory
component trees, we end up getting ClassCastException.
- This change checks for compatibility. If the component/cursor
pair are incompatible, the cursor and accessor are destroyed
and new ones are created.
Change-Id: I0fe224af1049b53c8cc37448ee8bfa2ccd780564
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2608
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Luo Chen <cluo8@uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
index 1209e17..3520e3a 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreePointSearchCursor.java
@@ -22,6 +22,7 @@
import java.util.List;
import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.util.CleanupUtils;
import org.apache.hyracks.dataflow.common.data.accessors.ITupleReference;
import org.apache.hyracks.storage.am.bloomfilter.impls.BloomFilter;
import org.apache.hyracks.storage.am.btree.impls.BTree;
@@ -162,7 +163,16 @@
searchCallback = lsmInitialState.getSearchOperationCallback();
predicate = (RangePredicate) lsmInitialState.getSearchPredicate();
numBTrees = operationalComponents.size();
- if (btreeCursors == null || btreeCursors.length != numBTrees) {
+ if (btreeCursors != null && btreeCursors.length != numBTrees) {
+ Throwable failure = CleanupUtils.destroy(null, btreeCursors);
+ btreeCursors = null;
+ failure = CleanupUtils.destroy(failure, btreeAccessors);
+ btreeAccessors = null;
+ if (failure != null) {
+ throw HyracksDataException.create(failure);
+ }
+ }
+ if (btreeCursors == null) {
// object creation: should be relatively low
btreeCursors = new ITreeIndexCursor[numBTrees];
btreeAccessors = new BTreeAccessor[numBTrees];
@@ -175,8 +185,13 @@
BTree btree = (BTree) component.getIndex();
if (component.getType() == LSMComponentType.MEMORY) {
includeMutableComponent = true;
- bloomFilters[i] = null;
+ if (bloomFilters[i] != null) {
+ destroyAndNullifyCursorAtIndex(i);
+ }
} else {
+ if (bloomFilters[i] == null) {
+ destroyAndNullifyCursorAtIndex(i);
+ }
bloomFilters[i] = ((LSMBTreeWithBloomFilterDiskComponent) component).getBloomFilter();
}
@@ -193,6 +208,18 @@
foundTuple = false;
}
+ private void destroyAndNullifyCursorAtIndex(int i) throws HyracksDataException {
+ // component at location i was a disk component before, and is now a memory component, or vise versa
+ bloomFilters[i] = null;
+ Throwable failure = CleanupUtils.destroy(null, btreeCursors[i]);
+ btreeCursors[i] = null;
+ failure = CleanupUtils.destroy(failure, btreeAccessors[i]);
+ btreeAccessors[i] = null;
+ if (failure != null) {
+ throw HyracksDataException.create(failure);
+ }
+ }
+
@Override
public void doNext() throws HyracksDataException {
nextHasBeenCalled = true;
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeRangeSearchCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeRangeSearchCursor.java
index bfda985..a675047 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeRangeSearchCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeRangeSearchCursor.java
@@ -47,10 +47,9 @@
public class LSMBTreeRangeSearchCursor extends LSMIndexSearchCursor {
private final ArrayTupleReference copyTuple;
private final RangePredicate reusablePred;
-
private ISearchOperationCallback searchCallback;
-
private BTreeAccessor[] btreeAccessors;
+ private boolean[] isMemoryComponent;
private ArrayTupleBuilder tupleBuilder;
private boolean canCallProceed = true;
private boolean resultOfSearchCallbackProceed = false;
@@ -340,15 +339,19 @@
// object creation: should be relatively low
rangeCursors = new IIndexCursor[numBTrees];
btreeAccessors = new BTreeAccessor[numBTrees];
+ isMemoryComponent = new boolean[numBTrees];
} else if (rangeCursors.length != numBTrees) {
// should destroy first
Throwable failure = CleanupUtils.destroy(null, btreeAccessors);
+ btreeAccessors = null;
failure = CleanupUtils.destroy(failure, rangeCursors);
+ rangeCursors = null;
if (failure != null) {
throw HyracksDataException.create(failure);
}
rangeCursors = new IIndexCursor[numBTrees];
btreeAccessors = new BTreeAccessor[numBTrees];
+ isMemoryComponent = new boolean[numBTrees];
}
for (int i = 0; i < numBTrees; i++) {
ILSMComponent component = operationalComponents.get(i);
@@ -357,7 +360,7 @@
includeMutableComponent = true;
}
btree = (BTree) component.getIndex();
- if (btreeAccessors[i] == null) {
+ if (btreeAccessors[i] == null || destroyIncompatible(component, i)) {
btreeAccessors[i] = btree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
rangeCursors[i] = btreeAccessors[i].createSearchCursor(false);
} else {
@@ -365,6 +368,7 @@
btreeAccessors[i].reset(btree, NoOpOperationCallback.INSTANCE, NoOpOperationCallback.INSTANCE);
rangeCursors[i].close();
}
+ isMemoryComponent[i] = component.getType() == LSMComponentType.MEMORY;
}
IndexCursorUtils.open(btreeAccessors, rangeCursors, searchPred);
try {
@@ -377,6 +381,22 @@
}
}
+ private boolean destroyIncompatible(ILSMComponent component, int index) throws HyracksDataException {
+ // exclusive or. if the component is memory and the previous one at that index was a disk component
+ // or vice versa, then we should destroy the cursor and accessor since they need to be recreated
+ if (component.getType() == LSMComponentType.MEMORY ^ isMemoryComponent[index]) {
+ Throwable failure = CleanupUtils.destroy(null, btreeAccessors[index]);
+ btreeAccessors[index] = null;
+ failure = CleanupUtils.destroy(failure, rangeCursors[index]);
+ rangeCursors[index] = null;
+ if (failure != null) {
+ throw HyracksDataException.create(failure);
+ }
+ return true;
+ }
+ return false;
+ }
+
@Override
public boolean getSearchOperationCallbackProceedResult() {
return resultOfSearchCallbackProceed;