You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2020/08/30 15:54:45 UTC

[tinkerpop] 01/02: [TINKERPOP-2396] add TraverserSet supplier option for AbstractStep and ExpandableStepIterator

This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2396
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 0ac129373082fd2db316db1691ef9063bbe985a3
Author: Norio Akagi <no...@amazon.com>
AuthorDate: Tue Jul 28 01:53:39 2020 -0700

    [TINKERPOP-2396] add TraverserSet supplier option for AbstractStep and ExpandableStepIterator
---
 .../traversal/step/filter/RangeGlobalStep.java     |  2 +-
 .../traversal/step/filter/SampleGlobalStep.java    |  2 +-
 .../traversal/step/filter/TailGlobalStep.java      |  2 +-
 .../process/traversal/step/map/MatchStep.java      |  7 +--
 .../traversal/step/map/NoOpBarrierStep.java        |  7 +--
 .../traversal/step/sideEffect/AggregateStep.java   |  7 +--
 .../process/traversal/step/util/AbstractStep.java  | 27 ++++++++++-
 .../traversal/step/util/CollectingBarrierStep.java |  7 +--
 .../step/util/ExpandableStepIterator.java          | 18 ++++++-
 .../util/function/TraverserSetSupplier.java        | 44 +++++++++++++++++
 .../util/function/TraverserSetSupplierTest.java    | 55 ++++++++++++++++++++++
 11 files changed, 161 insertions(+), 17 deletions(-)

diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
index b99915c..1343aab 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/RangeGlobalStep.java
@@ -167,7 +167,7 @@ public final class RangeGlobalStep<S> extends FilterStep<S> implements Ranging,
     public TraverserSet<S> nextBarrier() throws NoSuchElementException {
         if(!this.starts.hasNext())
             throw FastNoSuchElementException.instance();
-        final TraverserSet<S> barrier = new TraverserSet<>();
+        final TraverserSet<S> barrier = this.traverserSetSupplier.get();
         while (this.starts.hasNext()) {
             barrier.add(this.starts.next());
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
index 5290f97..a4d3458 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/SampleGlobalStep.java
@@ -82,7 +82,7 @@ public final class SampleGlobalStep<S> extends CollectingBarrierStep<S> implemen
             totalWeight = totalWeight + (((ProjectedTraverser<S, Number>) s).getProjections().get(0).doubleValue() * s.bulk());
         }
         ///////
-        final TraverserSet<S> sampledSet = new TraverserSet<>();
+        final TraverserSet<S> sampledSet = this.traverserSetSupplier.get();
         int runningAmountToSample = 0;
         while (runningAmountToSample < this.amountToSample) {
             boolean reSample = false;
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
index 2e31b1f..b8b8037 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/TailGlobalStep.java
@@ -146,7 +146,7 @@ public final class TailGlobalStep<S> extends AbstractStep<S, S> implements Bypas
     public TraverserSet<S> nextBarrier() throws NoSuchElementException {
         if (!this.starts.hasNext())
             throw FastNoSuchElementException.instance();
-        final TraverserSet<S> barrier = new TraverserSet<>();
+        final TraverserSet<S> barrier = this.traverserSetSupplier.get();
         while (this.starts.hasNext()) {
             barrier.add(this.starts.next());
         }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
index 9ad7132..f43ae4b 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MatchStep.java
@@ -70,7 +70,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
 
     public enum TraversalType {WHERE_PREDICATE, WHERE_TRAVERSAL, MATCH_TRAVERSAL}
 
-    private List<Traversal.Admin<Object, Object>> matchTraversals = new ArrayList<>();
+    private List<Traversal.Admin<Object, Object>> matchTraversals;
     private boolean first = true;
     private Set<String> matchStartLabels = new HashSet<>();
     private Set<String> matchEndLabels = new HashSet<>();
@@ -91,6 +91,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
         this.matchTraversals = (List) Stream.of(matchTraversals).map(Traversal::asAdmin).collect(Collectors.toList());
         this.matchTraversals.forEach(this::configureStartAndEndSteps); // recursively convert to MatchStep, MatchStartStep, or MatchEndStep
         this.matchTraversals.forEach(this::integrateChild);
+        this.standardAlgorithmBarrier = this.traverserSetSupplier.get();
         this.computedStartLabel = Helper.computeStartLabel(this.matchTraversals);
     }
 
@@ -246,7 +247,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
             clone.matchTraversals.add(traversal.clone());
         }
         if (this.dedups != null) clone.dedups = new HashSet<>();
-        clone.standardAlgorithmBarrier = new TraverserSet();
+        clone.standardAlgorithmBarrier = this.traverserSetSupplier.get();
         return clone;
     }
 
