@Override public void performOp(ITupleReference tuple, TestOperation op) throws HyracksDataException, IndexException { LSMBTreeAccessor accessor = (LSMBTreeAccessor) indexAccessor; IIndexCursor searchCursor = accessor.createSearchCursor(false); MultiComparator cmp = accessor.getMultiComparator(); RangePredicate rangePred = new RangePredicate(tuple, tuple, true, true, cmp, cmp); switch (op) { case INSERT: try { accessor.insert(tuple); } catch (TreeIndexDuplicateKeyException e) { // Ignore duplicate keys, since we get random tuples. } break; case DELETE: // Create a tuple reference with only key fields. deleteTb.reset(); for (int i = 0; i < numKeyFields; i++) { deleteTb.addField(tuple.getFieldData(i), tuple.getFieldStart(i), tuple.getFieldLength(i)); } deleteTuple.reset(deleteTb.getFieldEndOffsets(), deleteTb.getByteArray()); try { accessor.delete(deleteTuple); } catch (TreeIndexNonExistentKeyException e) { // Ignore non-existant keys, since we get random tuples. } break; case UPDATE: try { accessor.update(tuple); } catch (TreeIndexNonExistentKeyException e) { // Ignore non-existant keys, since we get random tuples. } catch (BTreeNotUpdateableException e) { // Ignore not updateable exception due to numKeys == numFields. } break; case POINT_SEARCH: searchCursor.reset(); rangePred.setLowKey(tuple, true); rangePred.setHighKey(tuple, true); accessor.search(searchCursor, rangePred); consumeCursorTuples(searchCursor); break; case SCAN: searchCursor.reset(); rangePred.setLowKey(null, true); rangePred.setHighKey(null, true); accessor.search(searchCursor, rangePred); consumeCursorTuples(searchCursor); break; case MERGE: accessor.scheduleMerge(NoOpIOOperationCallback.INSTANCE, lsmBTree.getImmutableComponents()); break; default: throw new HyracksDataException("Op " + op.toString() + " not supported."); } }
@Override public boolean hasNext() throws HyracksDataException, IndexException { if (nextHasBeenCalled) { return false; } else if (foundTuple) { return true; } boolean reconciled = false; for (int i = 0; i < numBTrees; ++i) { btreeAccessors[i].search(rangeCursors[i], predicate); if (rangeCursors[i].hasNext()) { rangeCursors[i].next(); // We use the predicate's to lock the key instead of the tuple that we get from cursor to // avoid copying the tuple when we do the "unlatch dance" if (reconciled || searchCallback.proceed(predicate.getLowKey())) { // if proceed is successful, then there's no need for doing the "unlatch dance" if (((ILSMTreeTupleReference) rangeCursors[i].getTuple()).isAntimatter()) { searchCallback.cancel(predicate.getLowKey()); rangeCursors[i].close(); return false; } else { frameTuple = rangeCursors[i].getTuple(); foundTuple = true; return true; } } if (i == 0 && includeMutableComponent) { // unlatch/unpin rangeCursors[i].reset(); searchCallback.reconcile(predicate.getLowKey()); reconciled = true; // retraverse btreeAccessors[0].search(rangeCursors[i], predicate); searchCallback.complete(predicate.getLowKey()); if (rangeCursors[i].hasNext()) { rangeCursors[i].next(); if (((ILSMTreeTupleReference) rangeCursors[i].getTuple()).isAntimatter()) { searchCallback.cancel(predicate.getLowKey()); rangeCursors[i].close(); return false; } else { frameTuple = rangeCursors[i].getTuple(); foundTuple = true; return true; } } else { rangeCursors[i].close(); } } else { frameTuple = rangeCursors[i].getTuple(); searchCallback.reconcile(frameTuple); searchCallback.complete(frameTuple); foundTuple = true; return true; } } else { rangeCursors[i].close(); } } return false; }