This is an automated email from the ASF dual-hosted git repository. colegreer pushed a commit to branch TINKERPOP-3107 in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
commit b1fce1ff3c9ed1b5718ac98e4fee1b3d8de31ea5 Author: Cole Greer <[email protected]> AuthorDate: Tue Apr 14 12:52:02 2026 -0700 cleanups and fixes --- docs/src/reference/gremlin-applications.asciidoc | 40 +++++------ docs/src/upgrade/release-4.x.x.asciidoc | 6 +- .../gremlin/server/util/ServerGremlinExecutor.java | 15 ++--- .../server/GremlinServerConfigIntegrateTest.java | 22 +------ .../server/util/ServerGremlinExecutorTest.java | 77 ++++++++++++++-------- 5 files changed, 80 insertions(+), 80 deletions(-) diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc index 412612b42a..1d0d0a0c96 100644 --- a/docs/src/reference/gremlin-applications.asciidoc +++ b/docs/src/reference/gremlin-applications.asciidoc @@ -444,22 +444,22 @@ $ bin/gremlin-server.sh conf/gremlin-server-modern.yaml (o o) -----oOOo-(4)-oOOo----- -[INFO] GremlinServer - Configuring Gremlin Server from conf/gremlin-server-modern.yaml -[INFO] MetricManager - Configured Metrics Slf4jReporter configured with interval=180000ms and loggerName=org.apache.tinkerpop.gremlin.server.Settings$Slf4jReporterMetrics -[INFO] DefaultGraphManager - Graph [graph] was successfully configured via [conf/tinkergraph-empty.properties]. -[INFO] ServerGremlinExecutor - Initialized Gremlin thread pool. Threads in pool named with pattern gremlin-* -[INFO] ServerGremlinExecutor - Initialized GremlinExecutor and preparing GremlinScriptEngines instances. -[INFO] ServerGremlinExecutor - A GraphTraversalSource is now auto-bound to [g] for graph [graph] -[INFO] ServerGremlinExecutor - Instantiated LifeCycleHook: org.apache.tinkerpop.gremlin.server.util.TinkerFactoryDataLoader -[INFO] GremlinServer - Executing start up LifeCycleHook -[INFO] TinkerFactoryDataLoader - TinkerFactoryDataLoader loaded [modern] dataset into graph [graph] -[INFO] GremlinServer - idleConnectionTimeout was set to 0 which resolves to 0 seconds when configuring this value - this feature will be disabled -[INFO] GremlinServer - keepAliveInterval was set to 0 which resolves to 0 seconds when configuring this value - this feature will be disabled -[INFO] AbstractChannelizer - Configured application/vnd.gremlin-v4.0+json with org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV4 -[INFO] AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV4 -[INFO] AbstractChannelizer - Configured application/vnd.graphbinary-v4.0 with org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4 -[INFO] GremlinServer$1 - Gremlin Server configured with worker thread pool of 1, gremlin pool of 4 and boss thread pool of 1. -[INFO] GremlinServer$1 - Channel started at port 8182. +[INFO] o.a.t.g.s.GremlinServer - Configuring Gremlin Server from conf/gremlin-server-modern.yaml +[INFO] o.a.t.g.s.u.MetricManager - Configured Metrics Slf4jReporter configured with interval=180000ms and loggerName=org.apache.tinkerpop.gremlin.server.Settings$Slf4jReporterMetrics +[INFO] o.a.t.g.s.u.DefaultGraphManager - Graph [graph] was successfully configured via [conf/tinkergraph-empty.properties]. +[INFO] o.a.t.g.s.u.ServerGremlinExecutor - Initialized Gremlin thread pool. Threads in pool named with pattern gremlin-* +[INFO] o.a.t.g.s.u.ServerGremlinExecutor - Initialized GremlinExecutor and preparing GremlinScriptEngines instances. +[INFO] o.a.t.g.s.u.ServerGremlinExecutor - Initialized gremlin-lang GremlinScriptEngine and registered metrics +[INFO] o.a.t.g.s.u.ServerGremlinExecutor - A GraphTraversalSource is now auto-bound to [g] for graph [graph] +[INFO] o.a.t.g.s.u.ServerGremlinExecutor - Instantiated LifeCycleHook: org.apache.tinkerpop.gremlin.server.util.TinkerFactoryDataLoader +[INFO] o.a.t.g.s.h.TransactionManager - TransactionManager initialized with timeout=600000ms, maxTransactions=1000 +[INFO] o.a.t.g.s.GremlinServer - Executing start up LifeCycleHook +[INFO] o.a.t.g.s.u.TinkerFactoryDataLoader - TinkerFactoryDataLoader loaded [modern] dataset into graph [graph] +[INFO] o.a.t.g.s.AbstractChannelizer - Configured application/vnd.gremlin-v4.0+json with org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV4 +[INFO] o.a.t.g.s.AbstractChannelizer - Configured application/json with org.apache.tinkerpop.gremlin.util.ser.GraphSONMessageSerializerV4 +[INFO] o.a.t.g.s.AbstractChannelizer - Configured application/vnd.graphbinary-v4.0 with org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4 +[INFO] o.a.t.g.s.GremlinServer - Gremlin Server configured with worker thread pool of 1, gremlin pool of 10 and boss thread pool of 1. +[INFO] o.a.t.g.s.GremlinServer - Channel started at port 8182. ---- Gremlin Server is configured by the provided link:http://www.yaml.org/[YAML] file `conf/gremlin-server-modern.yaml`. @@ -505,7 +505,7 @@ strategy configuration via a Gremlin query: ---- traversalSources: { g: {graph: graph}, - gReadOnly: {graph: graph, query: "g.withStrategies(ReadOnlyStrategy)"}} + gReadOnly: {graph: graph, query: "g.withStrategies(ReadOnlyStrategy)", language: "gremlin-lang"}} ---- Each entry supports: @@ -513,8 +513,8 @@ Each entry supports: * `graph` (required) — references a key in the `graphs` section * `query` (optional) — a Gremlin expression evaluated with a base traversal source bound as `g`; the result becomes the final `TraversalSource` -* `language` (optional) — which script engine to use for query evaluation; defaults to `gremlin-lang` or the single - configured non-`gremlin-lang` engine +* `language` (optional) — which script engine to use for query evaluation; defaults to `gremlin-lang`, or the sole + configured engine if only one is present Graphs with explicit `traversalSources` entries are excluded from auto-creation. @@ -899,7 +899,7 @@ The following table describes the various YAML configuration options that Gremli |traversalSources |A `Map` of `TraversalSource` configurations keyed by binding name. Each entry specifies a `graph` reference and optionally a `query` to configure strategies. See <<server-traversal-sources>>. |_none (auto-created from graphs)_ |traversalSources.<name>.graph |The name of the graph (as defined in `graphs`) to create the traversal source from. |_none_ |traversalSources.<name>.query |An optional Gremlin query evaluated with a base traversal source bound as `g`. The result becomes the final `TraversalSource`. |_none_ -|traversalSources.<name>.language |The script engine language to use for evaluating `query`. Falls back to the single configured non-`gremlin-lang` engine or `gremlin-lang`. |_auto-detected_ +|traversalSources.<name>.language |The script engine language to use for evaluating `query`. Falls back to the sole configured engine if only one is present, or `gremlin-lang` otherwise. |_auto-detected_ |lifecycleHooks |A `List` of Java-based `LifeCycleHook` implementations to instantiate and execute during server startup and shutdown. See <<server-lifecycle-hooks>>. |_none_ |lifecycleHooks[X].className |The fully qualified class name of the `LifeCycleHook` implementation. |_none_ |lifecycleHooks[X].config |A `Map` of configuration passed to the hook's `init(Map)` method. |_none_ diff --git a/docs/src/upgrade/release-4.x.x.asciidoc b/docs/src/upgrade/release-4.x.x.asciidoc index c7c13e021b..6cd0fdabd4 100644 --- a/docs/src/upgrade/release-4.x.x.asciidoc +++ b/docs/src/upgrade/release-4.x.x.asciidoc @@ -61,15 +61,15 @@ A new `traversalSources` YAML section allows explicit `TraversalSource` creation ---- traversalSources: { g: {graph: graph}, - gReadOnly: {graph: graph, query: "g.withStrategies(ReadOnlyStrategy)"}} + gReadOnly: {graph: graph, query: "g.withStrategies(ReadOnlyStrategy)", language: "gremlin-lang"}} ---- Each entry specifies: - `graph` (required) — references a key in the `graphs` section - `query` (optional) — a Gremlin expression evaluated with a base traversal source bound as `g` -- `language` (optional) — which script engine to use for the query (defaults to `gremlin-lang`, or the single - configured non-`gremlin-lang` engine if only one exists) +- `language` (optional) — which script engine to use for the query (defaults to `gremlin-lang`, or the sole + configured engine if only one is present) ===== Java-Based `lifecycleHooks` diff --git a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java index f3970b7a92..8f8b88e9a8 100644 --- a/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java +++ b/gremlin-server/src/main/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutor.java @@ -235,10 +235,8 @@ public class ServerGremlinExecutor { // bind a base traversal source as 'g' for the query to operate on final SimpleBindings bindings = new SimpleBindings(); bindings.put("g", graph.traversal()); - final GremlinExecutor.LifeCycle lifeCycle = GremlinExecutor.LifeCycle.build() - .evaluationTimeoutOverride(0L).create(); final TraversalSource ts = (TraversalSource) gremlinExecutor.eval( - tsSettings.query, language, bindings, lifeCycle).join(); + tsSettings.query, language, bindings).join(); this.graphManager.putTraversalSource(tsName, ts); logger.info("A {} is now bound to [{}] via query", ts.getClass().getSimpleName(), tsName); } catch (Exception ex) { @@ -309,18 +307,15 @@ public class ServerGremlinExecutor { /** * Resolves the script engine language to use for evaluating a traversal source query. If an explicit language - * is provided, it is used directly. Otherwise, if only one non-{@code gremlin-lang} script engine is configured, - * that engine is used. Falls back to {@code gremlin-lang}. + * is provided, it is used directly. Otherwise, if exactly one script engine is configured, that engine is used. + * Falls back to {@code gremlin-lang}. */ private String resolveLanguage(final String explicitLanguage) { if (explicitLanguage != null && !explicitLanguage.isEmpty()) return explicitLanguage; - final List<String> nonLangEngines = settings.scriptEngines.keySet().stream() - .filter(name -> !name.equals("gremlin-lang")) - .collect(Collectors.toList()); - if (nonLangEngines.size() == 1) - return nonLangEngines.get(0); + if (settings.scriptEngines.size() == 1) + return settings.scriptEngines.keySet().iterator().next(); return "gremlin-lang"; } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerConfigIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerConfigIntegrateTest.java index 647bbba964..38e89cbddb 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerConfigIntegrateTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerConfigIntegrateTest.java @@ -22,7 +22,6 @@ import org.apache.tinkerpop.gremlin.driver.Client; import org.apache.tinkerpop.gremlin.driver.Cluster; import org.apache.tinkerpop.gremlin.driver.Result; import org.apache.tinkerpop.gremlin.tinkergraph.structure.AbstractTinkerGraph; -import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -31,9 +30,9 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; @@ -47,7 +46,6 @@ import static org.hamcrest.Matchers.is; public class GremlinServerConfigIntegrateTest { private static final Logger logger = LoggerFactory.getLogger(GremlinServerConfigIntegrateTest.class); - private static final int TEST_PORT = 45950; @Parameterized.Parameter public String configName; @@ -70,24 +68,15 @@ public class GremlinServerConfigIntegrateTest { final File confDir = new File(System.getProperty("build.dir"), "../conf"); final Settings settings = Settings.read(new FileInputStream(new File(confDir, configName))); - settings.port = TEST_PORT; + settings.serializers = Collections.emptyList(); ServerTestHelper.rewritePathsInGremlinServerSettings(settings); - // ensure a V4 serializer is available so the V4 client can connect - if (!hasV4Serializer(settings)) { - final Settings.SerializerSettings v4 = new Settings.SerializerSettings(); - v4.className = GraphBinaryMessageSerializerV4.class.getName(); - final List<Settings.SerializerSettings> serializers = new ArrayList<>(settings.serializers); - serializers.add(v4); - settings.serializers = serializers; - } - final GremlinServer server = new GremlinServer(settings); try { server.start().join(); logger.info("Started server with config: {}", configName); - final Cluster cluster = Cluster.build("localhost").port(TEST_PORT).create(); + final Cluster cluster = Cluster.build("localhost").port(settings.port).create(); final Client client = cluster.connect(); try { final List<Result> results = client.submit("g.inject(1)").all().get(); @@ -104,9 +93,4 @@ public class GremlinServerConfigIntegrateTest { server.stop().join(); } } - - private static boolean hasV4Serializer(final Settings settings) { - return settings.serializers.stream() - .anyMatch(s -> s.className.contains("V4")); - } } diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutorTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutorTest.java index 03320268f7..489d4a6a5f 100644 --- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutorTest.java +++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/util/ServerGremlinExecutorTest.java @@ -22,11 +22,10 @@ import org.apache.tinkerpop.gremlin.server.Settings; import org.junit.After; import org.junit.Test; -import java.io.InputStream; import java.lang.reflect.Method; -import java.util.HashMap; +import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; @@ -35,6 +34,10 @@ import static org.hamcrest.Matchers.nullValue; public class ServerGremlinExecutorTest { + private static final String TINKERGRAPH_PROPERTIES = + new java.io.File(System.getProperty("build.dir"), "../src/test/scripts/tinkergraph-empty.properties") + .getAbsolutePath(); + private ServerGremlinExecutor serverGremlinExecutor; @After @@ -50,48 +53,59 @@ public class ServerGremlinExecutorTest { } } - private Settings readSettings(final String resource) { - final InputStream stream = ServerGremlinExecutorTest.class.getResourceAsStream("../" + resource); - final Settings settings = Settings.read(stream); + private Settings baseSettings() { + final Settings settings = new Settings(); + settings.graphs.put("graph", TINKERGRAPH_PROPERTIES); settings.gremlinPool = 1; return settings; } @Test public void shouldAutoCreateTraversalSourceForSingleGraph() { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); - serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); + serverGremlinExecutor = new ServerGremlinExecutor(baseSettings(), null, null); - // graph named "graph" should auto-create traversal source named "g" assertThat(serverGremlinExecutor.getGraphManager().getTraversalSource("g"), is(notNullValue())); } @Test public void shouldAutoCreateTraversalSourceWithPrefixForNonDefaultGraph() { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); - settings.graphs.put("myGraph", settings.graphs.get("graph")); + final Settings settings = baseSettings(); + settings.graphs.put("myGraph", TINKERGRAPH_PROPERTIES); serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); - // "graph" -> "g", "myGraph" -> "g_myGraph" assertThat(serverGremlinExecutor.getGraphManager().getTraversalSource("g"), is(notNullValue())); assertThat(serverGremlinExecutor.getGraphManager().getTraversalSource("g_myGraph"), is(notNullValue())); } @Test public void shouldNotAutoCreateTraversalSourceWhenExplicitEntryExists() { - final Settings settings = readSettings("gremlin-server-with-traversal-sources.yaml"); - // this YAML has explicit traversalSources for "g" referencing "graph" + final Settings settings = baseSettings(); + final Settings.TraversalSourceSettings tsSettings = new Settings.TraversalSourceSettings(); + tsSettings.graph = "graph"; + settings.traversalSources.put("g", tsSettings); serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); - // "g" should exist from the explicit config assertThat(serverGremlinExecutor.getGraphManager().getTraversalSource("g"), is(notNullValue())); - // "g_graph" should NOT exist because "graph" had an explicit traversalSources entry assertThat(serverGremlinExecutor.getGraphManager().getTraversalSource("g_graph"), is(nullValue())); } @Test public void shouldInstantiateLifecycleHooksFromYaml() { - final Settings settings = readSettings("gremlin-server-with-traversal-sources.yaml"); + final Settings settings = baseSettings(); + final Settings.LifeCycleHookSettings hook1 = new Settings.LifeCycleHookSettings(); + hook1.className = TinkerFactoryDataLoader.class.getName(); + hook1.config = new LinkedHashMap<>(); + hook1.config.put("graph", "graph"); + hook1.config.put("dataset", "modern"); + final Settings.LifeCycleHookSettings hook2 = new Settings.LifeCycleHookSettings(); + hook2.className = TinkerFactoryDataLoader.class.getName(); + hook2.config = new LinkedHashMap<>(); + hook2.config.put("graph", "graph"); + hook2.config.put("dataset", "classic"); + final List<Settings.LifeCycleHookSettings> hooks = new ArrayList<>(); + hooks.add(hook1); + hooks.add(hook2); + settings.lifecycleHooks = hooks; serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); assertThat(serverGremlinExecutor.getHooks().size(), is(2)); @@ -101,17 +115,14 @@ public class ServerGremlinExecutorTest { @Test public void shouldHaveEmptyHooksWhenNoneConfigured() { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); - settings.lifecycleHooks.clear(); - serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); + serverGremlinExecutor = new ServerGremlinExecutor(baseSettings(), null, null); assertThat(serverGremlinExecutor.getHooks().isEmpty(), is(true)); } @Test public void resolveLanguageShouldReturnExplicitLanguage() throws Exception { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); - serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); + serverGremlinExecutor = new ServerGremlinExecutor(baseSettings(), null, null); final Method resolveLanguage = ServerGremlinExecutor.class.getDeclaredMethod("resolveLanguage", String.class); resolveLanguage.setAccessible(true); @@ -121,9 +132,7 @@ public class ServerGremlinExecutorTest { @Test public void resolveLanguageShouldFallBackToGremlinLangWhenNoExplicitLanguage() throws Exception { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); - // minimal YAML has no scriptEngines, so constructor default is just gremlin-lang - serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); + serverGremlinExecutor = new ServerGremlinExecutor(baseSettings(), null, null); final Method resolveLanguage = ServerGremlinExecutor.class.getDeclaredMethod("resolveLanguage", String.class); resolveLanguage.setAccessible(true); @@ -133,15 +142,27 @@ public class ServerGremlinExecutorTest { } @Test - public void resolveLanguageShouldUseSingleNonLangEngine() throws Exception { - final Settings settings = readSettings("gremlin-server-minimal.yaml"); + public void resolveLanguageShouldFallBackToGremlinLangWhenMultipleEngines() throws Exception { + final Settings settings = baseSettings(); + settings.scriptEngines.put("gremlin-groovy", new Settings.ScriptEngineSettings()); + serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); + + final Method resolveLanguage = ServerGremlinExecutor.class.getDeclaredMethod("resolveLanguage", String.class); + resolveLanguage.setAccessible(true); + + assertThat(resolveLanguage.invoke(serverGremlinExecutor, (String) null), is("gremlin-lang")); + } + + @Test + public void resolveLanguageShouldUseSoleConfiguredEngine() throws Exception { + final Settings settings = baseSettings(); + settings.scriptEngines.clear(); settings.scriptEngines.put("gremlin-groovy", new Settings.ScriptEngineSettings()); serverGremlinExecutor = new ServerGremlinExecutor(settings, null, null); final Method resolveLanguage = ServerGremlinExecutor.class.getDeclaredMethod("resolveLanguage", String.class); resolveLanguage.setAccessible(true); - // with one non-gremlin-lang engine configured, should resolve to it assertThat(resolveLanguage.invoke(serverGremlinExecutor, (String) null), is("gremlin-groovy")); } }
