You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by fl...@apache.org on 2021/10/06 09:45:22 UTC

[tinkerpop] branch TINKERPOP-2556 updated (dad0e36 -> e0227e3)

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

florianhockmann pushed a change to branch TINKERPOP-2556
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git.


 discard dad0e36  TINKERPOP-2556 First try, tests don't terminate for some reason
     add 1cdac2a  Fix NPE due to CompletionException in ConnectionPool
     add d309ce6  Merge branch '3.4-dev' into 3.5-dev
     add 7efa866  Pin setuptools version prior to 58.
     add 248b70a  Merge branch '3.4-dev' into 3.5-dev
     add 086f7fa  TINKERPOP-2605 hasLabel(null) filters results
     add 2838d79  TINKERPOP-2605 Added test/docs for order() when the by() produces null
     add e9329eb  TINKERPOP-2605 Added test to validate dedup() grabbing the first item it encounters
     add c159c53  TINKERPOP-2605 Added tests for path() where by() can produce null
     add 3ca209a  TINKERPOP-2605 Added project() test where by() returns null
     add 24c70cf  TINKERPOP-2605 Added test for select() where by() produces null
     add a0d4b30  TINKERPOP-2598 Addressed NullPointerException with P.within/out
     add 5f77ae4  TINKERPOP-2605 Added test for where() evaluated null equality
     add 89119c3  TINKERPOP-2605 Improved null handling in reducing math steps.
     add 8503708  TINKERPOP-2605 Fixed issues with null and inject()
     add 53b5eb8  TINKERPOP-2605 Better handle hasKey/Value(null)
     add 95e0fc5  TINKERPOP-2605 Fixed docs around TinkerGraph default null handling
     add f8c9637  TINKERPOP-2605 Call correct overload for hasValue(null)
     add 31ea72a  TINKERPOP-2605 withSideEffect() allows null value
     add 73db22a  TINKERPOP-2605 Support null in path()
     add cf6b331  TINKERPOP-2605 Clean up a few minor points related to this JIRA
     add e6adca4  Merge branch 'TINKERPOP-2605' into 3.5-dev
     add 8bbf8d7  TINKERPOP-2570 Support custom types in GraphBinary for .NET
     add 6392aea  Merge branch 'TINKERPOP-2570' into 3.5-dev
     add cf81782  Fixed null handling in grammar
     add c629a7e  Added ConnectedComponent tokens given to with() to the grammar CTR
     add d8a41bc  Fixed bug in DotNetTranslator around ambiguous has() calls CTR
     add 730f70c  Preferred withEmbedded() in generate scripts CTR
     add 05f3f49  Backported some test assertion adjustments that make them work more consistently across OS/JVM CTR
     add 8a9cade  Merge branch '3.4-dev' into 3.5-dev
     add 79e01c8  Remove python2 from travis build
     add 298cd6b  TINKERPOP-2596 Added datetime() to gremlin-language
     add c911737  Merge branch 'TINKERPOP-2596' into 3.5-dev
     add f330348  minor doc fixup CTR
     add dac32de  TINKERPOP-2609 Improve error message for bad serialization in HTTP CTR
     add 66d0ee3  Merge branch '3.4-dev' into 3.5-dev
     add e1cc2bc  Fixed compile after 3.4-dev merge CTR
     add 009cda3  Bump gherkin from 20.0.1 to 22.0.0 in /gremlin-dotnet
     add f2445be  Merge branch 'dependabot/nuget/gremlin-dotnet/3.5-dev/gherkin-22.0.0' into 3.5-dev
     add 1c07696  Fix maven install for python3 CTR
     add b57125e  TINKERPOP-2621 Allowed grammar to support empty arguments to within() and without()
     add 11e84bf  Merge branch 'TINKERPOP-2621' into 3.5-dev
     add 324fa15  Added gh action build for 3.4-dev
     add f593dbc  Fixed copy/paste error in gh actions. CTR
     add de95cb6  Merge branch '3.4-dev' into 3.5-dev
     add 273b881  Added gh action build for 3.5-dev CTR
     add 5903586  Fixed rat issues with github actions for 3.4-dev
     add 4c85f2e  Merge branch '3.4-dev' into 3.5-dev
     add 22165d6  Fixed python version install in gh actions
     add a6f51e5  Stopped smoke tests from running in gh actions for 3.4-dev CTR
     add b23a5a9  fixed syntax error in smoke test for gh actions
     add 90b5d39  Merge branch '3.4-dev' into 3.5-dev
     add afd6106  All CI is now handled in gh actions - remove travis CTR
     add 1b2f307  Merge branch '3.4-dev' into 3.5-dev
     add 4814ca0  Move to temurin jdk as directed by setup-java docs.
     add 09bb73e  Skip 3.4-dev SSL tests to see if they are trouble to gh actions CTR
     add 637a83e  Test gh actions build without neo4j CTR
     add 2f2e42a  Merge branch '3.4-dev' into 3.5-dev
     add 1603415  Try to trim down the gh action builds so that they only occur for code changes CTR
     add 9a0c9f1  Already an error in previous commit related - smoke needs to depend on check CTR
     add 1be21d7  Apparently apache forces us to use a version in GitHub Marketplace CTR
     add b1ad6a3  Error in previous commit with gh action version CTR
     add e9746fc  In tiny tiny letters it seems that this gh action is not certified by the gh marketplace - can't be used. CTR
     add cafd020  Merge branch '3.4-dev' into 3.5-dev
     add 76fc5ba  Retain failure context in NoHostAvailableException
     add bfdffc5  Merge branch 'pr-1479' into 3.5-dev
     add abe0b0d  TINKERPOP-2616 Added upgrade docs for ssl exception changes CTR
     add ec98d58  Changed assertion for SSL error.
     add 3cab8c7  Remove duplicate build command entry CTR
     add f747ea0  Merge branch '3.4-dev' into 3.5-dev
     new e0227e3  TINKERPOP-2556 First try, tests don't terminate for some reason

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (dad0e36)
            \
             N -- N -- N   refs/heads/TINKERPOP-2556 (e0227e3)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/build-test.yml                   | 188 +++++++++++
 .travis.install-maven.sh                           |   2 +-
 .travis.yml                                        |  76 -----
 CHANGELOG.asciidoc                                 |  20 ++
 .../dev/developer/development-environment.asciidoc |   1 -
 docs/src/dev/developer/for-committers.asciidoc     |   3 +-
 docs/src/reference/gremlin-variants.asciidoc       |  12 +
 .../reference/implementations-tinkergraph.asciidoc |   2 +-
 docs/src/reference/the-traversal.asciidoc          |  96 +++++-
 docs/src/upgrade/release-3.5.x.asciidoc            |  61 ++++
 .../tinkerpop/gremlin/jsr223/CoreImports.java      |   6 +
 .../language/grammar/GenericLiteralVisitor.java    |  14 +
 .../grammar/GraphTraversalSourceVisitor.java       |  14 +-
 .../language/grammar/GremlinAntlrToJava.java       |  35 +++
 .../language/grammar/GremlinBaseVisitor.java       |  25 ++
 .../grammar/GremlinStringConstantsVisitor.java     |  21 ++
 .../language/grammar/TraversalMethodVisitor.java   |  23 +-
 .../grammar/TraversalPredicateVisitor.java         |   8 +-
 .../gremlin/process/traversal/Operator.java        |  53 +++-
 .../tinkerpop/gremlin/process/traversal/P.java     |  20 +-
 .../tinkerpop/gremlin/process/traversal/Path.java  |  33 +-
 .../traversal/dsl/graph/GraphTraversal.java        | 108 +++++--
 .../traversal/dsl/graph/GraphTraversalSource.java  |   6 +-
 .../process/traversal/step/map/GraphStep.java      |   3 +-
 .../process/traversal/step/map/MaxGlobalStep.java  |   1 -
 .../process/traversal/step/map/MeanGlobalStep.java |  22 +-
 .../process/traversal/step/map/MeanLocalStep.java  |  18 +-
 .../process/traversal/step/map/MinGlobalStep.java  |   1 -
 .../process/traversal/step/map/PropertiesStep.java |   3 +-
 .../process/traversal/step/map/SumGlobalStep.java  |  16 +-
 .../process/traversal/step/map/SumLocalStep.java   |  11 +-
 .../process/traversal/step/util/HasContainer.java  |  10 +-
 .../process/traversal/step/util/ImmutablePath.java |  12 +-
 .../process/traversal/step/util/MutablePath.java   |   5 +-
 .../traversal/step/util/ReducingBarrierStep.java   |  63 +++-
 .../strategy/decoration/SideEffectStrategy.java    |   2 +-
 .../traversal/translator/DotNetTranslator.java     |  41 ++-
 .../traversal/translator/GroovyTranslator.java     |  56 +++-
 .../traverser/B_LP_O_S_SE_SL_Traverser.java        |   2 +-
 .../traverser/LP_O_OB_S_SE_SL_Traverser.java       |   2 +-
 .../util/DefaultTraversalSideEffects.java          |   4 -
 .../process/traversal/util/SideEffectHelper.java   |  10 +
 .../structure/io/binary/types/PSerializer.java     |   2 +-
 .../structure/io/gryo/GryoSerializersV1d0.java     |   2 +-
 .../structure/io/gryo/GryoSerializersV3d0.java     |   2 +-
 .../gremlin/structure/io/gryo/GryoVersion.java     |  10 +-
 .../gremlin/structure/util/StringFactory.java      |   6 +-
 .../tinkerpop/gremlin/util/DatetimeHelper.java     | 116 +++++++
 .../tinkerpop/gremlin/util/NumberHelper.java       | 136 ++++++++
 .../gremlin/util/iterator/ArrayIterator.java       |   5 +-
 .../grammar/GeneralLiteralVisitorTest.java         |  44 +++
 .../grammar/TraversalPredicateVisitorTest.java     |   4 +
 .../gremlin/process/traversal/OperatorTest.java    | 344 ++++++++++++++-------
 .../tinkerpop/gremlin/process/traversal/PTest.java |  26 ++
 .../gremlin/process/traversal/PathTest.java        |  30 +-
 .../traversal/translator/DotNetTranslatorTest.java |  36 ++-
 .../traversal/translator/GroovyTranslatorTest.java |  13 +
 .../translator/JavascriptTranslatorTest.java       |   5 +
 .../util/DefaultTraversalSideEffectsTest.java      |  26 ++
 .../graphson/GraphSONMapperEmbeddedTypeTest.java   |   4 +-
 .../tinkerpop/gremlin/util/DatetimeHelperTest.java | 103 ++++++
 .../tinkerpop/gremlin/util/NumberHelperTest.java   | 112 ++++---
 .../gremlin/util/iterator/ArrayIteratorTest.java   |  32 ++
 gremlin-dotnet/build/generate.groovy               | 100 +++---
 .../Process/Traversal/GraphTraversal.cs            |  15 +-
 .../Process/Traversal/GraphTraversalSource.cs      |  16 +-
 .../Structure/IO/GraphBinary/DataType.cs           |   5 +
 .../IO/GraphBinary/GraphBinaryMessageSerializer.cs |  18 +-
 .../Structure/IO/GraphBinary/GraphBinaryReader.cs  |  25 +-
 .../Structure/IO/GraphBinary/GraphBinaryWriter.cs  |  22 +-
 .../IO/GraphBinary/TypeSerializerRegistry.cs       | 100 +++++-
 ...versalSerializer.cs => CustomTypeSerializer.cs} |  35 +--
 .../Gherkin/GherkinTestRunner.cs                   |   9 +-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |  66 +++-
 .../Gremlin.Net.IntegrationTest.csproj             |   2 +-
 .../IO/GraphBinary/Types/Sample/SamplePerson.cs}   |  42 +--
 .../Types/Sample/SamplePersonSerializer.cs         | 117 +++++++
 .../Types/Sample/SamplePersonSerializerTests.cs    |  77 +++++
 .../apache/tinkerpop/gremlin/driver/Client.java    |  61 ++--
 .../tinkerpop/gremlin/driver/ConnectionPool.java   |   4 +-
 .../driver/exception/NoHostAvailableException.java |   4 +
 .../GraphBinaryReaderWriterRoundTripTest.java      |   2 +-
 gremlin-javascript/build/generate.groovy           |  54 ++--
 .../gremlin-javascript/test/cucumber/gremlin.js    |  66 +++-
 gremlin-language/src/main/antlr4/Gremlin.g4        |  35 ++-
 .../language/grammar/ReferenceGrammarTest.java     |   1 -
 gremlin-python/build/generate.groovy               |  57 ++--
 gremlin-python/pom.xml                             |   9 +
 gremlin-python/src/main/python/radish/gremlin.py   |  66 +++-
 .../server/handler/HttpGremlinEndpointHandler.java |  13 +
 .../GraphBinaryRemoteGraphComputerProvider.java    |  30 +-
 .../GraphSONRemoteGraphComputerProvider.java       |  30 +-
 .../remote/GryoRemoteGraphComputerProvider.java    |  30 +-
 ...emoteGraphGroovyTranslatorComputerProvider.java |  30 +-
 .../gremlin/server/GremlinDriverIntegrateTest.java |   7 +-
 .../server/GremlinServerAuthIntegrateTest.java     |   3 +-
 .../server/GremlinServerHttpIntegrateTest.java     |  30 ++
 .../gremlin/server/GremlinServerIntegrateTest.java |   2 +-
 .../server/GremlinServerSslIntegrateTest.java      |  18 +-
 gremlin-test/features/filter/Dedup.feature         |  21 +-
 gremlin-test/features/filter/Has.feature           | 224 +++++++++++++-
 gremlin-test/features/filter/Where.feature         |  15 +
 gremlin-test/features/map/Max.feature              |  44 +++
 gremlin-test/features/map/Mean.feature             |  73 +++++
 gremlin-test/features/map/Min.feature              |  44 +++
 gremlin-test/features/map/Order.feature            |  16 +
 gremlin-test/features/map/Path.feature             |  39 +++
 gremlin-test/features/map/Project.feature          |  20 +-
 gremlin-test/features/map/Select.feature           |  44 ++-
 gremlin-test/features/map/Sum.feature              |  73 +++++
 gremlin-test/features/sideEffect/Inject.feature    |  89 +++++-
 .../gremlin/process/GremlinProcessRunner.java      |   4 +-
 .../process/traversal/step/filter/DedupTest.java   |  23 ++
 .../process/traversal/step/filter/HasTest.java     | 242 ++++++++++++++-
 .../process/traversal/step/filter/WhereTest.java   |  15 +
 .../process/traversal/step/map/MaxTest.java        |  63 ++++
 .../process/traversal/step/map/MeanTest.java       |  93 ++++++
 .../process/traversal/step/map/MinTest.java        |  63 ++++
 .../process/traversal/step/map/OrderTest.java      |  17 +
 .../process/traversal/step/map/PathTest.java       |  66 +++-
 .../process/traversal/step/map/ProjectTest.java    |  29 +-
 .../process/traversal/step/map/SelectTest.java     |  33 ++
 .../process/traversal/step/map/SumTest.java        | 100 ++++++
 .../traversal/step/sideEffect/InjectTest.java      | 102 ++++++
 .../traversal/step/sideEffect/Neo4jGraphStep.java  |  13 +-
 .../spark/process/computer/SparkMemory.java        |   1 -
 .../tinkergraph/process/computer/TinkerMemory.java |  20 +-
 127 files changed, 4301 insertions(+), 653 deletions(-)
 create mode 100644 .github/workflows/build-test.yml
 delete mode 100644 .travis.yml
 create mode 100644 gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/util/DatetimeHelper.java
 create mode 100644 gremlin-core/src/test/java/org/apache/tinkerpop/gremlin/util/DatetimeHelperTest.java
 copy gremlin-dotnet/src/Gremlin.Net/Structure/IO/GraphBinary/Types/{TraversalSerializer.cs => CustomTypeSerializer.cs} (55%)
 copy gremlin-dotnet/{src/Gremlin.Net/Structure/Element.cs => test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/Types/Sample/SamplePerson.cs} (53%)
 create mode 100644 gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/Types/Sample/SamplePersonSerializer.cs
 create mode 100644 gremlin-dotnet/test/Gremlin.Net.UnitTest/Structure/IO/GraphBinary/Types/Sample/SamplePersonSerializerTests.cs

