You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by va...@apache.org on 2022/12/05 22:57:48 UTC
[tinkerpop] 01/01: merge from 3.5-dev
This is an automated email from the ASF dual-hosted git repository.
valentyn pushed a commit to branch 3.6-dev
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit 4b2fff742764805533e9ae8e9c9dd5079fbe6667
Merge: ca8111140c ea67b9e64a
Author: Valentyn Kahamlyk <va...@bitquilltech.com>
AuthorDate: Mon Dec 5 14:57:38 2022 -0800
merge from 3.5-dev
CHANGELOG.asciidoc | 4 ++
docs/src/dev/provider/index.asciidoc | 8 +++
docs/src/reference/gremlin-applications.asciidoc | 4 ++
docs/src/reference/gremlin-variants.asciidoc | 10 +++
.../Gremlin.Net/Driver/ConnectionPoolSettings.cs | 13 +++-
.../src/Gremlin.Net/Driver/GremlinClient.cs | 9 ++-
.../src/Gremlin.Net/Driver/WebSocketConnection.cs | 6 ++
.../src/Gremlin.Net/Driver/WebSocketSettings.cs | 2 +
gremlin-dotnet/src/Gremlin.Net/Process/Utils.cs | 27 +++++++-
.../tinkerpop/gremlin/driver/Channelizer.java | 13 ++--
.../apache/tinkerpop/gremlin/driver/Cluster.java | 31 ++++++++-
.../apache/tinkerpop/gremlin/driver/Settings.java | 8 +++
.../apache/tinkerpop/gremlin/driver/UserAgent.java | 55 ++++++++++++++++
.../tinkerpop/gremlin/driver/SettingsTest.java | 2 +
.../gremlin/driver/TestWSGremlinInitializer.java | 37 +++++++++++
.../WebSocketClientBehaviorIntegrateTest.java | 38 +++++++++++
gremlin-go/driver/client.go | 41 ++++++------
gremlin-go/driver/connection.go | 17 ++---
gremlin-go/driver/connection_test.go | 17 ++---
gremlin-go/driver/driverRemoteConnection.go | 67 ++++++++++---------
gremlin-go/driver/gorillaTransporter.go | 9 ++-
gremlin-go/driver/user_agent.go | 65 +++++++++++++++++++
.../main/python/gremlin_python/driver/client.py | 5 +-
.../python/gremlin_python/driver/connection.py | 9 ++-
.../driver/driver_remote_connection.py | 7 +-
.../main/python/gremlin_python/driver/useragent.py | 41 ++++++++++++
.../apache/tinkerpop/gremlin/server/Context.java | 10 +++
.../server/channel/WebSocketChannelizer.java | 5 +-
.../gremlin/server/handler/WsUserAgentHandler.java | 75 ++++++++++++++++++++++
.../gremlin/server/util/MetricManager.java | 8 +++
.../gremlin/server/GremlinServerIntegrateTest.java | 70 ++++++++++++++++++++
.../gremlin/server/channel/TestChannelizer.java | 52 +++++++++++++++
.../server/channel/UnifiedTestChannelizer.java | 44 +++++++++++++
.../server/channel/WebSocketTestChannelizer.java | 44 +++++++++++++
34 files changed, 768 insertions(+), 85 deletions(-)
diff --cc gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
index 00bd75ed46,bccd5d63b4..0f49cf964b
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/ConnectionPoolSettings.cs
@@@ -35,10 -35,11 +35,11 @@@ namespace Gremlin.Net.Drive
private int _maxInProcessPerConnection = DefaultMaxInProcessPerConnection;
private int _reconnectionAttempts = DefaultReconnectionAttempts;
private TimeSpan _reconnectionBaseDelay = DefaultReconnectionBaseDelay;
- private const int DefaultPoolSize = 4;
- private const int DefaultMaxInProcessPerConnection = 32;
+ private const int DefaultPoolSize = 8;
+ private const int DefaultMaxInProcessPerConnection = 16;
private const int DefaultReconnectionAttempts = 4;
private static readonly TimeSpan DefaultReconnectionBaseDelay = TimeSpan.FromSeconds(1);
+ internal const bool DefaultEnableUserAgentOnConnect = true;
/// <summary>
/// Gets or sets the size of the connection pool.
diff --cc gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
index acda9d04e6,a688c53879..361cf57357
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/GremlinClient.cs
@@@ -169,10 -172,11 +173,11 @@@ namespace Gremlin.Net.Drive
Action<ClientWebSocketOptions> webSocketConfiguration = null, string sessionId = null,
bool disableCompression = false, ILoggerFactory loggerFactory = null)
{
- messageSerializer ??= new GraphSON3MessageSerializer();
+ messageSerializer ??= new GraphBinaryMessageSerializer();
var webSocketSettings = new WebSocketSettings
{
- WebSocketConfigurationCallback = webSocketConfiguration
+ WebSocketConfigurationCallback = webSocketConfiguration,
+ EnableUserAgentOnConnect = connectionPoolSettings?.EnableUserAgentOnConnect ?? ConnectionPoolSettings.DefaultEnableUserAgentOnConnect
#if NET6_0_OR_GREATER
, UseCompression = !disableCompression
#endif
diff --cc gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
index a9e5105376,2ce10c2653..5a56418ff1
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/WebSocketClientBehaviorIntegrateTest.java
@@@ -75,8 -73,59 +75,46 @@@ public class WebSocketClientBehaviorInt
@After
public void shutdown() {
server.stop();
-
- // reset logger
- final org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
-
- if (name.getMethodName().equals("shouldRemoveConnectionFromPoolWhenServerClose_WithPendingRequests") ||
- name.getMethodName().equals("shouldNotCreateReplacementConnectionWhenClientClosesConnection")) {
- final org.apache.log4j.Logger connectionPoolLogger = org.apache.log4j.Logger.getLogger(ConnectionPool.class);
- final org.apache.log4j.Logger connectionLogger = org.apache.log4j.Logger.getLogger(Connection.class);
- connectionPoolLogger.setLevel(previousLogLevel);
- connectionLogger.setLevel(previousLogLevel);
- }
-
- rootLogger.removeAppender(recordingAppender);
}
+ /**
+ * Tests that client is correctly sending user agent during web socket handshake by having the server return
+ * the captured user agent.
+ */
+ @Test
+ public void shouldIncludeUserAgentInHandshakeRequest() {
+ final Cluster cluster = Cluster.build("localhost").port(SimpleSocketServer.PORT)
+ .minConnectionPoolSize(1)
+ .maxConnectionPoolSize(1)
+ .serializer(Serializers.GRAPHSON_V2D0)
+ .create();
+ final Client.ClusteredClient client = cluster.connect();
+
+ // trigger the testing server to return captured user agent
+ String returnedUserAgent = client.submit("1", RequestOptions.build()
+ .overrideRequestId(TestWSGremlinInitializer.USER_AGENT_REQUEST_ID).create()).one().getString();
+ assertEquals(UserAgent.USER_AGENT, returnedUserAgent);
+ }
+
+ /**
+ * Tests that no user agent is sent to server when that behaviour is disabled.
+ */
+ @Test
+ public void shouldNotIncludeUserAgentInHandshakeRequestIfDisabled() {
+ final Cluster cluster = Cluster.build("localhost").port(SimpleSocketServer.PORT)
+ .minConnectionPoolSize(1)
+ .maxConnectionPoolSize(1)
+ .serializer(Serializers.GRAPHSON_V2D0)
+ .enableUserAgentOnConnect(false)
+ .create();
+ final Client.ClusteredClient client = cluster.connect();
+
+ // trigger the testing server to return captured user agent
+ String returnedUserAgent = client.submit("1", RequestOptions.build()
+ .overrideRequestId(TestWSGremlinInitializer.USER_AGENT_REQUEST_ID).create()).one().getString();
+ assertEquals("", returnedUserAgent);
+ }
+
/**
* Constructs a deadlock situation when initializing a {@link Client} object in sessionless form that leads to
* hanging behavior in low resource environments (TINKERPOP-2504) and for certain configurations of the
diff --cc gremlin-python/src/main/python/gremlin_python/driver/client.py
index 084b86f45c,61bead15a9..3a8e45c147
--- a/gremlin-python/src/main/python/gremlin_python/driver/client.py
+++ b/gremlin-python/src/main/python/gremlin_python/driver/client.py
@@@ -43,8 -41,8 +43,8 @@@ class Client
transport_factory=None, pool_size=None, max_workers=None,
message_serializer=None, username="", password="",
kerberized_service="", headers=None, session=None,
- **transport_kwargs):
+ enable_user_agent_on_connect=True, **transport_kwargs):
- logging.info("Creating Client with url '%s'", url)
+ log.info("Creating Client with url '%s'", url)
self._closed = False
self._url = url
self._headers = headers
diff --cc gremlin-python/src/main/python/gremlin_python/driver/connection.py
index c26a09e627,92ebb2795d..ca43d66d20
--- a/gremlin-python/src/main/python/gremlin_python/driver/connection.py
+++ b/gremlin-python/src/main/python/gremlin_python/driver/connection.py
@@@ -15,10 -15,10 +15,10 @@@
# specific language governing permissions and limitations
# under the License.
import uuid
+import queue
from concurrent.futures import Future
-from six.moves import queue
- from gremlin_python.driver import resultset
+ from gremlin_python.driver import resultset, useragent
__author__ = 'David M. Brown (davebshow@gmail.com)'
diff --cc gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py
index 4156bf2822,e7768746fe..858c85b92e
--- a/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py
+++ b/gremlin-python/src/main/python/gremlin_python/driver/driver_remote_connection.py
@@@ -39,8 -37,8 +39,8 @@@ class DriverRemoteConnection(RemoteConn
username="", password="", kerberized_service='',
message_serializer=None, graphson_reader=None,
graphson_writer=None, headers=None, session=None,
- **transport_kwargs):
- log.info("Creating DriverRemoteConnection with url '%s'", str(url))
+ enable_user_agent_on_connect=True, **transport_kwargs):
- logging.info("Creating DriverRemoteConnection with url '%s'", str(url))
++ logg.info("Creating DriverRemoteConnection with url '%s'", str(url))
self.__url = url
self.__traversal_source = traversal_source
self.__protocol_factory = protocol_factory
diff --cc gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
index 955182ce93,ad15772509..da1c666bc0
--- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
+++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/Context.java
@@@ -24,9 -24,10 +24,10 @@@ import org.apache.tinkerpop.gremlin.dri
import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
import org.apache.tinkerpop.gremlin.groovy.engine.GremlinExecutor;
import io.netty.channel.ChannelHandlerContext;
-import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinScriptChecker;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptChecker;
import org.apache.tinkerpop.gremlin.process.traversal.Bytecode;
import org.apache.tinkerpop.gremlin.server.handler.Frame;
+ import org.apache.tinkerpop.gremlin.server.handler.WsUserAgentHandler;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
diff --cc gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 5f237a3d56,f5264886fe..5ab40a265e
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@@ -18,14 -18,12 +18,16 @@@
*/
package org.apache.tinkerpop.gremlin.server;
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+ import io.netty.channel.ChannelHandlerContext;
+ import io.netty.util.AttributeKey;
+import nl.altindag.log.LogCaptor;
import org.apache.commons.configuration2.BaseConfiguration;
import org.apache.commons.configuration2.Configuration;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
+import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
+import org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer;
+import org.apache.tinkerpop.gremlin.util.ExceptionHelper;
import org.apache.tinkerpop.gremlin.TestHelper;
import org.apache.tinkerpop.gremlin.driver.Client;
import org.apache.tinkerpop.gremlin.driver.Cluster;
@@@ -49,12 -47,21 +52,19 @@@ import org.apache.tinkerpop.gremlin.str
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
-import org.apache.tinkerpop.gremlin.server.handler.OpSelectorHandler;
import org.apache.tinkerpop.gremlin.server.op.AbstractEvalOpProcessor;
import org.apache.tinkerpop.gremlin.server.op.standard.StandardOpProcessor;
+ import org.apache.tinkerpop.gremlin.server.channel.TestChannelizer;
+ import org.apache.tinkerpop.gremlin.server.channel.UnifiedChannelizer;
+ import org.apache.tinkerpop.gremlin.server.channel.UnifiedTestChannelizer;
+ import org.apache.tinkerpop.gremlin.server.channel.WebSocketChannelizer;
+ import org.apache.tinkerpop.gremlin.server.channel.WebSocketTestChannelizer;
+ import org.apache.tinkerpop.gremlin.server.handler.WsUserAgentHandler;
import org.apache.tinkerpop.gremlin.structure.Graph;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
-import org.apache.tinkerpop.gremlin.util.Log4jRecordingAppender;
import org.apache.tinkerpop.gremlin.util.function.Lambda;
+ import org.apache.tinkerpop.gremlin.util.ExceptionHelper;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matchers;
import org.junit.After;
@@@ -122,42 -128,42 +132,46 @@@ public class GremlinServerIntegrateTes
}};
private static final int POOL_SIZE_FOR_TIMEOUT_TESTS = 1;
+ private static LogCaptor logCaptor;
+
+ @BeforeClass
+ public static void setupLogCaptor() {
+ logCaptor = LogCaptor.forRoot();
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() {
+ logCaptor.close();
+ }
+
@Before
public void setupForEachTest() {
- recordingAppender = new Log4jRecordingAppender();
- final Logger rootLogger = Logger.getRootLogger();
if (name.getMethodName().equals("shouldPingChannelIfClientDies") ||
- name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond") ||
- name.getMethodName().equals("shouldCaptureUserAgentFromClient")) {
- final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
- final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
- final org.apache.log4j.Logger wsUserAgentHandlerLogger = org.apache.log4j.Logger.getLogger(WsUserAgentHandler.class);
+ name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
+ final Logger opSelectorHandlerLogger = (Logger) LoggerFactory.getLogger(OpSelectorHandler.class);
+ final Logger unifiedHandlerLogger = (Logger) LoggerFactory.getLogger(UnifiedHandler.class);
++ final Logger wsUserAgentHandlerLogger = (Logger) LoggerFactory.getLogger(WsUserAgentHandler.class);
previousLogLevel = opSelectorHandlerLogger.getLevel();
opSelectorHandlerLogger.setLevel(Level.INFO);
unifiedHandlerLogger.setLevel(Level.INFO);
+ wsUserAgentHandlerLogger.setLevel(Level.DEBUG);
}
- rootLogger.addAppender(recordingAppender);
+ logCaptor.clearLogs();
}
@After
public void teardownForEachTest() {
- final Logger rootLogger = Logger.getRootLogger();
-
if (name.getMethodName().equals("shouldPingChannelIfClientDies")||
- name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond") ||
- name.getMethodName().equals("shouldCaptureUserAgentFromClient")) {
- final org.apache.log4j.Logger opSelectorHandlerLogger = org.apache.log4j.Logger.getLogger(OpSelectorHandler.class);
+ name.getMethodName().equals("shouldCloseChannelIfClientDoesntRespond")) {
+ final Logger opSelectorHandlerLogger = (Logger) LoggerFactory.getLogger(OpSelectorHandler.class);
opSelectorHandlerLogger.setLevel(previousLogLevel);
- final org.apache.log4j.Logger unifiedHandlerLogger = org.apache.log4j.Logger.getLogger(UnifiedHandler.class);
+ final Logger unifiedHandlerLogger = (Logger) LoggerFactory.getLogger(UnifiedHandler.class);
unifiedHandlerLogger.setLevel(previousLogLevel);
- final org.apache.log4j.Logger wsUserAgentHandlerLogger = org.apache.log4j.Logger.getLogger(WsUserAgentHandler.class);
++ final Logger wsUserAgentHandlerLogger = (Logger) LoggerFactory.getLogger(WsUserAgentHandler.class);
+ wsUserAgentHandlerLogger.setLevel(previousLogLevel);
}
-
- rootLogger.removeAppender(recordingAppender);
}
/**
@@@ -290,6 -302,55 +310,56 @@@
return scriptEngineConf;
}
+ @Test
+ public void shouldCaptureUserAgentFromClient() {
+ final Cluster cluster = TestClientFactory.build().enableUserAgentOnConnect(true).create();
+ final Client client = cluster.connect();
+ client.submit("test");
+
- assertThat(recordingAppender.logContainsAny(".*New Connection on channel .* with user agent.*$"), is(true));
++ assertThat(logCaptor.getLogs().stream().anyMatch(m -> m.matches(
++ ".*New Connection on channel .* with user agent.*$")), is(true));
+
+ cluster.close();
+ }
+
+ @Test
+ public void shouldStoreUserAgentInContextWebSocket() throws InterruptedException {
+ shouldStoreUserAgentInContext();
+ }
+
+ @Test
+ public void shouldStoreUserAgentInContextUnified() throws InterruptedException {
+ shouldStoreUserAgentInContext();
+ }
+
+ private void shouldStoreUserAgentInContext() throws InterruptedException {
+ if(server.getChannelizer() instanceof TestChannelizer) {
+ assertNull(getUserAgentIfAvailable());
+ final Cluster cluster = TestClientFactory.build().enableUserAgentOnConnect(true).create();
+ final Client client = cluster.connect();
+
+ client.submit("test");
+ assertEquals(UserAgent.USER_AGENT, getUserAgentIfAvailable());
+ client.submit("test");
+ assertEquals(UserAgent.USER_AGENT, getUserAgentIfAvailable());
+ client.close();
+ cluster.close();
+ }
+ }
+
+ private String getUserAgentIfAvailable() {
+ final AttributeKey<String> userAgentAttrKey = AttributeKey.valueOf(UserAgent.USER_AGENT_HEADER_NAME);
+ if(!(server.getChannelizer() instanceof TestChannelizer)) {
+ return null;
+ }
+ final TestChannelizer channelizer = (TestChannelizer) server.getChannelizer();
+ final ChannelHandlerContext ctx = channelizer.getMostRecentChannelHandlerContext();
+ if(ctx == null || !ctx.channel().hasAttr(userAgentAttrKey)) {
+ return null;
+ }
+ return channelizer.getMostRecentChannelHandlerContext().channel().attr(userAgentAttrKey).get();
+ }
+
@Test
public void shouldBlowTheWorkQueueSize() throws Exception {
final Cluster cluster = TestClientFactory.open();