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

colegreer pushed a commit to branch GValueManager3.8-wip
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git


The following commit(s) were added to refs/heads/GValueManager3.8-wip by this 
push:
     new 4442e2e3b7 WIP Start pinning GValues instead of removal
4442e2e3b7 is described below

commit 4442e2e3b7a391530bd1154582ccc32065ef7e45
Author: Cole-Greer <[email protected]>
AuthorDate: Mon Jun 16 19:37:52 2025 -0700

    WIP Start pinning GValues instead of removal
---
 .../strategy/decoration/VertexProgramStrategy.java |  3 +
 .../gremlin/process/traversal/GValueManager.java   | 86 ++++++++++++++++++++--
 .../strategy/optimization/CountStrategy.java       |  2 +-
 .../strategy/optimization/EarlyLimitStrategy.java  |  5 ++
 .../optimization/InlineFilterStrategy.java         |  5 +-
 .../strategy/optimization/OrderLimitStrategy.java  |  4 +-
 .../optimization/PathProcessorStrategy.java        |  4 +
 .../optimization/RepeatUnrollStrategy.java         |  2 +-
 .../traversal/strategy/GValueManagerVerifier.java  | 12 +++
 .../strategy/optimization/CountStrategyTest.java   |  4 +-
 .../optimization/OrderLimitStrategyTest.java       |  2 +-
 11 files changed, 114 insertions(+), 15 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
