/* * Licensed to Crate under one or more contributor license agreements. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. Crate 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. * * However, if you have executed another commercial license agreement * with Crate these terms will supersede the license and you may use the * software solely pursuant to the terms of the relevant commercial * agreement. */ package io.crate.operation.merge; import com.google.common.collect.PeekingIterator; import com.google.common.collect.UnmodifiableIterator; import java.util.*; import static com.google.common.collect.Iterators.peekingIterator; /** * MergingIterator like it is used in guava Iterators.mergedSort * It has (limited) shared object support. * <p> * And it also has a merge function with which additional backing iterators can be added to enable paging */ class PlainSortedMergeIterator<TKey, TRow> extends UnmodifiableIterator<TRow> implements SortedMergeIterator<TKey, TRow> { private final Queue<NumberedPeekingIterator<TKey, TRow>> queue; private NumberedPeekingIterator<TKey, TRow> lastUsedIter = null; private boolean leastExhausted = false; private TKey exhausted; PlainSortedMergeIterator(final Comparator<? super TRow> itemComparator) { Comparator<PeekingIterator<TRow>> heapComparator = (o1, o2) -> itemComparator.compare(o1.peek(), o2.peek()); queue = new PriorityQueue<>(2, heapComparator); } private void addIterators(Iterable<? extends KeyIterable<TKey, TRow>> iterables) { for (KeyIterable<TKey, TRow> iterable : iterables) { Iterator<TRow> rowIterator = iterable.iterator(); if (rowIterator.hasNext()) { queue.add(new NumberedPeekingIterator<>(iterable.key(), peekingIterator(rowIterator))); } } } @Override public boolean hasNext() { reAddLastIterator(); return !queue.isEmpty(); } private void reAddLastIterator() { if (lastUsedIter != null) { if (lastUsedIter.hasNext()) { queue.add(lastUsedIter); } else { leastExhausted = true; exhausted = lastUsedIter.key; } lastUsedIter = null; } } @Override public TRow next() { if (!hasNext()) { throw new NoSuchElementException("no more rows should exist"); } lastUsedIter = queue.remove(); return lastUsedIter.next(); } @Override public void merge(Iterable<? extends KeyIterable<TKey, TRow>> numberedIterables) { if (lastUsedIter != null && lastUsedIter.hasNext()) { queue.add(lastUsedIter); lastUsedIter = null; } addIterators(numberedIterables); leastExhausted = false; } public boolean isLeastExhausted() { return leastExhausted; } @Override public TKey exhaustedIterable() { return exhausted; } @Override public Iterable<TRow> repeat() { throw new UnsupportedOperationException("cannot repeat with " + getClass().getSimpleName()); } private static class NumberedPeekingIterator<TKey, TRow> implements PeekingIterator<TRow> { private final TKey key; private final PeekingIterator<TRow> peekingIterator; NumberedPeekingIterator(TKey key, PeekingIterator<TRow> peekingIterator) { this.key = key; this.peekingIterator = peekingIterator; } @Override public TRow peek() { return peekingIterator.peek(); } @Override public TRow next() { return peekingIterator.next(); } @Override public void remove() { peekingIterator.remove(); } @Override public boolean hasNext() { return peekingIterator.hasNext(); } } }