[ASTERIXDB-2321][STO] Follow the contract in IIndexCursor.open calls
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- The index cursor contract says that an open call which returns
successfully, leaves the cursor in the open state, otherwise,
the cursor remains in the closed state.
- The LSM cursors have many cursors inside. In the
case where one of the cursors fails to open, and an exception
is about to be thrown, we must close all previously open cursors
since the LSM cursor will be in the closed state
and close will not be called.
Change-Id: I19db2afd2d6ca4a2ca1056cd95ae504b2be69813
Reviewed-on: https://asterix-gerrit.ics.uci.edu/2501
Sonar-Qube: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Michael Blow <mblow@apache.org>
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Contrib: Jenkins <jenkins@fulliautomatix.ics.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/LSMBTreeDiskComponentScanCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeDiskComponentScanCursor.java
index a120296..a6c8393 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeDiskComponentScanCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeDiskComponentScanCursor.java
@@ -40,6 +40,7 @@
import org.apache.hyracks.storage.common.IIndexCursor;
import org.apache.hyracks.storage.common.ISearchPredicate;
import org.apache.hyracks.storage.common.MultiComparator;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMBTreeDiskComponentScanCursor extends LSMIndexSearchCursor {
@@ -77,15 +78,20 @@
BTree btree = (BTree) component.getIndex();
btreeAccessors[i] = btree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
rangeCursors[i] = btreeAccessors[i].createSearchCursor(false);
- btreeAccessors[i].search(rangeCursors[i], searchPred);
}
-
- cursorIndexPointable = new IntegerPointable();
- int length = IntegerPointable.TYPE_TRAITS.getFixedLength();
- cursorIndexPointable.set(new byte[length], 0, length);
-
- setPriorityQueueComparator();
- initPriorityQueue();
+ IndexCursorUtils.open(btreeAccessors, rangeCursors, searchPred);
+ try {
+ cursorIndexPointable = new IntegerPointable();
+ int length = IntegerPointable.TYPE_TRAITS.getFixedLength();
+ cursorIndexPointable.set(new byte[length], 0, length);
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ } catch (Throwable th) { // NOSONAR: Must call this on
+ for (int i = 0; i < numBTrees; i++) {
+ IndexCursorUtils.close(rangeCursors[i], th);
+ }
+ throw HyracksDataException.create(th);
+ }
}
@Override
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 0cb7d1c..bfda985 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
@@ -42,6 +42,7 @@
import org.apache.hyracks.storage.common.IIndexCursor;
import org.apache.hyracks.storage.common.ISearchOperationCallback;
import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMBTreeRangeSearchCursor extends LSMIndexSearchCursor {
private final ArrayTupleReference copyTuple;
@@ -349,7 +350,6 @@
rangeCursors = new IIndexCursor[numBTrees];
btreeAccessors = new BTreeAccessor[numBTrees];
}
-
for (int i = 0; i < numBTrees; i++) {
ILSMComponent component = operationalComponents.get(i);
BTree btree;
@@ -365,12 +365,16 @@
btreeAccessors[i].reset(btree, NoOpOperationCallback.INSTANCE, NoOpOperationCallback.INSTANCE);
rangeCursors[i].close();
}
- btreeAccessors[i].search(rangeCursors[i], searchPred);
}
-
- setPriorityQueueComparator();
- initPriorityQueue();
- canCallProceed = true;
+ IndexCursorUtils.open(btreeAccessors, rangeCursors, searchPred);
+ try {
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ canCallProceed = true;
+ } catch (Throwable th) { // NOSONAR Must catch all
+ IndexCursorUtils.close(rangeCursors, th);
+ throw HyracksDataException.create(th);
+ }
}
@Override
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeWithBuddySortedCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeWithBuddySortedCursor.java
index 2913be1..b600f12 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeWithBuddySortedCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBTreeWithBuddySortedCursor.java
@@ -25,6 +25,7 @@
import org.apache.hyracks.storage.am.lsm.common.api.ILSMIndexOperationContext;
import org.apache.hyracks.storage.common.ICursorInitialState;
import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMBTreeWithBuddySortedCursor extends LSMBTreeWithBuddyAbstractCursor {
// TODO: This class can be removed and instead use a search cursor that uses
@@ -160,12 +161,21 @@
foundNext = false;
for (int i = 0; i < numberOfTrees; i++) {
btreeCursors[i].close();
- btreeAccessors[i].search(btreeCursors[i], btreeRangePredicate);
- if (btreeCursors[i].hasNext()) {
- btreeCursors[i].next();
- } else {
- depletedBtreeCursors[i] = true;
+ }
+ IndexCursorUtils.open(btreeAccessors, btreeCursors, btreeRangePredicate);
+ try {
+ for (int i = 0; i < numberOfTrees; i++) {
+ if (btreeCursors[i].hasNext()) {
+ btreeCursors[i].next();
+ } else {
+ depletedBtreeCursors[i] = true;
+ }
}
+ } catch (Throwable th) { // NOSONAR Must catch all failures to close before throwing
+ for (int i = 0; i < numberOfTrees; i++) {
+ IndexCursorUtils.close(btreeCursors[i], th);
+ }
+ throw HyracksDataException.create(th);
}
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBuddyBTreeMergeCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBuddyBTreeMergeCursor.java
index fd13e62..b35c5d1 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBuddyBTreeMergeCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-btree/src/main/java/org/apache/hyracks/storage/am/lsm/btree/impls/LSMBuddyBTreeMergeCursor.java
@@ -32,6 +32,7 @@
import org.apache.hyracks.storage.common.IIndexAccessor;
import org.apache.hyracks.storage.common.IIndexCursor;
import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMBuddyBTreeMergeCursor extends LSMIndexSearchCursor {
@@ -55,7 +56,6 @@
lsmHarness = null;
int numBTrees = operationalComponents.size();
rangeCursors = new IIndexCursor[numBTrees];
-
RangePredicate btreePredicate = new RangePredicate(null, null, true, true, cmp, cmp);
IIndexAccessor[] btreeAccessors = new ITreeIndexAccessor[numBTrees];
for (int i = 0; i < numBTrees; i++) {
@@ -64,9 +64,14 @@
rangeCursors[i] = new BTreeRangeSearchCursor(leafFrame, false);
BTree buddyBtree = ((LSMBTreeWithBuddyDiskComponent) component).getBuddyIndex();
btreeAccessors[i] = buddyBtree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
- btreeAccessors[i].search(rangeCursors[i], btreePredicate);
}
- setPriorityQueueComparator();
- initPriorityQueue();
+ IndexCursorUtils.open(btreeAccessors, rangeCursors, btreePredicate);
+ try {
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ } catch (Throwable th) { // NOSONAR: Must catch all failures
+ IndexCursorUtils.close(rangeCursors, th);
+ throw HyracksDataException.create(th);
+ }
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/api/ILSMIndex.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/api/ILSMIndex.java
index 62493f4..a8467d3 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/api/ILSMIndex.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-common/src/main/java/org/apache/hyracks/storage/am/lsm/common/api/ILSMIndex.java
@@ -61,6 +61,15 @@
void modify(IIndexOperationContext ictx, ITupleReference tuple) throws HyracksDataException;
+ /**
+ * If this method returns successfully, then the cursor has been opened, and need to be closed
+ * Otherwise, it has not been opened
+ *
+ * @param ictx
+ * @param cursor
+ * @param pred
+ * @throws HyracksDataException
+ */
void search(ILSMIndexOperationContext ictx, IIndexCursor cursor, ISearchPredicate pred) throws HyracksDataException;
public void scanDiskComponents(ILSMIndexOperationContext ctx, IIndexCursor cursor) throws HyracksDataException;
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/impls/LSMInvertedIndexDeletedKeysBTreeMergeCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/impls/LSMInvertedIndexDeletedKeysBTreeMergeCursor.java
index 21ce940..f1f5241 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/impls/LSMInvertedIndexDeletedKeysBTreeMergeCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-invertedindex/src/main/java/org/apache/hyracks/storage/am/lsm/invertedindex/impls/LSMInvertedIndexDeletedKeysBTreeMergeCursor.java
@@ -30,6 +30,7 @@
import org.apache.hyracks.storage.common.IIndexCursor;
import org.apache.hyracks.storage.common.ISearchPredicate;
import org.apache.hyracks.storage.common.MultiComparator;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMInvertedIndexDeletedKeysBTreeMergeCursor extends LSMIndexSearchCursor {
@@ -48,7 +49,8 @@
(LSMInvertedIndexRangeSearchCursorInitialState) initialState;
cmp = lsmInitialState.getOriginalKeyComparator();
operationalComponents = lsmInitialState.getOperationalComponents();
- // We intentionally set the lsmHarness to null so that we don't call lsmHarness.endSearch() because we already do that when we merge the inverted indexes.
+ // We intentionally set the lsmHarness to null so that we don't call lsmHarness.endSearch() because we already
+ // do that when we merge the inverted indexes.
lsmHarness = null;
int numBTrees = operationalComponents.size();
rangeCursors = new IIndexCursor[numBTrees];
@@ -60,7 +62,13 @@
rangeCursors[i] = btreeAccessors.get(i).createSearchCursor(false);
btreeAccessors.get(i).search(rangeCursors[i], btreePredicate);
}
- setPriorityQueueComparator();
- initPriorityQueue();
+ IndexCursorUtils.open(btreeAccessors, rangeCursors, btreePredicate);
+ try {
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ } catch (Throwable th) { // NOSONAR: Must catch all failures
+ IndexCursorUtils.close(rangeCursors, th);
+ throw HyracksDataException.create(th);
+ }
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeDeletedKeysBTreeMergeCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeDeletedKeysBTreeMergeCursor.java
index 892fe83..b57b517 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeDeletedKeysBTreeMergeCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeDeletedKeysBTreeMergeCursor.java
@@ -33,6 +33,7 @@
import org.apache.hyracks.storage.common.IIndexAccessor;
import org.apache.hyracks.storage.common.IIndexCursor;
import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMRTreeDeletedKeysBTreeMergeCursor extends LSMIndexSearchCursor {
@@ -65,7 +66,13 @@
btreeAccessors[i] = btree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
btreeAccessors[i].search(rangeCursors[i], btreePredicate);
}
- setPriorityQueueComparator();
- initPriorityQueue();
+ IndexCursorUtils.open(btreeAccessors, rangeCursors, btreePredicate);
+ try {
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ } catch (Throwable th) { // NOSONAR: Must catch all failures
+ IndexCursorUtils.close(rangeCursors, th);
+ throw HyracksDataException.create(th);
+ }
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeSortedCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeSortedCursor.java
index 9bbc3e1..483e082 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeSortedCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeSortedCursor.java
@@ -28,6 +28,7 @@
import org.apache.hyracks.storage.am.lsm.common.api.ILSMIndexOperationContext;
import org.apache.hyracks.storage.common.ICursorInitialState;
import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMRTreeSortedCursor extends LSMRTreeAbstractCursor {
@@ -163,14 +164,19 @@
super.doOpen(initialState, searchPred);
depletedRtreeCursors = new boolean[numberOfTrees];
foundNext = false;
- for (int i = 0; i < numberOfTrees; i++) {
- rtreeCursors[i].close();
- rtreeAccessors[i].search(rtreeCursors[i], rtreeSearchPredicate);
- if (rtreeCursors[i].hasNext()) {
- rtreeCursors[i].next();
- } else {
- depletedRtreeCursors[i] = true;
+ try {
+ for (int i = 0; i < numberOfTrees; i++) {
+ rtreeCursors[i].close();
+ rtreeAccessors[i].search(rtreeCursors[i], rtreeSearchPredicate);
+ if (rtreeCursors[i].hasNext()) {
+ rtreeCursors[i].next();
+ } else {
+ depletedRtreeCursors[i] = true;
+ }
}
+ } catch (Throwable th) { // NOSONAR. Must catch all failures
+ IndexCursorUtils.close(rtreeCursors, th);
+ throw HyracksDataException.create(th);
}
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
index 449c711..427575b 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesFlushCursor.java
@@ -27,6 +27,7 @@
import org.apache.hyracks.storage.common.ICursorInitialState;
import org.apache.hyracks.storage.common.ISearchPredicate;
import org.apache.hyracks.storage.common.MultiComparator;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMRTreeWithAntiMatterTuplesFlushCursor extends EnforcedIndexCursor implements ILSMIndexCursor {
private final TreeTupleSorter rTreeTupleSorter;
@@ -49,17 +50,13 @@
@Override
public void doOpen(ICursorInitialState initialState, ISearchPredicate searchPred) throws HyracksDataException {
- boolean rtreeOpen = false;
- boolean btreeOpen = false;
try {
rTreeTupleSorter.open(initialState, searchPred);
- rtreeOpen = true;
bTreeTupleSorter.open(initialState, searchPred);
- btreeOpen = true;
- } finally {
- if (rtreeOpen && !btreeOpen) {
- rTreeTupleSorter.close();
- }
+ } catch (Throwable th) { // NOSONAR: Must catch all failures
+ IndexCursorUtils.close(bTreeTupleSorter, th);
+ IndexCursorUtils.close(rTreeTupleSorter, th);
+ throw HyracksDataException.create(th);
}
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesSearchCursor.java b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesSearchCursor.java
index 094acbc..7db65bd 100644
--- a/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesSearchCursor.java
+++ b/hyracks-fullstack/hyracks/hyracks-storage-am-lsm-rtree/src/main/java/org/apache/hyracks/storage/am/lsm/rtree/impls/LSMRTreeWithAntiMatterTuplesSearchCursor.java
@@ -42,6 +42,7 @@
import org.apache.hyracks.storage.common.ISearchOperationCallback;
import org.apache.hyracks.storage.common.ISearchPredicate;
import org.apache.hyracks.storage.common.MultiComparator;
+import org.apache.hyracks.storage.common.util.IndexCursorUtils;
public class LSMRTreeWithAntiMatterTuplesSearchCursor extends LSMIndexSearchCursor {
@@ -113,19 +114,25 @@
rangeCursors = new RTreeSearchCursor[numImmutableComponents];
ITreeIndexAccessor[] immutableRTreeAccessors = new ITreeIndexAccessor[numImmutableComponents];
int j = 0;
- for (int i = numMemoryComponents; i < operationalComponents.size(); i++) {
- ILSMComponent component = operationalComponents.get(i);
- rangeCursors[j] = new RTreeSearchCursor(
- (IRTreeInteriorFrame) lsmInitialState.getRTreeInteriorFrameFactory().createFrame(),
- (IRTreeLeafFrame) lsmInitialState.getRTreeLeafFrameFactory().createFrame());
- RTree rtree = ((LSMRTreeWithAntimatterDiskComponent) component).getIndex();
- immutableRTreeAccessors[j] = rtree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
- immutableRTreeAccessors[j].search(rangeCursors[j], searchPred);
- j++;
+ try {
+ for (int i = numMemoryComponents; i < operationalComponents.size(); i++) {
+ ILSMComponent component = operationalComponents.get(i);
+ rangeCursors[j] = new RTreeSearchCursor(
+ (IRTreeInteriorFrame) lsmInitialState.getRTreeInteriorFrameFactory().createFrame(),
+ (IRTreeLeafFrame) lsmInitialState.getRTreeLeafFrameFactory().createFrame());
+ RTree rtree = ((LSMRTreeWithAntimatterDiskComponent) component).getIndex();
+ immutableRTreeAccessors[j] = rtree.createAccessor(NoOpIndexAccessParameters.INSTANCE);
+ immutableRTreeAccessors[j].search(rangeCursors[j], searchPred);
+ j++;
+ }
+ searchNextCursor();
+ setPriorityQueueComparator();
+ initPriorityQueue();
+ } catch (Throwable th) { // NOSONAR: Must catch all failures
+ IndexCursorUtils.close(rangeCursors, th);
+ IndexCursorUtils.close(mutableRTreeCursors, th);
+ throw HyracksDataException.create(th);
}
- searchNextCursor();
- setPriorityQueueComparator();
- initPriorityQueue();
open = true;
}
diff --git a/hyracks-fullstack/hyracks/hyracks-storage-common/src/main/java/org/apache/hyracks/storage/common/util/IndexCursorUtils.java b/hyracks-fullstack/hyracks/hyracks-storage-common/src/main/java/org/apache/hyracks/storage/common/util/IndexCursorUtils.java
new file mode 100644
index 0000000..7587a2a
--- /dev/null
+++ b/hyracks-fullstack/hyracks/hyracks-storage-common/src/main/java/org/apache/hyracks/storage/common/util/IndexCursorUtils.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.hyracks.storage.common.util;
+
+import java.util.List;
+
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+import org.apache.hyracks.api.util.ExceptionUtils;
+import org.apache.hyracks.storage.common.IIndexAccessor;
+import org.apache.hyracks.storage.common.IIndexCursor;
+import org.apache.hyracks.storage.common.ISearchPredicate;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+public class IndexCursorUtils {
+
+ private static final Logger LOGGER = LogManager.getLogger();
+
+ private IndexCursorUtils() {
+ }
+
+ /**
+ * Close the IIndexCursor and suppress any Throwable thrown by the close call.
+ * This method must NEVER throw any Throwable
+ *
+ * @param cursor
+ * the cursor to close
+ * @param root
+ * the first exception encountered during release of resources
+ * @return the root Throwable if not null or a new Throwable if any was thrown, otherwise, it returns null
+ */
+ public static Throwable close(IIndexCursor cursor, Throwable root) {
+ if (cursor != null) {
+ try {
+ cursor.close();
+ } catch (Throwable th) { // NOSONAR Will be suppressed
+ try {
+ LOGGER.log(Level.WARN, "Failure closing a cursor", th);
+ } catch (Throwable loggingFailure) { // NOSONAR: Ignore catching Throwable
+ // NOSONAR ignore logging failure
+ }
+ root = ExceptionUtils.suppress(root, th); // NOSONAR: Using the same variable is not bad in this context
+ }
+ }
+ return root;
+ }
+
+ public static void open(List<IIndexAccessor> accessors, IIndexCursor[] cursors, ISearchPredicate pred)
+ throws HyracksDataException {
+ int opened = 0;
+ try {
+ for (int i = 0; i < cursors.length; i++) {
+ if (accessors.get(i) != null) {
+ accessors.get(i).search(cursors[i], pred);
+ }
+ opened++;
+ }
+ } catch (Throwable th) { // NOSONAR: Much catch all failures
+ for (int j = 0; j < opened; j++) {
+ IndexCursorUtils.close(cursors[j], th);
+ }
+ throw HyracksDataException.create(th);
+ }
+ }
+
+ public static void open(IIndexAccessor[] accessors, IIndexCursor[] cursors, ISearchPredicate pred)
+ throws HyracksDataException {
+ int opened = 0;
+ try {
+ for (int i = 0; i < accessors.length; i++) {
+ if (accessors[i] != null) {
+ accessors[i].search(cursors[i], pred);
+ }
+ opened++;
+ }
+ } catch (Throwable th) { // NOSONAR: Much catch all failures
+ for (int j = 0; j < opened; j++) {
+ IndexCursorUtils.close(cursors[j], th);
+ }
+ throw HyracksDataException.create(th);
+ }
+ }
+
+ public static Throwable close(IIndexCursor[] cursors, Throwable th) {
+ for (int j = 0; j < cursors.length; j++) {
+ th = IndexCursorUtils.close(cursors[j], th); // NOSONAR: Using the same variable is cleaner in this context
+ }
+ return th;
+ }
+
+}