@Override public void open(ICursorInitialState initialState, ISearchPredicate searchPred) throws HyracksDataException, IndexException { LSMBTreeCursorInitialState lsmInitialState = (LSMBTreeCursorInitialState) initialState; cmp = lsmInitialState.getOriginalKeyComparator(); includeMemComponent = lsmInitialState.getIncludeMemComponent(); operationalComponents = lsmInitialState.getOperationalComponents(); lsmHarness = lsmInitialState.getLSMHarness(); searchCallback = lsmInitialState.getSearchOperationCallback(); memBTreeAccessor = lsmInitialState.getMemBTreeAccessor(); predicate = (RangePredicate) lsmInitialState.getSearchPredicate(); reusablePred.setLowKeyComparator(cmp); reusablePred.setHighKey(predicate.getHighKey(), predicate.isHighKeyInclusive()); reusablePred.setHighKeyComparator(predicate.getHighKeyComparator()); int numBTrees = lsmInitialState.getNumBTrees(); rangeCursors = new IIndexCursor[numBTrees]; for (int i = 0; i < numBTrees; i++) { IBTreeLeafFrame leafFrame = (IBTreeLeafFrame) lsmInitialState.getLeafFrameFactory().createFrame(); rangeCursors[i] = new BTreeRangeSearchCursor(leafFrame, false); } setPriorityQueueComparator(); int cursorIx = 0; ListIterator<ILSMComponent> btreesIter = operationalComponents.listIterator(); if (includeMemComponent) { // Open cursor of in-memory BTree at index 0. memBTreeAccessor.search(rangeCursors[cursorIx], searchPred); // Skip 0 because it is the in-memory BTree. ++cursorIx; btreesIter.next(); } // Open cursors of on-disk BTrees. int numDiskComponents = includeMemComponent ? numBTrees - 1 : numBTrees; ITreeIndexAccessor[] diskBTreeAccessors = new ITreeIndexAccessor[numDiskComponents]; int diskBTreeIx = 0; while (btreesIter.hasNext()) { BTree diskBTree = (BTree) ((LSMBTreeImmutableComponent) btreesIter.next()).getBTree(); diskBTreeAccessors[diskBTreeIx] = diskBTree.createAccessor(NoOpOperationCallback.INSTANCE, NoOpOperationCallback.INSTANCE); diskBTreeAccessors[diskBTreeIx].search(rangeCursors[cursorIx], searchPred); cursorIx++; diskBTreeIx++; } initPriorityQueue(); proceed = true; }
@Override public void nextFrame(ByteBuffer buffer) throws HyracksDataException { accessor.reset(buffer); int tupleCount = accessor.getTupleCount(); try { for (int i = 0; i < tupleCount; i++) { if (lowKey != null) lowKey.reset(accessor, i); if (highKey != null) highKey.reset(accessor, i); rangePred.setLowKey(lowKey, lowKeyInclusive); rangePred.setHighKey(highKey, highKeyInclusive); cursor.reset(); indexAccessor.search(cursor, rangePred); writeSearchResults(accessor, i); } } catch (Exception e) { throw new HyracksDataException(e); } }
protected void checkPriorityQueue() throws HyracksDataException, IndexException { while (!outputPriorityQueue.isEmpty() || needPush == true) { if (!outputPriorityQueue.isEmpty()) { PriorityQueueElement checkElement = outputPriorityQueue.peek(); if (proceed && !searchCallback.proceed(checkElement.getTuple())) { if (includeMemComponent) { PriorityQueueElement inMemElement = null; boolean inMemElementFound = false; // scan the PQ for the in-memory component's element Iterator<PriorityQueueElement> it = outputPriorityQueue.iterator(); while (it.hasNext()) { inMemElement = it.next(); if (inMemElement.getCursorIndex() == 0) { inMemElementFound = true; it.remove(); break; } } if (inMemElementFound) { // copy the in-mem tuple if (tupleBuilder == null) { tupleBuilder = new ArrayTupleBuilder(cmp.getKeyFieldCount()); } TupleUtils.copyTuple(tupleBuilder, inMemElement.getTuple(), cmp.getKeyFieldCount()); copyTuple.reset(tupleBuilder.getFieldEndOffsets(), tupleBuilder.getByteArray()); // unlatch/unpin rangeCursors[0].reset(); // reconcile if (checkElement.getCursorIndex() == 0) { searchCallback.reconcile(copyTuple); } else { searchCallback.reconcile(checkElement.getTuple()); } // retraverse reusablePred.setLowKey(copyTuple, true); memBTreeAccessor.search(rangeCursors[0], reusablePred); pushIntoPriorityQueue(inMemElement); if (cmp.compare(copyTuple, inMemElement.getTuple()) != 0) { searchCallback.cancel(copyTuple); continue; } } else { // the in-memory cursor is exhausted searchCallback.reconcile(checkElement.getTuple()); } } else { searchCallback.reconcile(checkElement.getTuple()); } } // If there is no previous tuple or the previous tuple can be ignored if (outputElement == null) { if (isDeleted(checkElement)) { // If the key has been deleted then pop it and set needPush to true. // We cannot push immediately because the tuple may be // modified if hasNext() is called outputElement = outputPriorityQueue.poll(); searchCallback.cancel(checkElement.getTuple()); needPush = true; proceed = false; } else { break; } } else { // Compare the previous tuple and the head tuple in the PQ if (compare(cmp, outputElement.getTuple(), checkElement.getTuple()) == 0) { // If the previous tuple and the head tuple are // identical // then pop the head tuple and push the next tuple from // the tree of head tuple // the head element of PQ is useless now PriorityQueueElement e = outputPriorityQueue.poll(); pushIntoPriorityQueue(e); } else { // If the previous tuple and the head tuple are different // the info of previous tuple is useless if (needPush == true) { pushIntoPriorityQueue(outputElement); needPush = false; } proceed = true; outputElement = null; } } } else { // the priority queue is empty and needPush pushIntoPriorityQueue(outputElement); needPush = false; outputElement = null; proceed = true; } } }
protected void setCursor() { cursor = indexAccessor.createSearchCursor(false); }