[tinkerpop] 01/01: TINKERPOP-2556 First try, tests don't terminate for some reason

Posted by fl...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

florianhockmann pushed a commit to branch TINKERPOP-2556
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit e0227e36f6c25471cb62a6b96344ac84b1ed621e
Author: Florian Hockmann <fh...@florian-hockmann.de>
AuthorDate: Fri Oct 1 15:52:32 2021 +0200

    TINKERPOP-2556 First try, tests don't terminate for some reason
---
 .../Driver/Remote/DriverRemoteConnection.cs        | 35 ++++++++-
 .../Driver/Remote/DriverRemoteTransaction.cs       | 69 ++++++++++++++++
 gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj  |  5 +-
 .../Process/Remote/IRemoteConnection.cs            |  6 ++
 .../src/Gremlin.Net/Process/Traversal/Bytecode.cs  |  2 +-
 .../IRemoteConnection.cs => Traversal/GraphOp.cs}  | 26 +++----
 .../Process/Traversal/GraphTraversalSource.cs      | 32 ++++++--
 .../ITransaction.cs}                               | 17 ++--
 .../GraphTraversalModificationTests.cs             | 91 ++++++++++++++++++++++
 .../DriverRemoteConnection/GraphTraversalTests.cs  |  2 +-
 .../Driver/Remote/DriverRemoteTransactionTests.cs  | 57 ++++++++++++++
 11 files changed, 303 insertions(+), 39 deletions(-)

diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
index 006cf8a..63649a1 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteConnection.cs
@@ -25,10 +25,10 @@ using System;
 using System.Collections.Generic;
 using System.Threading.Tasks;
 using Gremlin.Net.Driver.Messages;
-using Gremlin.Net.Driver;
 using Gremlin.Net.Process.Remote;
 using Gremlin.Net.Process.Traversal;
 using Gremlin.Net.Process.Traversal.Strategy.Decoration;
+using Gremlin.Net.Structure;
 
 namespace Gremlin.Net.Driver.Remote
 {
@@ -49,6 +49,10 @@ namespace Gremlin.Net.Driver.Remote
                     {Tokens.ArgsEvalTimeout, "scriptEvaluationTimeout", Tokens.ArgsBatchSize, 
                      Tokens.RequestId, Tokens.ArgsUserAgent};
 
+        private readonly string _sessionId;
+        private string Processor => IsSessionBound ? Tokens.ProcessorSession : Tokens.ProcessorTraversal;
+        public bool IsSessionBound => _sessionId != null;
+
         /// <summary>
         ///     Initializes a new <see cref="IRemoteConnection" /> using "g" as the default remote TraversalSource name.
         /// </summary>
@@ -91,6 +95,12 @@ namespace Gremlin.Net.Driver.Remote
             _traversalSource = traversalSource ?? throw new ArgumentNullException(nameof(traversalSource));
         }
 
