This is an automated email from the ASF dual-hosted git repository. kenhuuu pushed a commit to branch 3.8-dev in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 0db826ae685d49d6a8a7c41347d52da57db75e92 Merge: e0a65c729f 8e286c5d97 Author: Ken Hu <[email protected]> AuthorDate: Tue Mar 31 13:42:22 2026 -0700 Merge branch '3.7-dev' into 3.8-dev Note that this moves the session reuse entry from 3.8.1 to 3.7.6 where it belongs. docs/src/dev/provider/index.asciidoc | 10 ++ docs/src/reference/gremlin-applications.asciidoc | 2 +- docs/src/reference/gremlin-variants.asciidoc | 122 ++++++++++++++++++++-- docs/src/upgrade/release-3.7.x.asciidoc | 127 ++++++++++++++++++++++- docs/src/upgrade/release-3.8.1.asciidoc | 122 ---------------------- 5 files changed, 250 insertions(+), 133 deletions(-) diff --cc docs/src/upgrade/release-3.8.1.asciidoc index 2a786bdb74,0000000000..97aff2dab7 mode 100644,000000..100644 --- a/docs/src/upgrade/release-3.8.1.asciidoc +++ b/docs/src/upgrade/release-3.8.1.asciidoc @@@ -1,258 -1,0 +1,136 @@@ +//// +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +//// +== TinkerPop 3.8.1 + +*Release Date: NOT OFFICIALLY RELEASED YET* + +Please see the link:https://github.com/apache/tinkerpop/blob/3.8.1/CHANGELOG.asciidoc#release-3-8-1[changelog] for a +complete list of all the modifications that are part of this release. + +=== Upgrading for Users + +==== Gremlint MCP + +The Gremlin MCP server now exposes Gremlint formatting for Gremlin traversals, which can be a convenient way to make +a long string of Gremlin easier to read directly from an AI assistant. Provide a simple prompt like the following to +an AI coding agent: + +[source,text] +---- +Format this Gremlin query: +``` +g.V().union(limit(3).fold(),tail(3).fold()).local( + unfold().order().by(bothE().count(),desc).limit(1).fold()) +``` +---- + +It will trigger a call to Gremlint within the Gremlin MCP Server to format it with better indentation and spacing. + +==== Gremlint Improvements + +Gremlint's approach to newlines often produced formatting that didn't generally follow the espoused best practices. +Specifically, if Gremlint found that arguments to a step would exceed the line length, it would instantly apply a +newline and then do an indent. This formatting rule made certain Gremlin appear stretched out vertically in many cases. + +The following example demonstrates this stretching. The following bit of Gremlin is manually formatted according to +common norms and best practices: + +[source,groovy] +---- +g.V().as("v"). + repeat(both().simplePath().as("v")).emit(). + filter(project("x","y","z").by(select(first, "v")). + by(select(last, "v")). + by(select(all, "v").count(local)).as("triple"). + coalesce(select("x","y").as("a"). + select("triples").unfold().as("t"). + select("x","y").where(eq("a")). + select("t"), + local(aggregate("triples"))). + select("z").as("length"). + select("triple").select("z").where(eq("length"))). + select(all, "v").unfold(). + groupCount() +---- + +In earlier versions of Gremlint, it would format that query to: + +[source,groovy] +---- +g.V().as("v"). + repeat(both().simplePath().as("v")).emit(). + filter( + project("x", "y", "z"). + by(select(first, "v")). + by(select(last, "v")). + by(select(all, "v").count(local)). + as("triple"). + coalesce( + select("x", "y").as("a"). + select("triples"). + unfold().as("t"). + select("x", "y"). + where(eq("a")). + select("t"), + local(aggregate("triples"))). + select("z").as("length"). + select("triple"). + select("z"). + where(eq("length"))). + select(all, "v"). + unfold(). + groupCount() +---- + +In this version, after the improvements mentioned above, Gremlint now produces: + +[source,groovy] +---- +g.V().as("v"). + repeat(both().simplePath().as("v")).emit(). + filter(project("x", "y", "z"). + by(select(first, "v")). + by(select(last, "v")). + by(select(all, "v").count(local)). + as("triple"). + coalesce(select("x", "y").as("a"). + select("triples"). + unfold().as("t"). + select("x", "y"). + where(eq("a")). + select("t"), local(aggregate("triples"))). + select("z").as("length"). + select("triple"). + select("z"). + where(eq("length"))). + select(all, "v"). + unfold(). + groupCount() +---- + +This more compact representation presents a form much more in line with the manually formatted one. While there is still +room to improve, Gremlint now produces a format that is more likely to be usable without additional manual formatting +intervention. + - ==== Remote Transaction Performance Improvements - - The Java driver now supports reusing existing pooled WebSocket connections for session-based requests rather than - establishing a dedicated connection per session. This behavior is controlled by the `Cluster.Builder` option - `reuseConnectionsForSessions`, which defaults to `false`. - - When enabled, a `Client.SessionedChildClient` will attempt to borrow a connection from the connection pool of a standard - `Client` rather than opening its own WebSocket connection. This avoids the overhead of the TCP handshake and WebSocket - upgrade for each session, which can be significant when issuing many short-lived transactions. - - [source,java] - ---- - // Enable connection reuse for sessions - Cluster cluster = Cluster.build(host) - .reuseConnectionsForSessions(true) - .create(); - ---- - - This feature was designed specifically for use with remote transactions, where sessions are short-lived and terminate - after a `commit()` or `rollback()`. It should not be used for classic long-running session use cases where a session - is used for purposes other than transactions such as remote console. - - ===== Server Configuration - - When using `reuseConnectionsForSessions`, the server must be configured with `closeSessionPostGraphOp` set to `true`. - This setting instructs the server to close the session immediately after a graph-level operation such as `commit()` or - `rollback()` completes. Without this setting, sessions will not be closed until the session timeout expires, leading to - a buildup of idle sessions on the server side. - - [source,yaml] - ---- - # gremlin-server.yaml - closeSessionPostGraphOp: true - ---- - - IMPORTANT: Failing to enable `closeSessionPostGraphOp` on the server when using `reuseConnectionsForSessions` on the - client will result in sessions that are not properly cleaned up. These leaked sessions will accumulate until the - configured `sessionLifetimeTimeout` is reached, consuming server resources unnecessarily. - - ===== Performance - - Performance was measured with an ad-hoc benchmark application. The application executes a configurable number of - complete transaction lifecycles (begin, mutate, commit) and reports throughput and latency percentiles. Each transaction - opens a session, submits one or more `addV()` operations, commits, and closes the session. - - The benchmark varies the following parameters: - - * *Concurrent clients* (`threads`): The number of threads issuing transactions simultaneously. A value of 1 means - transactions are executed sequentially by a single client. Higher values simulate multiple application threads or - service instances issuing transactions concurrently against the same server. - * *Connection pool size* (`pool`): The number of WebSocket connections maintained in the pool when - `reuseConnectionsForSessions` is enabled. When reuse is disabled, each session creates its own dedicated connection - and this parameter does not apply (shown as `n/a`). - * *Transaction weight* (`weight`): "light" transactions perform a single `addV()` plus commit. "heavy" transactions - perform ten `addV()` operations plus commit, simulating a more substantial unit of work per transaction. - - Tests were conducted both locally (client and server on the same machine) and remotely (client on the US west coast, - server on the US east coast) to isolate the effect of network latency on connection setup overhead. Each scenario - executed 1000 transactions after a warmup phase of 50 transactions. - - *Local Results (same machine)* - - [cols="3,1,1,1", options="header"] - |========================================================= - |Configuration |No-Reuse (tx/s) |Best-Reuse (tx/s) |Speedup - |1 client, light |23.1 |26.7 |1.16x - |8 clients, light |25.2 |28.5 |1.13x - |16 clients, light |25.4 |27.9 |1.10x - |1 client, heavy |26.0 |26.9 |1.03x - |8 clients, heavy |26.4 |27.9 |1.06x - |16 clients, heavy |25.8 |26.5 |1.03x - |========================================================= - - *Remote Results (west coast to east coast)* - - [cols="3,1,1,1", options="header"] - |========================================================= - |Configuration |No-Reuse (tx/s) |Best-Reuse (tx/s) |Speedup - |1 client, light |3.6 |7.6 |2.10x - |8 clients, light |15.6 |23.0 |1.48x - |16 clients, light |15.4 |25.3 |1.64x - |1 client, heavy |1.4 |1.8 |1.26x - |8 clients, heavy |9.2 |10.8 |1.17x - |16 clients, heavy |14.5 |15.9 |1.10x - |========================================================= - - The "Best-Reuse" column reflects the highest throughput observed across all tested pool sizes (2, 4, and 8 connections) - for each scenario. - - The benefit of connection reuse is most pronounced in remote scenarios with light transactions. When the network - round-trip cost is high and the transaction payload is small, the WebSocket connection setup overhead represents a - larger proportion of the total transaction time. In the single-client remote light workload, connection reuse yielded a - 2.10x throughput improvement, as the connection handshake cost dominated the per-transaction time. With 16 concurrent - clients in the same remote light scenario, throughput improved from 15.4 tx/s to 25.3 tx/s (1.64x), as the connection - pool amortized the setup cost across many parallel sessions. - - As transaction weight increases, the relative benefit diminishes because the graph operations themselves become the - bottleneck rather than connection setup. In the local heavy workload scenarios, the improvement was only 3-6%, as the - connection overhead was already negligible relative to the cost of the graph mutations. Even in the remote heavy - scenarios, the improvement ranged from 10-26%, as the ten `addV()` operations per transaction shifted the time - distribution toward server-side processing. - - In summary, `reuseConnectionsForSessions` provides the greatest benefit when: - - * Network latency between client and server is significant (remote deployments) - * Transactions are lightweight (few operations per transaction) - * Many short-lived transactions are issued in sequence or concurrently - - See: link:https://issues.apache.org/jira/browse/TINKERPOP-3213[TINKERPOP-3213] - +=== Upgrading for Providers + +==== Graph System Providers + - ===== Closing Sessions On Graph Operations - - An option has been added to the Java GLV (`reuseConnectionsForSessions`) that allows for borrowing open WebSocket - connections for sessions. This is primarily to reduce the overhead of new connection setup per session. This can lead - to large performance gains in remote transaction scenarios where there are many small mutation traversals. - - This option is disabled by default on the driver but providers may want to add an option that will allow sessions to end - on the successful completion of a graph operation (commit/rollback). This will prevent a buildup of sessions if a user - has enabled this option as the driver will *not* close the underlying WebSocket connection as a signal to end the - session. Gremlin Server has added an option like this called `closeSessionPostGraphOp`. Remote graph providers are - encouraged to add the same functionality. - +==== Graph Driver Providers +
