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