+        private DriverRemoteConnection(IGremlinClient client, string traversalSource, Guid sessionId)
+            : this(client, traversalSource)
+        {
+            _sessionId = sessionId.ToString();
+        }
+
         /// <summary>
         ///     Submits <see cref="Bytecode" /> for evaluation to a remote Gremlin Server.
         /// </summary>
@@ -107,11 +117,16 @@ namespace Gremlin.Net.Driver.Remote
         {
             var requestMsg =
                 RequestMessage.Build(Tokens.OpsBytecode)
-                    .Processor(Tokens.ProcessorTraversal)
+                    .Processor(Processor)
                     .OverrideRequestId(requestid)
                     .AddArgument(Tokens.ArgsGremlin, bytecode)
                     .AddArgument(Tokens.ArgsAliases, new Dictionary<string, string> {{"g", _traversalSource}});
 
+            if (IsSessionBound)
+            {
+                requestMsg.AddArgument(Tokens.ArgsSession, _sessionId);
+            }
+
             var optionsStrategyInst = bytecode.SourceInstructions.Find(
                 s => s.OperatorName == "withStrategies" && s.Arguments[0] is OptionsStrategy);
             if (optionsStrategyInst != null)
@@ -128,6 +143,22 @@ namespace Gremlin.Net.Driver.Remote
             
             return await _client.SubmitAsync<Traverser>(requestMsg.Create()).ConfigureAwait(false);
         }
