/** * diqube: Distributed Query Base. * * Copyright (C) 2015 Bastian Gloeckle * * This file is part of diqube. * * diqube is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.diqube.execution.steps; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import org.diqube.execution.consumers.AbstractThreadedOverwritingRowIdConsumer; import org.diqube.execution.consumers.DoneConsumer; import org.diqube.execution.consumers.GenericConsumer; import org.diqube.execution.consumers.OverwritingRowIdConsumer; import org.diqube.executionenv.ExecutionEnvironment; import org.diqube.executionenv.VersionedExecutionEnvironment; import org.diqube.queries.QueryRegistry; import org.diqube.util.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A noop step which provides the results of a HAVING clause on the query master, if available. * * <p> * Input: 1 {@link OverwritingRowIdConsumer} <br> * Output: {@link OverwritingRowIdConsumer}. * * @author Bastian Gloeckle */ public class HavingResultStep extends AbstractThreadedExecutablePlanStep { private static final Logger logger = LoggerFactory.getLogger(HavingResultStep.class); private AtomicBoolean sourceIsDone = new AtomicBoolean(false); private Pair<ExecutionEnvironment, Long[]> curPair; private Object curPairSync = new Object(); private AbstractThreadedOverwritingRowIdConsumer rowIdConsumer = new AbstractThreadedOverwritingRowIdConsumer(this) { @Override protected void allSourcesAreDone() { sourceIsDone.set(true); } @Override protected void doConsume(ExecutionEnvironment env, Long[] rowIds) { Pair<ExecutionEnvironment, Long[]> p = new Pair<>(env, rowIds); synchronized (curPairSync) { if (curPair == null || !(env instanceof VersionedExecutionEnvironment) || ((curPair.getLeft() instanceof VersionedExecutionEnvironment) && ((VersionedExecutionEnvironment) env) .getVersion() > ((VersionedExecutionEnvironment) curPair.getLeft()).getVersion())) curPair = p; else logger.debug("Ignoring consume pair of {} since we have one of {}", env, curPair.getLeft()); } } }; public HavingResultStep(int stepId, QueryRegistry queryRegistry) { super(stepId, queryRegistry); } @Override protected void execute() { Pair<ExecutionEnvironment, Long[]> activePair; synchronized (curPairSync) { activePair = curPair; } if (activePair != null) { logger.trace("Reporting {} rowIds.", activePair.getRight().length); forEachOutputConsumerOfType(OverwritingRowIdConsumer.class, c -> c.consume(activePair.getLeft(), activePair.getRight())); } if (sourceIsDone.get() && curPair == activePair) { forEachOutputConsumerOfType(GenericConsumer.class, c -> c.sourceIsDone()); doneProcessing(); } } @Override protected void validateOutputConsumer(GenericConsumer consumer) throws IllegalArgumentException { if (!(consumer instanceof DoneConsumer) && !(consumer instanceof OverwritingRowIdConsumer)) throw new IllegalArgumentException("Only OverwritingRowIdConsumer supported!"); } @Override protected List<GenericConsumer> inputConsumers() { return Arrays.asList(rowIdConsumer); } @Override protected String getAdditionalToStringDetails() { return null; } }