You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2017/03/24 17:27:32 UTC
[20/20] tinkerpop git commit: TINKERPOP-1095 Added a custom
ScriptContext
TINKERPOP-1095 Added a custom ScriptContext
Used the custom ScriptContext, GremlinScriptContext, to prevent usage of the SimpleScriptContext which creates unnecessary ByteBuffer instances on every call to eval().
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/48daf8d2
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/48daf8d2
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/48daf8d2
Branch: refs/heads/TINKERPOP-1095
Commit: 48daf8d25fcf3abb9d2a3c307e65ec6613595959
Parents: e3e1dca
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Mar 24 12:23:46 2017 -0400
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Mar 24 13:26:59 2017 -0400
----------------------------------------------------------------------
CHANGELOG.asciidoc | 9 +-
.../gremlin/jsr223/GremlinScriptContext.java | 234 +++++++++++++++++++
.../jsr223/GremlinGroovyScriptEngine.java | 22 ++
3 files changed, 261 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/48daf8d2/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index ed26f7a..e6216c0 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -32,10 +32,11 @@ TinkerPop 3.2.5 (Release Date: NOT OFFICIALLY RELEASED YET)
* Added various metrics to the `GremlinGroovyScriptEngine` around script compilation and exposed them in Gremlin Server.
* Moved the `caffeine` dependency down to `gremlin-groovy` and out of `gremlin-server`.
* Improved script compilation in `GremlinGroovyScriptEngine to use better caching, log long compile times and prevent failed compilations from recompiling on future requests.
-* Script compilation is synchronised.
-* Script compilation times are placed in to logs.
-* Failed scripts will not be recompiled.
-* Scripts that take over 5 seconds to compile are logged as a warning.
+* Synchronized script compilation.
+* Logged Script compilation times.
+* Prevented failed scripts from recompiling.
+* Logged warnings for scripts that take "too long" to compile.
+* Improved memory usage of the `GremlinGroovyScriptEngine`.
* Added `cyclicPath().from().to().by()` support to `GraphTraversal`.
* Added `simplePath().from().to().by()` support to `GraphTraversal`.
* Added `path().from().to()` support to `GraphTraversal` so sub-paths can be isolated from the current path.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/48daf8d2/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptContext.java
----------------------------------------------------------------------
diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptContext.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptContext.java
new file mode 100644
index 0000000..5f94225
--- /dev/null
+++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptContext.java
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+package org.apache.tinkerpop.gremlin.jsr223;
+
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.SimpleBindings;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A {@code ScriptContext} that doesn't create new instances of {@code Reader} and {@code Writer} classes on
+ * initialization.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GremlinScriptContext implements ScriptContext {
+
+ private Writer writer;
+ private Writer errorWriter;
+ private Reader reader;
+ private Bindings engineScope;
+ private Bindings globalScope;
+ private static List<Integer> scopes;
+
+ static {
+ scopes = new ArrayList<>(2);
+ scopes.add(ENGINE_SCOPE);
+ scopes.add(GLOBAL_SCOPE);
+ scopes = Collections.unmodifiableList(scopes);
+ }
+
+ /**
+ * Create a {@code GremlinScriptContext}.
+ */
+ public GremlinScriptContext(final Reader in, final Writer out, final Writer error) {
+ engineScope = new SimpleBindings();
+ globalScope = null;
+ reader = in;
+ writer = out;
+ errorWriter = error;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBindings(final Bindings bindings, final int scope) {
+ switch (scope) {
+ case ENGINE_SCOPE:
+ if (null == bindings) throw new NullPointerException("Engine scope cannot be null.");
+ engineScope = bindings;
+ break;
+ case GLOBAL_SCOPE:
+ globalScope = bindings;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid scope value.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getAttribute(final String name) {
+ checkName(name);
+ if (engineScope.containsKey(name)) {
+ return getAttribute(name, ENGINE_SCOPE);
+ } else if (globalScope != null && globalScope.containsKey(name)) {
+ return getAttribute(name, GLOBAL_SCOPE);
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getAttribute(final String name, final int scope) {
+ checkName(name);
+ switch (scope) {
+ case ENGINE_SCOPE:
+ return engineScope.get(name);
+ case GLOBAL_SCOPE:
+ return globalScope != null ? globalScope.get(name) : null;
+ default:
+ throw new IllegalArgumentException("Illegal scope value.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object removeAttribute(final String name, final int scope) {
+ checkName(name);
+ switch (scope) {
+ case ENGINE_SCOPE:
+ return getBindings(ENGINE_SCOPE) != null ? getBindings(ENGINE_SCOPE).remove(name) : null;
+ case GLOBAL_SCOPE:
+ return getBindings(GLOBAL_SCOPE) != null ? getBindings(GLOBAL_SCOPE).remove(name) : null;
+ default:
+ throw new IllegalArgumentException("Illegal scope value.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAttribute(final String name, final Object value, final int scope) {
+ checkName(name);
+ switch (scope) {
+ case ENGINE_SCOPE:
+ engineScope.put(name, value);
+ return;
+ case GLOBAL_SCOPE:
+ if (globalScope != null) globalScope.put(name, value);
+ return;
+ default:
+ throw new IllegalArgumentException("Illegal scope value.");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getAttributesScope(final String name) {
+ checkName(name);
+ if (engineScope.containsKey(name))
+ return ENGINE_SCOPE;
+ else if (globalScope != null && globalScope.containsKey(name))
+ return GLOBAL_SCOPE;
+ else
+ return -1;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Bindings getBindings(final int scope) {
+ if (scope == ENGINE_SCOPE)
+ return engineScope;
+ else if (scope == GLOBAL_SCOPE)
+ return globalScope;
+ else
+ throw new IllegalArgumentException("Illegal scope value.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<Integer> getScopes() {
+ return scopes;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Writer getWriter() {
+ return writer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Reader getReader() {
+ return reader;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setReader(final Reader reader) {
+ this.reader = reader;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setWriter(final Writer writer) {
+ this.writer = writer;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Writer getErrorWriter() {
+ return errorWriter;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setErrorWriter(final Writer writer) {
+ this.errorWriter = writer;
+ }
+
+ private void checkName(final String name) {
+ Objects.requireNonNull(name);
+ if (name.isEmpty()) throw new IllegalArgumentException("name cannot be empty");
+ }
+}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/48daf8d2/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 7a39f43..d52e104 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@ -44,6 +44,7 @@ import org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin;
import org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPluginException;
import org.apache.tinkerpop.gremlin.jsr223.CoreGremlinPlugin;
import org.apache.tinkerpop.gremlin.jsr223.Customizer;
+import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptContext;
import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine;
import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory;
import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer;
@@ -474,6 +475,27 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
}
/**
+ * Creates the {@code ScriptContext} using a {@link GremlinScriptContext} which avoids a significant amount of
+ * additional object creation on script evaluation.
+ */
+ @Override
+ protected ScriptContext getScriptContext(final Bindings nn) {
+ final GremlinScriptContext ctxt = new GremlinScriptContext(context.getReader(), context.getWriter(), context.getErrorWriter());
+ final Bindings gs = getBindings(ScriptContext.GLOBAL_SCOPE);
+
+ if (gs != null) ctxt.setBindings(gs, ScriptContext.GLOBAL_SCOPE);
+
+ if (nn != null) {
+ ctxt.setBindings(nn,
+ ScriptContext.ENGINE_SCOPE);
+ } else {
+ throw new NullPointerException("Engine scope Bindings may not be null.");
+ }
+
+ return ctxt;
+ }
+
+ /**
* Resets the {@code ScriptEngine} but does not clear the loaded plugins or bindings. Typically called by
* {@link DependencyManager} methods that need to just force the classloader to be recreated and script caches
* cleared.