Greatly simplified ImmutablePath and MutablePath.retract() algorithms. Got a 3x 
speedup on a big ol fat match() query I'm benchmarking with. Simplified 
LP_XXXX_Traverser implementations around retract(). Small fix to 
NativeNeo4jCypherCheck -- had an extra ( in an Ignored Test.


Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/a8bcd7dc
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/a8bcd7dc
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/a8bcd7dc

Branch: refs/heads/TINKERPOP-1278
Commit: a8bcd7dc1262b2eea93472a4f8e04d5ffb84fc0a
Parents: b900de2
Author: Marko A. Rodriguez <okramma...@gmail.com>
Authored: Mon Jul 11 13:09:31 2016 -0600
Committer: Marko A. Rodriguez <okramma...@gmail.com>
Committed: Mon Jul 11 13:09:31 2016 -0600

----------------------------------------------------------------------
 .../traversal/step/util/ImmutablePath.java      | 132 +++----------------
 .../traversal/step/util/MutablePath.java        |  22 +---
 .../traverser/B_LP_O_S_SE_SL_Traverser.java     |  46 ++++---
 .../traverser/LP_O_OB_P_S_SE_SL_Traverser.java  |  22 ++--
 .../neo4j/process/NativeNeo4jCypherCheck.java   |   2 +-
 5 files changed, 61 insertions(+), 163 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8bcd7dc/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
index b71c56e..fb3155f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/ImmutablePath.java
@@ -24,7 +24,6 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -78,121 +77,28 @@ public class ImmutablePath implements Path, 
ImmutablePathImpl, Serializable, Clo
 
     @Override
     public Path retract(final Set<String> labels) {
-        if (labels == null || labels.isEmpty()) {
+        if (labels.isEmpty())
             return this;
-        }
 
-        // first see if the labels in the set are even present in this path
-        boolean found = false;
-        for (final Set<String> labelSet : labels()) {
-            if (!Collections.disjoint(labelSet, labels)) {
-                found = true;
+        // get all the immutable path sections
+        final List<ImmutablePath> immutablePaths = new ArrayList<>();
+        ImmutablePath currentPathSection = this;
+        while (true) {
+            immutablePaths.add(0, currentPathSection);
+            if (currentPathSection.previousPath instanceof TailPath)
                 break;
-            }
-        }
-
-        if (!found) {
-            return this;
-        }
-
-        if (this.previousPath instanceof TailPath) {
-            ImmutablePath clone = cloneImmutablePath(this);
-            clone.currentLabels.removeAll(labels);
-            clone.previousPath = TailPath.instance();
-            if (clone.currentLabels.isEmpty()) {
-                // return the previous tail path because this path segment can 
be dropped
-                return clone.previousPath;
-            }
-            return clone;
+            else
+                currentPathSection = (ImmutablePath) 
currentPathSection.previousPath;
         }
-
-        ImmutablePath parent;
-        ImmutablePath child;
-        if (this.previousPath != null) {
-            parent = this;
-            child = (ImmutablePath)this.previousPath;
-        } else {
-            parent = (ImmutablePath)this.previousPath;
-            child = this;
+        // build a new immutable path using the respective path sections that 
are not to be retracted
+        Path newPath = TailPath.instance();
+        for (final ImmutablePath immutablePath : immutablePaths) {
+            final Set<String> temp = new 
LinkedHashSet<>(immutablePath.currentLabels);
+            temp.removeAll(labels);
+            if (!temp.isEmpty())
+                newPath = newPath.extend(immutablePath.currentObject, temp);
         }
-
-        if (!Collections.disjoint(parent.currentLabels, labels)) {
-            ImmutablePath clonedParent = cloneImmutablePath(parent);
-            clonedParent.currentLabels.removeAll(labels);
-            if (clonedParent.currentLabels.isEmpty()) {
-                parent = (ImmutablePath) parent.previousPath;
-            } else {
-                parent = clonedParent;
-            }
-        }
-
-        // store the head and return it at the end of this
-        ImmutablePath head = parent;
-
-        // parents can be a mixture of ImmutablePaths and collapsed
-        // cloned ImmutablePaths that are a result of branching
-        List<Object> parents = new ArrayList<>();
-        parents.add(parent);
-
-        while(true) {
-            if (Collections.disjoint(child.currentLabels, labels)) {
-                parents.add(child);
-                if (child.previousPath instanceof TailPath) {
-                    break;
-                }
-                child = (ImmutablePath)child.previousPath;
-                continue;
-            }
-            // split path
-            // clone child
-            ImmutablePath clone = cloneImmutablePath(child);
-            clone.currentLabels.removeAll(labels);
-            if (clone.currentLabels.isEmpty()) {
-                clone.currentObject = null;
-            }
-
-            // walk back up and build parent clones or reuse
-            // other previously cloned paths
-            boolean headFound = false;
-            if (parents.size() > 0) {
-                boolean first = true;
-                // construct parents up to this point
-                ImmutablePath newPath = 
cloneImmutablePath((ImmutablePath)parents.get(0));
-                // replace the previous
-                ImmutablePath prevPath = newPath;
-                ImmutablePath lastPath = prevPath;
-                if (!headFound) {
-                    head = newPath;
-                }
-                for (int i = 1; i < parents.size(); i++) {
-                    ImmutablePath clonedPrev = 
cloneImmutablePath((ImmutablePath) parents.get(i));
-                    prevPath.previousPath = clonedPrev;
-                    lastPath = clonedPrev;
-                    prevPath = clonedPrev;
-                }
-
-                if (clone.currentLabels.isEmpty()) {
-                    lastPath.previousPath = clone.previousPath;
-                } else {
-                    lastPath.previousPath = clone;
-                }
-
-                parents = new ArrayList<>();
-                parents.add(lastPath);
-
-                if (child.previousPath instanceof TailPath) {
-                    break;
-                }
-
-                child = (ImmutablePath)child.previousPath;
-            }
-        }
-
-        return head;
-    }
-
-    private static ImmutablePath cloneImmutablePath(final ImmutablePath path) {
-        return new ImmutablePath(path.previousPath, path.currentObject, new 
HashSet<>(path.currentLabels));
+        return newPath;
     }
 
     @Override
@@ -315,7 +221,9 @@ public class ImmutablePath implements Path, 
ImmutablePathImpl, Serializable, Clo
 
         @Override
         public Path extend(final Set<String> labels) {
-            if (labels.size() == 0) { return this; }
+            if (labels.size() == 0) {
+                return this;
+            }
             throw new UnsupportedOperationException("A head path can not have 
labels added to it");
         }
 

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8bcd7dc/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java
index fd86e2d..f97879f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/MutablePath.java
@@ -80,7 +80,7 @@ public class MutablePath implements Path, Serializable {
 
     @Override
     public Path extend(final Set<String> labels) {
-        if(labels.size() > 0) {
+        if (labels.size() > 0) {
             this.labels.get(this.labels.size() - 1).addAll(labels);
         }
         return this;
@@ -89,22 +89,10 @@ public class MutablePath implements Path, Serializable {
     @Override
     public Path retract(final Set<String> removeLabels) {
         for (int i = this.labels.size() - 1; i >= 0; i--) {
-            for (final String label : removeLabels) {
-                synchronized (this.labels.get(i)) {
-                    if (this.labels.get(i).contains(label)) {
-                        this.labels.get(i).remove(label);
-                        boolean empty = false;
-                        if (this.labels.get(i).size() == 0) {
-                            this.labels.remove(i);
-                            this.objects.remove(i);
-                            empty = true;
-                        }
-                        // label was found, so break out
-                        if (empty) {
-                            break;
-                        }
-                    }
-                }
+            this.labels.get(i).removeAll(removeLabels);
+            if (this.labels.get(i).isEmpty()) {
+                this.labels.remove(i);
+                this.objects.remove(i);
             }
         }
         return this;

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8bcd7dc/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_S_SE_SL_Traverser.java
index 793ead6..ce70c5c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/B_LP_O_S_SE_SL_Traverser.java
@@ -23,11 +23,9 @@ import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ImmutablePath;
-import org.apache.tinkerpop.gremlin.process.traversal.step.util.MutablePath;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
 
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -89,6 +87,32 @@ public class B_LP_O_S_SE_SL_Traverser<T> extends 
B_O_S_SE_SL_Traverser<T> {
 
     @Override
     public void keepLabels(final Set<String> labels) {
+        final Set<String> retractLabels = new HashSet<>();
+        for (final Set<String> stepLabels : this.path.labels()) {
+            for (final String l : stepLabels) {
+                if (!labels.contains(l))
+                    retractLabels.add(l);
+            }
+        }
+        this.path = this.path.retract(retractLabels);
+    }
+
+    @Override
+    public void dropLabels(final Set<String> labels) {
+        if (!labels.isEmpty())
+            this.path = path.retract(labels);
+    }
+
+    @Override
+    public void dropPath() {
+        this.path = ImmutablePath.make();
+    }
+
+
+
+
+    /*@Override
+    public void keepLabels(final Set<String> labels) {
         if (!labels.isEmpty()) {
             Set<String> retractLabels = new HashSet<>();
             List<Set<String>> existingLabels = this.path.labels();
@@ -108,23 +132,7 @@ public class B_LP_O_S_SE_SL_Traverser<T> extends 
B_O_S_SE_SL_Traverser<T> {
                 this.path = this.path.retract(retractLabels);
             }
         }
-    }
-
-    @Override
-    public void dropLabels(final Set<String> labels) {
-        if(!labels.isEmpty()) {
-            this.path = this.path.retract(labels);
-        }
-    }
-
-    @Override
-    public void dropPath() {
-        if(path instanceof ImmutablePath) {
-            this.path = ImmutablePath.make();
-        } else {
-            this.path = MutablePath.make();
-        }
-    }
+    }*/
 
     @Override
     public int hashCode() {

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8bcd7dc/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_O_OB_P_S_SE_SL_Traverser.java
----------------------------------------------------------------------
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_O_OB_P_S_SE_SL_Traverser.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_O_OB_P_S_SE_SL_Traverser.java
index ee951c1..97b79a4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_O_OB_P_S_SE_SL_Traverser.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/traverser/LP_O_OB_P_S_SE_SL_Traverser.java
@@ -26,7 +26,6 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.util.ImmutablePath;
 import org.apache.tinkerpop.gremlin.structure.util.reference.ReferenceFactory;
 
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 /**
@@ -84,25 +83,20 @@ public class LP_O_OB_P_S_SE_SL_Traverser<T> extends 
O_OB_S_SE_SL_Traverser<T> {
 
     @Override
     public void keepLabels(final Set<String> labels) {
-        if (labels != null) {
-            Set<String> retractLabels = new HashSet<>();
-            List<Set<String>> existingLabels = this.path.labels();
-            for (Set<String> labelSet : existingLabels) {
-                for (String l : labelSet) {
-                    if (labels.isEmpty() || labels.contains(l) == false) {
-                        retractLabels.add(l);
-                    }
-                }
+        final Set<String> retractLabels = new HashSet<>();
+        for (final Set<String> stepLabels : this.path.labels()) {
+            for (final String l : stepLabels) {
+                if (!labels.contains(l))
+                    retractLabels.add(l);
             }
-            this.path = this.path.retract(retractLabels);
         }
+        this.path = this.path.retract(retractLabels);
     }
 
     @Override
     public void dropLabels(final Set<String> labels) {
-        if(!labels.isEmpty()) {
-            this.path = path.retract(new HashSet(labels));
-        }
+        if (!labels.isEmpty())
+            this.path = path.retract(labels);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/a8bcd7dc/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
----------------------------------------------------------------------
diff --git 
a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
 
b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
index a758eea..c98e8f9 100644
--- 
a/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
+++ 
b/neo4j-gremlin/src/test/java/org/apache/tinkerpop/gremlin/neo4j/process/NativeNeo4jCypherCheck.java
@@ -201,7 +201,7 @@ public class NativeNeo4jCypherCheck extends 
AbstractNeo4jGremlinTest {
                 () -> g.V().match(
                         as("a").out("followedBy").as("b"),
                         
as("b").out("followedBy").as("c")).select("a").by("name"),
-                () -> n.cypher("MATCH ((a)-[:followedBy]->(b), 
(b)-[:followedBy]->(c) RETURN a.name")
+                () -> n.cypher("MATCH (a)-[:followedBy]->(b), 
(b)-[:followedBy]->(c) RETURN a.name")
                 ///
                 /*() -> g.V().match(
                         as("a").out("followedBy").as("b"),

Reply via email to