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

colegreer pushed a commit to branch sideEffectBarrier
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 7fdc024bd6790b1855841f39917dc0b520db0218
Author: Cole-Greer <[email protected]>
AuthorDate: Sun Oct 26 21:36:52 2025 -0700

    add docs
---
 docs/src/dev/provider/gremlin-semantics.asciidoc |  3 +-
 docs/src/reference/the-traversal.asciidoc        |  9 +++--
 docs/src/upgrade/release-3.8.x.asciidoc          | 43 ++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/docs/src/dev/provider/gremlin-semantics.asciidoc 
b/docs/src/dev/provider/gremlin-semantics.asciidoc
index 8ac0f17449..a0e6aad47d 100644
--- a/docs/src/dev/provider/gremlin-semantics.asciidoc
+++ b/docs/src/dev/provider/gremlin-semantics.asciidoc
@@ -1549,7 +1549,8 @@ key.
 
 The `groupCount()` step can be used as both a map step and a side-effect step. 
As a map step, it returns a `Map` with
 the counted objects as keys and their counts as values. As a side-effect step, 
it stores the counts in a side-effect and
-passes the traverser to the next step unchanged.
+passes the traverser to the next step unchanged. Note that both the map and 
side-effect forms of this step are barriers
+must fully iterate the traversal before returning any results.
 
 *Exceptions*
 
diff --git a/docs/src/reference/the-traversal.asciidoc 
b/docs/src/reference/the-traversal.asciidoc
index a4a241b927..1f7e2df933 100644
--- a/docs/src/reference/the-traversal.asciidoc
+++ b/docs/src/reference/the-traversal.asciidoc
@@ -5043,20 +5043,19 @@ g.V().has('name','josh').out('created').values('name').
 <1> When the `tree()` is created, vertex 3 and 5 are unique and thus, form 
unique branches in the tree structure.
 <2> When the `tree()` is `by()`-modulated by `label`, then vertex 3 and 5 are 
both "software" and thus are merged to a single node in the tree.
 
-The `tree()` step can also take a side-effect key as an argument. When using 
this form, the `Tree` is constructed
-lazily, such that it becomes possible to assess its contents as each traverser 
passes through.
+The `tree()` step can also take a side-effect key as an argument. When using 
this form, the `Tree` is is built up in a
+side-effect as each traverser passes through. The `Tree` can later be accessed 
by either `select()` or `cap()`.
 
 [gremlin-groovy,modern]
 ----
 g.V().has('name','josh').out('created').values('name').tree('x').select('x')
 ----
 
-You can use `cap()` step to force `tree()` to consume the traversal stream 
eagerly and output results similar to prior
-examples.
+It is possible to force lazy construction of the tree by embedding inside a 
`local()` step.
 
 [gremlin-groovy,modern]
 ----
-g.V().has('name','josh').out('created').values('name').tree('x').cap('x')
+g.V().has('name','josh').out('created').values('name').local(tree('x')).select('x')
 ----
 
 *Additional References*
diff --git a/docs/src/upgrade/release-3.8.x.asciidoc 
b/docs/src/upgrade/release-3.8.x.asciidoc
index 38f366c2f0..ad8c7c3e1e 100644
--- a/docs/src/upgrade/release-3.8.x.asciidoc
+++ b/docs/src/upgrade/release-3.8.x.asciidoc
@@ -637,6 +637,49 @@ g.with_strategies(OptionsStrategy(options=myOptions))
 g.with_strategies(OptionsStrategy(**myOptions))
 ----
 
+==== Add barrier to most SideEffect steps
+
+Prior to 3.8.0, the `group(String)`, `groupCount(String)`, `tree(String)` and 
`subgraph(String)` steps were non-blocking,
+in that they allowed traversers to pass through without fully iterating the 
traversal and fully computing the side
+effect. Consider the following example:
+
+[source, groovy]
+----
+// 3.7.4
+gremlin> g.V().groupCount("x").select("x")
+==>[v[1]:1]
+==>[v[1]:1,v[2]:1]
+==>[v[1]:1,v[2]:1,v[3]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+----
+
+As of 3.8.0, all of these steps now implement `LocalBarrier`, meaning that the 
traversal is fully iterated before any
+results are passed. This guarantees that a traversal will produce the same 
results regardless of it is evaluated in a
+lazy (DFS) or eager (BFS) fashion. Any usages which are reliant on the 
previous "one-at-a-time" accumulation of results
+can still achieve this by embedding the side effect step inside a `local()` 
step.
+
+[source, groovy]
+----
+// 3.8.0
+gremlin> g.V().groupCount("x").select("x")
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+
+gremlin> g.V().local(groupCount("x")).select("x")
+==>[v[1]:1]
+==>[v[1]:1,v[2]:1]
+==>[v[1]:1,v[2]:1,v[3]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1]
+==>[v[1]:1,v[2]:1,v[3]:1,v[4]:1,v[5]:1,v[6]:1]
+----
+
 ==== choose() Semantics
 
 Several enhancements and clarifications have been made to the `choose()` step 
in TinkerPop 3.8.0 to improve its behavior

Reply via email to