index d28f6047c8..0dbbcee2a7 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/computer/traversal/strategy/decoration/VertexProgramStrategy.java
@@ -70,6 +70,9 @@ public final class VertexProgramStrategy extends 
AbstractTraversalStrategy<Trave
 
     @Override
     public void apply(final Traversal.Admin<?, ?> traversal) {
+        // Don't track GValues in OLAP
+        traversal.getGValueManager().reset();
+
         // VertexPrograms can only execute at the root level of a Traversal 
and should not be applied locally prior to RemoteStrategy
         if (!(traversal.isRoot())
                 || traversal instanceof AbstractLambdaTraversal
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
index d4781b6220..d383a5884c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/GValueManager.java
@@ -38,6 +38,7 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Map;
@@ -54,7 +55,8 @@ import java.util.stream.Collectors;
 public final class GValueManager implements Serializable, Cloneable {
 
     private boolean locked = false;
-    private final Map<String, GValue> gValueRegistry = new IdentityHashMap();
+    private final Map<String, GValue> gValueRegistry = new HashMap<>();
+    private final Map<String, GValue> pinnedGValues = new HashMap<>();
     private final Map<Step, StepContract> stepRegistry = new IdentityHashMap();
 
     public GValueManager() {
@@ -122,10 +124,10 @@ public final class GValueManager implements Serializable, 
Cloneable {
      * Copy the registry state from one step to another.
      */
     public <S, E> void copyRegistryState(final Step<S,E> sourceStep, final 
Step<S,E> targetStep) {
-        if (this.locked) {
-            throw Traversal.Exceptions.traversalIsLocked();
-        }
         if (stepRegistry.containsKey(sourceStep)) {
+            if (this.locked) {
+                throw Traversal.Exceptions.traversalIsLocked();
+            }
             // todo: oh boy - should has stuff even be handled this way?
             // todo: is it ok that the StepContract can be tied to two 
different steps? like, can happen with Traversal.clone() where you gotta copy
 
@@ -194,6 +196,22 @@ public final class GValueManager implements Serializable, 
Cloneable {
         }
     }
 
+    /**
+     * Gets the set of variable names used in this traversal which have not 
been pinned to specific values. Note that
+     * this set won't be consistent until {@link #lock()} is called first. 
Calls to this method prior to locking will
+     * force iteration through traversal steps to real-time gather then 
variable names.
+     */
+    public Set<String> getUnpinnedVariableNames() {
+        Set<String> variableNames = new HashSet<>();
+        if (locked) {
+            variableNames.addAll(gValueRegistry.keySet());
+        } else {
+            
variableNames.addAll(getGValues().stream().map(GValue::getName).collect(Collectors.toSet()));
+        }
+        variableNames.removeAll(pinnedGValues.keySet());
+        return Collections.unmodifiableSet(variableNames);
+    }
+
     /**
      * Gets the set of {@link GValue} objects used in this traversal. Note 
that this set won't be consistent until
      * {@link #lock()} is called first. Calls to this method prior to locking 
will force iteration through traversal
@@ -234,6 +252,13 @@ public final class GValueManager implements Serializable, 
Cloneable {
         return !getVariableNames().isEmpty();
     }
 
+    /**
+     * Determines whether the manager has unpinned GValues.
+     */
+    public boolean hasUnpinnedVariables() {
+        return !getUnpinnedVariableNames().isEmpty();
+    }
+
     /**
      * Delete all data.
      */
@@ -254,13 +279,48 @@ public final class GValueManager implements Serializable, 
Cloneable {
         if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
         final StepContract removedContract = stepRegistry.remove(step);
 
-        if (removedContract != null) {
-            removeGValues(extractGValues(removedContract));
-        }
+        //TODO:: should we automatically pin GValues for removed steps?
 
         return removedContract;
     }
 
+    /**
+     * Pins the GValues associated with the step to their current values. This 
should be called anytime an optimization
+     * alters the Traversal based on the current value of a GValue. This 
indicates that the resulting traversal is only
+     * valid for this specific value of a GValue, and is not generalizable to 
any parameter value.
+     *
+     * @param step the {@link Step} in which to pin associated GValues
+     * @return the pinned contract or null if there was no mapping for the key
+     * @throws IllegalStateException if the manager is locked
+     */
+    public StepContract pinGValues(final Step step) {
+        if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
+        final StepContract contract = stepRegistry.get(step);
+
+        if (contract != null) {
+            pinGValues(extractGValues(contract));
+        }
+        return contract;
+    }
+
+    /**
+     * Pins any GValue with the provided name. This should be called anytime 
an optimization
+     * alters the Traversal based on the current value of a GValue. This 
indicates that the resulting traversal is only
+     * valid for this specific value of a GValue, and is not generalizable to 
any parameter value.
+     *
+     * @param name the name of the GValue to be pinned
+     * @return true if name matches a registered GValue which was successfully 
pinned, false otherwise.
+     * @throws IllegalStateException if the manager is locked
+     */
+    public boolean pinVariable(final String name) {
+        if (this.locked) throw Traversal.Exceptions.traversalIsLocked();
+        if (!gValueRegistry.containsKey(name)) {
+            return false;
+        }
+        pinnedGValues.put(name, gValueRegistry.get(name));
+        return true;
+    }
+
     @Override
     public GValueManager clone() {
         return new GValueManager(gValueRegistry, stepRegistry);
@@ -476,6 +536,18 @@ public final class GValueManager implements Serializable, 
Cloneable {
         }
     }
 
+    /**
+     * Pin a collection of {@link GValue} instances from the internal 
registry. Iteratively processes each
+     * {@link GValue} to pin it to its current value.
+     */
+    private void pinGValues(final Collection<GValue<?>> gValues) {
+        for (GValue<?> gValue : gValues) {
+            if (gValue.isVariable()) {
+                pinnedGValues.put(gValue.getName(), gValue);
+            }
+        }
+    }
+
     /**
      * Recursively collects mappings of {@link Step} to associated {@link 
GValue} instances from the given traversal
      * and its child traversals. If a {@link Step} is parameterized, its 
associated {@link GValue}s are extracted
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategy.java
index 50bd0fdbdd..c12260f41e 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategy.java
@@ -154,7 +154,7 @@ public final class CountStrategy extends 
AbstractTraversalStrategy<TraversalStra
                     // this, we nullify the possibility of using that GValue 
for downstream optimizations as it
                     // would tie the dynamic GValue to a statically 
constructed literal (i.e. the highRange) that
                     // only applies for this current strategy application.
-                    traversal.getGValueManager().remove(isStep);
+                    traversal.getGValueManager().pinGValues(isStep);
 
                     if (useNotStep || dismissCountIs) {
                         TraversalHelper.removeStep(isStep, traversal); // 
IsStep
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategy.java
index 9dee35a509..0437864a9f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/EarlyLimitStrategy.java
@@ -132,6 +132,11 @@ public final class EarlyLimitStrategy
             }
             remove = merge;
 
+            // optimization is dependent on the high and low values from both 
`step` and `other`. Both must have their
+            // GValues pinned as a result.
+            traversal.getGValueManager().pinGValues(step);
+            traversal.getGValueManager().pinGValues(other);
+
             // a step is being permanently removed - remove from manager
             final Step stepToRemove = merge ? insertAfter : step;
             traversal.getGValueManager().remove(stepToRemove);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
index c9d0edaccf..fd26fc8dca 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/InlineFilterStrategy.java
@@ -257,7 +257,10 @@ public final class InlineFilterStrategy extends 
AbstractTraversalStrategy<Traver
         if (process) {
             final HasStep hasStep = new HasStep<>(traversal, new 
HasContainer(key, predicate));
             TraversalHelper.replaceStep(step, hasStep, traversal);
-            stepsToRemoveFromManager.forEach(s -> 
traversal.getGValueManager().remove(s));
+            stepsToRemoveFromManager.forEach(s -> {
+                traversal.getGValueManager().pinGValues(s);
+                traversal.getGValueManager().remove(s);
+            });
             traversal.getGValueManager().register(hasStep, hasStep);
             TraversalHelper.copyLabels(step, hasStep, false);
             for (final String label : labels) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategy.java
index 31a64ac8d0..28cd007159 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategy.java
@@ -99,8 +99,8 @@ public final class OrderLimitStrategy extends 
AbstractTraversalStrategy<Traversa
             if (null != range) {
                 order.setLimit(range.getHighRange());
 
-                // remove GValueManager state because the step contract value 
has been used to set up order()
-                traversal.getGValueManager().remove(range);
+                // pin GValues because the step contract value has been used 
to set up order()
+                traversal.getGValueManager().pinGValues(range);
             }
         }
     }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategy.java
index 766a087df1..4c76998a9b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/PathProcessorStrategy.java
@@ -168,7 +168,9 @@ public final class PathProcessorStrategy extends 
AbstractTraversalStrategy<Trave
                     final List<Step> byChildSteps = 
TraversalHelper.getStepsOfAssignableClassRecursively(Step.class, byTraversal);
                     for (int ix = 0; ix < byChildSteps.size(); ix++) {
                         manager.copyRegistryState(byChildSteps.get(ix), 
clonedByTraversal.getSteps().get(ix));
+                        manager.pinGValues(byChildSteps.get(ix));
                         manager.remove(byChildSteps.get(ix));
+                        
clonedByTraversal.getGValueManager().pinGValues(byChildSteps.get(ix));
                         
clonedByTraversal.getGValueManager().remove(byChildSteps.get(ix));
                     }
 
@@ -198,7 +200,9 @@ public final class PathProcessorStrategy extends 
AbstractTraversalStrategy<Trave
                         manager.copyRegistryState(localChildSteps.get(ix), 
localChildClone.getSteps().get(ix));
 
                         // todo: look at cases where we clone() traversal more 
carefully. so much to think about in these cases
+                        manager.pinGValues(localChildSteps.get(ix));
                         manager.remove(localChildSteps.get(ix));
+                        
localChildClone.getGValueManager().pinGValues(localChildSteps.get(ix));
                         
localChildClone.getGValueManager().remove(localChildSteps.get(ix));
                     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
index 0a4d0c285c..46a013c823 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/RepeatUnrollStrategy.java
@@ -100,7 +100,7 @@ public final class RepeatUnrollStrategy extends 
AbstractTraversalStrategy<Traver
                             manager.copyRegistryState(repeatSteps.get(ix), 
repeatClone.getSteps().get(ix));
 
                             // todo: PathProcessorStrategy showed some state 
can hang about in the manager - really need to investigate clone more
-                            
repeatClone.getGValueManager().remove(repeatSteps.get(ix));
+                            
repeatClone.getGValueManager().remove(repeatSteps.get(ix)); // don't need to 
pin GValues as RepeatUnroll isn't based on specific GValue Values
                         }
 
                         TraversalHelper.insertTraversal(insertIndex, 
repeatClone, traversal);
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/GValueManagerVerifier.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/GValueManagerVerifier.java
index 45564422e9..8e2dd0a386 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/GValueManagerVerifier.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/GValueManagerVerifier.java
@@ -303,6 +303,18 @@ public class GValueManagerVerifier {
             return self();
         }
 
+        /**
+         * Verifies that and GValues in GValueManager have been pinned to 
indicate that optimizations have been applied
+         * which cannot be generalized for any parameter values. Pinning of 
GValues only applies to variables. There
+         * might yet be unnamed {@link GValue} instances which are unpinned, 
but since we don't bind to those and they
+         * are usually incident to something like {@code V(1, x=2, 3)} where 
one variable implies that all arguments
+         * must be converted to {@link GValue} you can have scenarios where 
there is a mix.
+         */
+        public T allGValuesArePinned() {
+            assertThat(String.format("GValueManager only contain pinned 
GValues but [%s] is unpinned", manager.getUnpinnedVariableNames()), 
manager.hasUnpinnedVariables(), is(false));
+            return self();
+        }
+
         /**
          * Verifies that specific steps have been cleared from GValueManager
          */
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
index cc299bd177..7e10f0bdf5 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/CountStrategyTest.java
@@ -181,7 +181,7 @@ public class CountStrategyTest {
      * instances are being introduced by CountStrategy.
      */
     @RunWith(Parameterized.class)
-    public static class GValueClearedBecauseItWasAccessedToInformTest {
+    public static class GValuePinnedBecauseItWasAccessedToInformTest {
 
         @Parameterized.Parameter(value = 0)
         public Traversal.Admin<?, ?> traversal;
@@ -300,7 +300,7 @@ public class CountStrategyTest {
                     beforeApplying().
                     stepsOfClassAreParameterized(true, IsStep.class).
                     afterApplying().
-                    managerIsEmpty();
+                    allGValuesArePinned();
         }
     }
 
diff --git 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
index f0a975b173..1f5d71ebf2 100644
--- 
a/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
+++ 
b/gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/optimization/OrderLimitStrategyTest.java
@@ -120,7 +120,7 @@ public class OrderLimitStrategyTest {
                     beforeApplying().
                         hasVariables(expectedNames).
                     afterApplying().
-                        managerIsEmpty();
+                        allGValuesArePinned();
         }
     }
 }

Reply via email to