@@ -353,7 +354,7 @@ public final class MatchStep<S, E> extends ComputerAwareStep<S, Map<String, E>>
         return this.referencedLabelsMap;
     }
 
-    private TraverserSet standardAlgorithmBarrier = new TraverserSet();
+    private TraverserSet standardAlgorithmBarrier;
 
     @Override
     protected Iterator<Traverser.Admin<Map<String, E>>> standardAlgorithm() throws NoSuchElementException {
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java
index bedf078..14421c9 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java
@@ -38,7 +38,7 @@ import java.util.Set;
 public final class NoOpBarrierStep<S> extends AbstractStep<S, S> implements LocalBarrier<S> {
 
     private int maxBarrierSize;
-    private TraverserSet<S> barrier = new TraverserSet<>();
+    private TraverserSet<S> barrier;
 
     public NoOpBarrierStep(final Traversal.Admin traversal) {
         this(traversal, Integer.MAX_VALUE);
@@ -47,6 +47,7 @@ public final class NoOpBarrierStep<S> extends AbstractStep<S, S> implements Loca
     public NoOpBarrierStep(final Traversal.Admin traversal, final int maxBarrierSize) {
         super(traversal);
         this.maxBarrierSize = maxBarrierSize;
+        this.barrier = this.traverserSetSupplier.get();
     }
 
     @Override
@@ -83,7 +84,7 @@ public final class NoOpBarrierStep<S> extends AbstractStep<S, S> implements Loca
             throw FastNoSuchElementException.instance();
         else {
             final TraverserSet<S> temp = this.barrier;
-            this.barrier = new TraverserSet<>();
+            this.barrier = this.traverserSetSupplier.get();
             return temp;
         }
     }
@@ -96,7 +97,7 @@ public final class NoOpBarrierStep<S> extends AbstractStep<S, S> implements Loca
     @Override
     public NoOpBarrierStep<S> clone() {
         final NoOpBarrierStep<S> clone = (NoOpBarrierStep<S>) super.clone();
-        clone.barrier = new TraverserSet<>();
+        clone.barrier = this.traverserSetSupplier.get();
         return clone;
     }
 
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java
index 8d6d960..c7b7a40 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java
@@ -48,11 +48,12 @@ public final class AggregateStep<S> extends AbstractStep<S, S> implements SideEf
 
     private Traversal.Admin<S, Object> aggregateTraversal = null;
     private String sideEffectKey;
-    private TraverserSet<S> barrier = new TraverserSet<>();
+    private TraverserSet<S> barrier;
 
     public AggregateStep(final Traversal.Admin traversal, final String sideEffectKey) {
         super(traversal);
         this.sideEffectKey = sideEffectKey;
+        this.barrier = this.traverserSetSupplier.get();
         this.getTraversal().getSideEffects().registerIfAbsent(this.sideEffectKey, (Supplier) BulkSetSupplier.instance(), Operator.addAll);
     }
 
@@ -84,7 +85,7 @@ public final class AggregateStep<S> extends AbstractStep<S, S> implements SideEf
     @Override
     public AggregateStep<S> clone() {
         final AggregateStep<S> clone = (AggregateStep<S>) super.clone();
-        clone.barrier = new TraverserSet<>();
+        clone.barrier = this.traverserSetSupplier.get();
         if (null != this.aggregateTraversal)
             clone.aggregateTraversal = this.aggregateTraversal.clone();
         return clone;
@@ -143,7 +144,7 @@ public final class AggregateStep<S> extends AbstractStep<S, S> implements SideEf
             throw FastNoSuchElementException.instance();
         else {
             final TraverserSet<S> temp = this.barrier;
-            this.barrier = new TraverserSet<>();
+            this.barrier = this.traverserSetSupplier.get();
             return temp;
         }
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
index e2757e2..28d0b88 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/AbstractStep.java
@@ -21,9 +21,11 @@ package org.apache.tinkerpop.gremlin.process.traversal.step.util;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
 import org.apache.tinkerpop.gremlin.process.traversal.util.EmptyTraversal;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalInterruptedException;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
+import org.apache.tinkerpop.gremlin.util.function.TraverserSetSupplier;
 
 import java.util.Collections;
 import java.util.Iterator;
@@ -43,13 +45,21 @@ public abstract class AbstractStep<S, E> implements Step<S, E> {
     protected ExpandableStepIterator<S> starts;
     protected Traverser.Admin<E> nextEnd = null;
     protected boolean traverserStepIdAndLabelsSetByChild = false;
+    protected TraverserSetSupplier<S> traverserSetSupplier;
 
     protected Step<?, S> previousStep = EmptyStep.instance();
     protected Step<E, ?> nextStep = EmptyStep.instance();
 
     public AbstractStep(final Traversal.Admin traversal) {
         this.traversal = traversal;
-        this.starts = new ExpandableStepIterator<>(this);
+        this.traverserSetSupplier = TraverserSetSupplier.instance();
+        this.starts = new ExpandableStepIterator<>(this, this.traverserSetSupplier.get());
+    }
+
+    public AbstractStep(final Traversal.Admin traversal, final TraverserSetSupplier<S> traverserSetSupplier) {
+        this.traversal = traversal;
+        this.traverserSetSupplier = traverserSetSupplier;
+        this.starts = new ExpandableStepIterator<>(this, this.traverserSetSupplier.get());
     }
 
     @Override
@@ -201,6 +211,21 @@ public abstract class AbstractStep<S, E> implements Step<S, E> {
         return result;
     }
 
+    public ExpandableStepIterator<S> getStarts() {
+        return this.starts;
+    }
+
+    /**
+     * Sets a new traverserSupplier so that providers can use their own implementation of TraverserSet instead of the default {@link TraverserSet}.
+     * Note that {@link AbstractStep#starts} also holds TraverserSet but this method doesn't automatically replace the traverserSet for it.
+     * Providers may use {@link ExpandableStepIterator#setTraverserSet(TraverserSet)} independently to replace its TraverserSet.
+     *
+     * @param traverserSetSupplier a new traverserSetSupplier used to spawn a new TraverserSet when necessary in the step.
+     */
+    public void setTraverserSetSupplier(final TraverserSetSupplier<S> traverserSetSupplier) {
+        this.traverserSetSupplier = traverserSetSupplier;
+    }
+
     private final Traverser.Admin<E> prepareTraversalForNextStep(final Traverser.Admin<E> traverser) {
         if (!this.traverserStepIdAndLabelsSetByChild) {
             traverser.setStepId(this.nextStep.getId());
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/CollectingBarrierStep.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/CollectingBarrierStep.java
index 8409c9f..ebc3975 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/CollectingBarrierStep.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/CollectingBarrierStep.java
@@ -41,7 +41,7 @@ import java.util.function.BinaryOperator;
  */
 public abstract class CollectingBarrierStep<S> extends AbstractStep<S, S> implements Barrier<TraverserSet<S>> {
 
-    protected TraverserSet<S> traverserSet = new TraverserSet<>();
+    protected TraverserSet<S> traverserSet;
     private int maxBarrierSize;
     private boolean barrierConsumed = false;
 
@@ -51,6 +51,7 @@ public abstract class CollectingBarrierStep<S> extends AbstractStep<S, S> implem
 
     public CollectingBarrierStep(final Traversal.Admin traversal, final int maxBarrierSize) {
         super(traversal);
+        this.traverserSet = this.traverserSetSupplier.get();
         this.maxBarrierSize = maxBarrierSize;
     }
 
@@ -86,7 +87,7 @@ public abstract class CollectingBarrierStep<S> extends AbstractStep<S, S> implem
         if (this.traverserSet.isEmpty())
             throw FastNoSuchElementException.instance();
         else {
-            final TraverserSet<S> temp = new TraverserSet<>();
+            final TraverserSet<S> temp = this.traverserSetSupplier.get();
             IteratorUtils.removeOnNext(this.traverserSet.iterator()).forEachRemaining(t -> {
                 DetachedFactory.detach(t, true); // this should be dynamic
                 temp.add(t);
@@ -119,7 +120,7 @@ public abstract class CollectingBarrierStep<S> extends AbstractStep<S, S> implem
     @Override
     public CollectingBarrierStep<S> clone() {
         final CollectingBarrierStep<S> clone = (CollectingBarrierStep<S>) super.clone();
-        clone.traverserSet = new TraverserSet<>();
+        clone.traverserSet = this.traverserSetSupplier.get();
         clone.barrierConsumed = false;
         return clone;
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ExpandableStepIterator.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ExpandableStepIterator.java
index 30558e8..d84e430 100644
--- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ExpandableStepIterator.java
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ExpandableStepIterator.java
@@ -30,11 +30,17 @@ import java.util.Iterator;
  */
 public final class ExpandableStepIterator<S> implements Iterator<Traverser.Admin<S>>, Serializable {
 
-    private final TraverserSet<S> traverserSet = new TraverserSet<>();
+    private TraverserSet<S> traverserSet;
     private final Step<S, ?> hostStep;
 
     public ExpandableStepIterator(final Step<S, ?> hostStep) {
         this.hostStep = hostStep;
+        this.traverserSet = new TraverserSet<>();
+    }
+
+    public ExpandableStepIterator(final Step<S, ?> hostStep, final TraverserSet<S> traverserSet) {
+        this.hostStep = hostStep;
+        this.traverserSet = traverserSet;
     }
 
     @Override
@@ -53,6 +59,16 @@ public final class ExpandableStepIterator<S> implements Iterator<Traverser.Admin
         return this.traverserSet.remove();
     }
 
+    /**
+     * Replaces the traverserSet. Useful when providers want to use their own implementation of TraverserSet instead of default {@link TraverserSet}.
+     * Note that if the existing traverserSet has elements, they are discarded.
+     *
+     * @param traverserSet a new TraverserSet used to manage a set of traversers.
+     */
+    public void setTraverserSet(final TraverserSet<S> traverserSet) {
+        this.traverserSet = traverserSet;
+    }
+
     public void add(final Iterator<Traverser.Admin<S>> iterator) {
         iterator.forEachRemaining(this.traverserSet::add);
     }
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplier.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplier.java
new file mode 100644
index 0000000..a217d33
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplier.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+package org.apache.tinkerpop.gremlin.util.function;
+
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+
+import java.io.Serializable;
+import java.util.function.Supplier;
+
+/**
+ * @author Norio Akagi
+ */
+public final class TraverserSetSupplier<S> implements Supplier<TraverserSet<S>>, Serializable {
+
+    private static final TraverserSetSupplier INSTANCE = new TraverserSetSupplier();
+
+    private TraverserSetSupplier() {
+    }
+
+    @Override
+    public TraverserSet<S> get() {
+        return new TraverserSet<>();
+    }
+
+    public static <S> TraverserSetSupplier<S> instance() {
+        return INSTANCE;
+    }
+}
diff --git a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplierTest.java b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplierTest.java
new file mode 100644
index 0000000..d6b057b
--- /dev/null
+++ b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/function/TraverserSetSupplierTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+package org.apache.tinkerpop.gremlin.util.function;
+
+import org.apache.tinkerpop.gremlin.process.traversal.traverser.util.TraverserSet;
+import org.junit.Test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasSize;
+
+/**
+ * @author Norio Akagi
+ */
+public class TraverserSetSupplierTest {
+    @Test
+    public void shouldSupplyTraverserSet() {
+        assertThat(TraverserSetSupplier.instance().get(), hasSize(0));
+    }
+
+    @Test
+    public void shouldSupplyTraverserSetInstance() {
+        assertThat(TraverserSetSupplier.instance().get(), hasSize(0));
+        assertThat(TraverserSetSupplier.instance().get(), instanceOf(TraverserSet.class));
+    }
+
+    @Test
+    public void shouldSupplyNewTraverserSetOnEachInvocation() {
+        final TraverserSet<Object> ts1 = TraverserSetSupplier.instance().get();
+        final TraverserSet<Object> ts2 = TraverserSetSupplier.instance().get();
+        final TraverserSet<Object> ts3 = TraverserSetSupplier.instance().get();
+
+        assertThat(ts1, not(sameInstance(ts2)));
+        assertThat(ts1, not(sameInstance(ts3)));
+        assertThat(ts2, not(sameInstance(ts3)));
+    }
+}