From 6dd1feabd5aeaaa5dee95983062c7c91c7991c20 Mon Sep 17 00:00:00 2001 From: Mislav Milicevic Date: Mon, 10 Aug 2020 16:29:19 +0200 Subject: [PATCH] Remove order affecting operations under certain conditions Conditions are described in #33 --- ...IntermediateOperationOptimizerFactory.java | 8 ++- .../RemoveOrderAffectingOperations.java | 62 +++++++++++++++++++ .../abstracts/AbstractSingleValueSquash.java | 12 ++++ .../strategy/SortedCriteriaModifier.java | 19 +++++- 4 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/RemoveOrderAffectingOperations.java diff --git a/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/InternalIntermediateOperationOptimizerFactory.java b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/InternalIntermediateOperationOptimizerFactory.java index 76a97295..c1c2d35c 100644 --- a/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/InternalIntermediateOperationOptimizerFactory.java +++ b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/InternalIntermediateOperationOptimizerFactory.java @@ -16,14 +16,15 @@ package com.speedment.jpastreamer.interopoptimizer.standard.internal; +import com.speedment.jpastreamer.interopoptimizer.IntermediateOperationOptimizer; +import com.speedment.jpastreamer.interopoptimizer.IntermediateOperationOptimizerFactory; +import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.RemoveOrderAffectingOperations; import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashDistinct; import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashFilter; import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashLimit; +import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashSkip; import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashSorted; import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationFactory; -import com.speedment.jpastreamer.interopoptimizer.IntermediateOperationOptimizer; -import com.speedment.jpastreamer.interopoptimizer.IntermediateOperationOptimizerFactory; -import com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy.SquashSkip; import com.speedment.jpastreamer.rootfactory.RootFactory; import java.util.ArrayList; @@ -39,6 +40,7 @@ public InternalIntermediateOperationOptimizerFactory() { final IntermediateOperationFactory intermediateOperationFactory = RootFactory .getOrThrow(IntermediateOperationFactory.class, ServiceLoader::load); + intermediateOperationOptimizers.add(new RemoveOrderAffectingOperations()); intermediateOperationOptimizers.add(new SquashSkip(intermediateOperationFactory)); intermediateOperationOptimizers.add(new SquashLimit(intermediateOperationFactory)); intermediateOperationOptimizers.add(new SquashFilter<>(intermediateOperationFactory)); diff --git a/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/RemoveOrderAffectingOperations.java b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/RemoveOrderAffectingOperations.java new file mode 100644 index 00000000..8ec39649 --- /dev/null +++ b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/RemoveOrderAffectingOperations.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2006-2020, Speedment, Inc. All Rights Reserved. + * + * Licensed 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 com.speedment.jpastreamer.interopoptimizer.standard.internal.strategy; + +import static com.speedment.jpastreamer.pipeline.intermediate.Statement.MODIFIES_ORDER; +import static com.speedment.jpastreamer.pipeline.intermediate.Statement.MODIFIES_SORTED; +import static com.speedment.jpastreamer.pipeline.intermediate.Verb.MODIFIES; +import static com.speedment.jpastreamer.pipeline.terminal.OrderPreservation.NOT_REQUIRED; +import static com.speedment.jpastreamer.pipeline.terminal.OrderPreservation.NOT_REQUIRED_IF_PARALLEL; + +import com.speedment.jpastreamer.interopoptimizer.IntermediateOperationOptimizer; +import com.speedment.jpastreamer.pipeline.Pipeline; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperation; +import com.speedment.jpastreamer.pipeline.intermediate.IntermediateOperationType; +import com.speedment.jpastreamer.pipeline.terminal.OrderPreservation; + +import java.util.LinkedList; + +public final class RemoveOrderAffectingOperations implements IntermediateOperationOptimizer { + + @Override + public Pipeline optimize(Pipeline pipeline) { + final OrderPreservation termOpOrderPreservation = pipeline.terminatingOperation().type().orderPreservation(); + + if (pipeline.isUnordered() || termOpOrderPreservation == NOT_REQUIRED || + (pipeline.isParallel() && termOpOrderPreservation == NOT_REQUIRED_IF_PARALLEL)) { + + final LinkedList> intermediateOperations = pipeline.intermediateOperations(); + + for (int i = intermediateOperations.size() - 1; i >= 0; i--) { + final IntermediateOperationType intermediateOperationType = intermediateOperations.get(i).type(); + + final boolean canBeRemoved = intermediateOperationType.statements().stream() + .filter(statement -> statement.verb() == MODIFIES) + .allMatch(statement -> statement == MODIFIES_ORDER || statement == MODIFIES_SORTED); + + if (!canBeRemoved) { + break; + } + + intermediateOperations.remove(i); + } + } + + return pipeline; + } + +} diff --git a/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/squash/abstracts/AbstractSingleValueSquash.java b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/squash/abstracts/AbstractSingleValueSquash.java index e057d200..77f13a14 100644 --- a/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/squash/abstracts/AbstractSingleValueSquash.java +++ b/provider/interopoptimizer-standard/src/main/java/com/speedment/jpastreamer/interopoptimizer/standard/internal/strategy/squash/abstracts/AbstractSingleValueSquash.java @@ -35,12 +35,24 @@ public Pipeline optimize(final Pipeline pipeline) { final IntermediateOperation intermediateOperation = intermediateOperations.get(i); if (intermediateOperation.type() == operationType()) { + if (intermediateOperation.arguments().length == 0) { + if (result != checkValue()) { + final IntermediateOperation newOperation = operationProvider() + .apply(result); + intermediateOperations.add(i + 1, newOperation); + + result = resetValue(); + } + continue; + } + if (valueClass().isAssignableFrom(intermediateOperation.arguments()[0].getClass())) { S value = (S) intermediateOperation.arguments()[0]; result = squash().apply(value, result); intermediateOperations.remove(i); } + continue; } diff --git a/provider/merger-standard/src/main/java/com/speedment/jpastreamer/merger/standard/internal/criteria/strategy/SortedCriteriaModifier.java b/provider/merger-standard/src/main/java/com/speedment/jpastreamer/merger/standard/internal/criteria/strategy/SortedCriteriaModifier.java index 1bd173a0..11b27043 100644 --- a/provider/merger-standard/src/main/java/com/speedment/jpastreamer/merger/standard/internal/criteria/strategy/SortedCriteriaModifier.java +++ b/provider/merger-standard/src/main/java/com/speedment/jpastreamer/merger/standard/internal/criteria/strategy/SortedCriteriaModifier.java @@ -79,7 +79,17 @@ public void modifyCriteria( criteria.getQuery().orderBy(orders); - mergingTracker.markAsMerged(operationType); + /* + * If a Stream::sorted sequence contains a operation without a specified comparator + * we cannot squash that sequence into a single operation. Because of this, we should + * only mark the operation as merged if it's the last one in the sequence. + * */ + operationReference.next().ifPresent(op -> { + if (op.get().type() != SORTED) { + mergingTracker.markAsMerged(operationType); + } + }); + mergingTracker.markForRemoval(operationReference.index()); } else { final EntityType entityType = criteria.getRoot().getModel(); @@ -93,7 +103,12 @@ public void modifyCriteria( criteria.getQuery().orderBy(order); - mergingTracker.markAsMerged(operationType); + operationReference.next().ifPresent(op -> { + if (op.get().type() != SORTED) { + mergingTracker.markAsMerged(operationType); + } + }); + mergingTracker.markForRemoval(operationReference.index()); }); }