Skip to content

Commit

Permalink
Make DFS the default for the RepeatStep
Browse files Browse the repository at this point in the history
  • Loading branch information
krlohnes committed May 20, 2018
1 parent f98b570 commit 64a7a60
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.tinkerpop.gremlin.process.traversal.step.branch;

import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.step.Barrier;
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
Expand All @@ -31,6 +32,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
Expand Down Expand Up @@ -179,16 +181,39 @@ public int hashCode() {
return result;
}

private final LinkedList<Traverser.Admin<S>> stashedStarts = new LinkedList<>();

private Traverser.Admin<S> nextStart(final boolean useDfs) {
if (!useDfs) {
return this.starts.next();
} else {
if (this.starts.hasNext()) {
return this.starts.next();
} else {
return this.stashedStarts.pop();
}
}
}

@Override
protected Iterator<Traverser.Admin<S>> standardAlgorithm() throws NoSuchElementException {
if (null == this.repeatTraversal)
throw new IllegalStateException("The repeat()-traversal was not defined: " + this);

final List<Step> steps = this.repeatTraversal.getSteps();
final Step stepBeforeRepeatEndStep = steps.get(steps.size() - 2);
final boolean useDfs = !(stepBeforeRepeatEndStep instanceof Barrier);
while (true) {
if (this.repeatTraversal.getEndStep().hasNext()) {
return this.repeatTraversal.getEndStep();
} else {
final Traverser.Admin<S> start = this.starts.next();
final Traverser.Admin<S> start = nextStart(useDfs);
if (useDfs) {
final List<Traverser.Admin<S>> localStarts = new ArrayList<>();
while (this.starts.hasNext()) {
localStarts.add(this.starts.next());
}
stashedStarts.addAll(0, localStarts);
}
if (doUntil(start, true)) {
start.resetLoops();
return IteratorUtils.of(start);
Expand Down Expand Up @@ -231,10 +256,12 @@ protected Iterator<Traverser.Admin<S>> computerAlgorithm() throws NoSuchElementE

public static <A, B, C extends Traversal<A, B>> C addRepeatToTraversal(final C traversal, final Traversal.Admin<B, B> repeatTraversal) {
final Step<?, B> step = traversal.asAdmin().getEndStep();
boolean setBfs = false;
if (step instanceof RepeatStep && null == ((RepeatStep) step).repeatTraversal) {
((RepeatStep<B>) step).setRepeatTraversal(repeatTraversal);
} else {
final RepeatStep<B> repeatStep = new RepeatStep<>(traversal.asAdmin());
List<Step> steps = repeatTraversal.getSteps();
repeatStep.setRepeatTraversal(repeatTraversal);
traversal.asAdmin().addStep(repeatStep);
}
Expand Down Expand Up @@ -273,11 +300,40 @@ public RepeatEndStep(final Traversal.Admin traversal) {
super(traversal);
}

final LinkedList<Traverser.Admin<S>> stashedStarts = new LinkedList<>();

private Traverser.Admin<S> nextStart(RepeatStep<S> repeatStep, boolean useDfs) {
if (!useDfs) {
return this.starts.next();
} else {
if (this.starts.hasNext()) {
return this.starts.next();
} else {
return this.stashedStarts.pop();
}
}
}

@Override
public boolean hasNext() {
return super.hasNext() || !this.stashedStarts.isEmpty();
}

@Override
protected Iterator<Traverser.Admin<S>> standardAlgorithm() throws NoSuchElementException {
final RepeatStep<S> repeatStep = (RepeatStep<S>) this.getTraversal().getParent();
final List<Step> steps = repeatStep.repeatTraversal.getSteps();
final Step stepBeforeRepeatEndStep = steps.get(steps.size() - 2);
final boolean useDfs = !(stepBeforeRepeatEndStep instanceof Barrier);
while (true) {
final Traverser.Admin<S> start = this.starts.next();
final Traverser.Admin<S> start = nextStart(repeatStep, useDfs);
if (useDfs) {
final List<Traverser.Admin<S>> localStarts = new ArrayList<>();
while (this.starts.hasNext()) {
localStarts.add(this.starts.next());
}
stashedStarts.addAll(0, localStarts);
}
start.incrLoops(this.getId());
if (repeatStep.doUntil(start, false)) {
start.resetLoops();
Expand Down Expand Up @@ -320,4 +376,4 @@ protected Iterator<Traverser.Admin<S>> computerAlgorithm() throws NoSuchElementE
}
}

}
}
15 changes: 15 additions & 0 deletions gremlin-test/features/branch/Repeat.feature
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,18 @@ Feature: Step - repeat()
| loop |
| loop |
| loop |

Scenario: g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit
Given the modern graph
And the traversal of
"""
g.V().has("name", "marko").repeat(__.outE().order().by("weight", Order.decr).inV()).emit()
"""
When iterated to list
Then the result should be ordered
| result |
| josh |
| ripple |
| lop |
| vadas |
| lop |
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.loops;
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.out;
import static org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.outE;
import static org.apache.tinkerpop.gremlin.process.traversal.Order.decr;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
Expand Down Expand Up @@ -98,6 +99,8 @@ public abstract class RepeatTest extends AbstractGremlinProcessTest {

public abstract Traversal<Vertex, Path> get_g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippleXX_path_byXnameX_byXlabelX();

public abstract Traversal<Vertex, Vertex> get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit();

@Test
@LoadGraphWith(MODERN)
public void g_V_repeatXoutX_timesX2X_emit_path() {
Expand Down Expand Up @@ -310,6 +313,18 @@ public void g_V_hasXname_markoX_repeatXoutE_inV_simplePathX_untilXhasXname_rippl
assertEquals("ripple", path.get(4));
}

@Test
@LoadGraphWith(MODERN)
public void g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit() {
final List<Vertex> vertices = get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit().toList();
assertEquals(5, vertices.size());
assertEquals("josh", vertices.get(0).values("name").next());
assertEquals("ripple", vertices.get(1).values("name").next());
assertEquals("lop", vertices.get(2).values("name").next());
assertEquals("vadas", vertices.get(3).values("name").next());
assertEquals("lop", vertices.get(4).values("name").next());
}

public static class Traversals extends RepeatTest {

@Override
Expand Down Expand Up @@ -386,5 +401,10 @@ public Traversal<Vertex, Path> get_g_V_hasXname_markoX_repeatXoutE_inV_simplePat
public Traversal<Vertex, Path> get_g_V_hasXloop_name_loopX_repeatXinX_timesX5X_path_by_name() {
return g.V().has("loops","name","loop").repeat(__.in()).times(5).path().by("name");
}

@Override
public Traversal<Vertex, Vertex> get_g_V_hasXname_markoX_repeatXoutE_order_byXweight_decrX_inVX_emit() {
return g.V().has("name", "marko").repeat(__.outE().order().by("weight", decr).inV()).emit();
}
}
}

0 comments on commit 64a7a60

Please sign in to comment.