+        
+        public ITransaction Tx(GraphTraversalSource g)
+        {
+            var session = new DriverRemoteConnection(_client, _traversalSource, Guid.NewGuid());
+            return new DriverRemoteTransaction(session, g);
+        }
+
+        public async Task CommitAsync()
+        {
+            await SubmitAsync<object, object>(GraphOp.Commit).ConfigureAwait(false);
+        }
+        
+        public async Task RollbackAsync()
+        {
+            await SubmitAsync<object, object>(GraphOp.Rollback).ConfigureAwait(false);
+        }
 
         /// <inheritdoc />
         public void Dispose()
diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs
new file mode 100644
index 0000000..f3be21b
--- /dev/null
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Remote/DriverRemoteTransaction.cs
@@ -0,0 +1,69 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
+
+namespace Gremlin.Net.Driver.Remote
+{
+    public class DriverRemoteTransaction : ITransaction, IDisposable
+    {
+        private readonly DriverRemoteConnection _sessionBasedConnection;
+        private GraphTraversalSource _g;
+
+        public DriverRemoteTransaction(DriverRemoteConnection connection, GraphTraversalSource g)
+        {
+            _sessionBasedConnection = connection;
+            _g = g;
+        }
+
+        public GraphTraversalSource Begin()
+        {
+            if (_g.IsSessionBound)
+            {
+                throw new InvalidOperationException("Transaction already started on this object");
+            }
+            _g = new GraphTraversalSource(_g.TraversalStrategies, _g.Bytecode, _sessionBasedConnection);
+            return _g;
+        }
+
+        public async Task CommitAsync()
+        {
+            await _sessionBasedConnection.CommitAsync().ConfigureAwait(false);
+            Dispose();
+        }
+
+        public async Task RollbackAsync()
+        {
+            await _sessionBasedConnection.RollbackAsync().ConfigureAwait(false);
+            Dispose();
+        }
+
+        public void Dispose()
+        {
+            _sessionBasedConnection.Dispose();
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
index 0f963bb..f9e3fc5 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
+++ b/gremlin-dotnet/src/Gremlin.Net/Gremlin.Net.csproj
@@ -19,8 +19,9 @@ limitations under the License.
 
   <PropertyGroup Label="Build">
     <TargetFramework>netstandard2.0</TargetFramework>
-    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
-    <GenerateDocumentationFile>true</GenerateDocumentationFile>
+<!--    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>-->
+<!--    <GenerateDocumentationFile>true</GenerateDocumentationFile>-->
+    <LangVersion>8</LangVersion>
   </PropertyGroup>
 
   <PropertyGroup Label="Package">
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
index 5393bcb..9502f5d 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
@@ -23,6 +23,7 @@
 
 using System.Threading.Tasks;
 using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
 
 namespace Gremlin.Net.Process.Remote
 {
@@ -38,5 +39,10 @@ namespace Gremlin.Net.Process.Remote
         /// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
         /// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
         Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+        
+        ITransaction Tx(GraphTraversalSource graphTraversalSource);
+        bool IsSessionBound { get; }
+        Task CommitAsync();
+        Task RollbackAsync();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
index 7149e8b..cd53a1c 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/Bytecode.cs
@@ -38,7 +38,7 @@ namespace Gremlin.Net.Process.Traversal
     /// </remarks>
     public class Bytecode
     {
-        private static readonly object[] EmptyArray = new object[0];
+        private static readonly object[] EmptyArray = Array.Empty<object>();
 
         /// <summary>
         ///     Initializes a new instance of the <see cref="Bytecode" /> class.
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
similarity index 55%
copy from gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
copy to gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
index 5393bcb..b938541 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphOp.cs
@@ -21,22 +21,18 @@
 
 #endregion
 
-using System.Threading.Tasks;
-using Gremlin.Net.Process.Traversal;
-
-namespace Gremlin.Net.Process.Remote
+namespace Gremlin.Net.Process.Traversal
 {
-    /// <summary>
-    ///     A simple abstraction of a "connection" to a "server".
-    /// </summary>
-    public interface IRemoteConnection
+    public static class GraphOp
     {
-        /// <summary>
-        ///     Submits <see cref="ITraversal" /> <see cref="Bytecode" /> to a server and returns a
-        ///     <see cref="ITraversal" />.
-        /// </summary>
-        /// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
-        /// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
-        Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+        public static Bytecode Commit { get; } = CreateGraphOp("tx", "commit");
+        public static Bytecode Rollback { get; } = CreateGraphOp("tx", "rollback");
+
+        private static Bytecode CreateGraphOp(string name, object value)
+        {
+            var bytecode = new Bytecode();
+            bytecode.AddSource(name, value);
+            return bytecode;
+        }
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
index c74e826..ba31cd7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Process/Traversal/GraphTraversalSource.cs
@@ -24,6 +24,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using Gremlin.Net.Driver.Remote;
 using Gremlin.Net.Process.Remote;
 using Gremlin.Net.Process.Traversal.Strategy.Decoration;
 using Gremlin.Net.Structure;
@@ -38,6 +39,10 @@ namespace Gremlin.Net.Process.Traversal
     /// </summary>
     public class GraphTraversalSource
     {
+        private readonly IRemoteConnection _connection;
+
+        public bool IsSessionBound => _connection is { IsSessionBound: true };
+        
         /// <summary>
         ///     Gets or sets the traversal strategies associated with this graph traversal source.
         /// </summary>
@@ -71,6 +76,15 @@ namespace Gremlin.Net.Process.Traversal
             Bytecode = bytecode;
         }
 
+        public GraphTraversalSource(ICollection<ITraversalStrategy> traversalStrategies, Bytecode bytecode,
+            IRemoteConnection connection)
+            : this(traversalStrategies.Where(strategy => strategy.GetType() != typeof(RemoteStrategy)).ToList(),
+                bytecode)
+        {
+            _connection = connection;
+            TraversalStrategies.Add(new RemoteStrategy(connection));
+        }
+
         public GraphTraversalSource With(string key)
         {
             return With(key, true);
@@ -243,12 +257,19 @@ namespace Gremlin.Net.Process.Traversal
         ///     <see cref="GraphTraversal{SType, EType}" />.
         /// </param>
         /// <returns>A <see cref="GraphTraversalSource" /> configured to use the provided <see cref="IRemoteConnection" />.</returns>
-        public GraphTraversalSource WithRemote(IRemoteConnection remoteConnection)
+        public GraphTraversalSource WithRemote(IRemoteConnection remoteConnection) =>
+            new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
+                new Bytecode(Bytecode), remoteConnection);
+
+        public ITransaction Tx()
         {
-            var source = new GraphTraversalSource(new List<ITraversalStrategy>(TraversalStrategies),
-                new Bytecode(Bytecode));
-            source.TraversalStrategies.Add(new RemoteStrategy(remoteConnection));
-            return source;
+            // you can't do g.tx().begin().tx() - no child transactions
+            if (IsSessionBound)
+            {
+                throw new InvalidOperationException(
+                    "This GraphTraversalSource is already bound to a transaction - child transactions are not supported");
+            }
+            return _connection.Tx(this);
         }
 
         /// <summary>
@@ -377,7 +398,6 @@ namespace Gremlin.Net.Process.Traversal
                 traversal.Bytecode.AddStep("io", file);
             return traversal;
         }
-
     }
     
 #pragma warning restore 1591
diff --git a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs b/gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
similarity index 59%
copy from gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
copy to gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
index 5393bcb..f3dc77e 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Process/Remote/IRemoteConnection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Structure/ITransaction.cs
@@ -24,19 +24,12 @@
 using System.Threading.Tasks;
 using Gremlin.Net.Process.Traversal;
 
-namespace Gremlin.Net.Process.Remote
+namespace Gremlin.Net.Structure
 {
-    /// <summary>
-    ///     A simple abstraction of a "connection" to a "server".
-    /// </summary>
-    public interface IRemoteConnection
+    public interface ITransaction
     {
-        /// <summary>
-        ///     Submits <see cref="ITraversal" /> <see cref="Bytecode" /> to a server and returns a
-        ///     <see cref="ITraversal" />.
-        /// </summary>
-        /// <param name="bytecode">The <see cref="Bytecode" /> to send.</param>
-        /// <returns>The <see cref="ITraversal" /> with the results and optional side-effects.</returns>
-        Task<ITraversal<S, E>> SubmitAsync<S, E>(Bytecode bytecode);
+        GraphTraversalSource Begin();
+        Task CommitAsync();
+        Task RollbackAsync();
     }
 }
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs
new file mode 100644
index 0000000..341cde0
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalModificationTests.cs
@@ -0,0 +1,91 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using System.Threading.Tasks;
+using Gremlin.Net.Process.Remote;
+using Gremlin.Net.Process.Traversal;
+using Xunit;
+
+namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
+{
+    public class GraphTraversalModificationTests : IDisposable
+    {
+        private readonly IRemoteConnection _connection = new RemoteConnectionFactory().CreateRemoteConnection("g");
+
+        [Fact]
+        public async Task ShouldSupportRemoteTransactionsCommit()
+        {
+            var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+            var tx = g.Tx();
+            var gtx = tx.Begin();
+            await gtx.AddV("person").Property("name", "florian").Promise(t => t.Iterate()).ConfigureAwait(false);
+            await gtx.AddV("person").Property("name", "josh").Promise(t => t.Iterate()).ConfigureAwait(false);
+            
+            // Assert within the transaction
+            var count = await gtx.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+            Assert.Equal(2, count);
+            
+            // Now commit changes to test outside of the transaction
+            await tx.CommitAsync().ConfigureAwait(false);
+
+            count = await g.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+            Assert.Equal(2, count);
+            
+            g.V().Count().Next();
+        }
+        
+        [Fact]
+        public async Task ShouldSupportRemoteTransactionsRollback()
+        {
+            var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+            var tx = g.Tx();
+            var gtx = tx.Begin();
+            await gtx.AddV("person").Property("name", "florian").Promise(t => t.Iterate()).ConfigureAwait(false);
+            await gtx.AddV("person").Property("name", "josh").Promise(t => t.Iterate()).ConfigureAwait(false);
+            
+            // Assert within the transaction
+            var count = await gtx.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+            Assert.Equal(2, count);
+            
+            // Now rollback changes to test outside of the transaction
+            await tx.RollbackAsync().ConfigureAwait(false);
+
+            count = await g.V().Count().Promise(t => t.Next()).ConfigureAwait(false);
+            Assert.Equal(2, count);
+            
+            g.V().Count().Next();
+        }
+
+        public void Dispose()
+        {
+            EmptyGraph();
+        }
+
+        private void EmptyGraph()
+        {
+            var g = AnonymousTraversalSource.Traversal().WithRemote(_connection);
+            g.V().Drop().Iterate();
+        }
+    }
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
index 89597a3..b0347bc 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/GraphTraversalTests.cs
@@ -247,4 +247,4 @@ namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
             Assert.Equal(6, count);
         }
     }
-}
+}
\ No newline at end of file
diff --git a/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs
new file mode 100644
index 0000000..51f2fc3
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.UnitTest/Driver/Remote/DriverRemoteTransactionTests.cs
@@ -0,0 +1,57 @@
+#region License
+
+/*
+ * 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.
+ */
+
+#endregion
+
+using System;
+using Gremlin.Net.Driver;
+using Gremlin.Net.Driver.Remote;
+using Gremlin.Net.Process.Traversal;
+using Moq;
+using Xunit;
+
+namespace Gremlin.Net.UnitTest.Driver.Remote
+{
+    public class DriverRemoteTransactionTests
+    {
+        [Fact]
+        public void ShouldNotAllowBeginMoreThanOnce()
+        {
+            var g = AnonymousTraversalSource.Traversal()
+                .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>()));
+            var tx = g.Tx();
+            tx.Begin();
+
+            Assert.Throws<InvalidOperationException>(() => tx.Begin());
+        }
+        
+        [Fact]
+        public void ShouldNotSupportChildTransactions()
+        {
+            var g = AnonymousTraversalSource.Traversal()
+                .WithRemote(new DriverRemoteConnection(Mock.Of<IGremlinClient>()));
+            var tx = g.Tx();
+            
+            var gtx = tx.Begin();
+            Assert.Throws<InvalidOperationException>(() => gtx.Tx());
+        }
+    }
+}
\ No newline at end of file