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/15 16:36:51 UTC
[12/19] tinkerpop git commit: TINKERPOP-1644 Added metrics to
GremlinGroovyScriptEngine
TINKERPOP-1644 Added metrics to GremlinGroovyScriptEngine
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/8ffa5af6
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/8ffa5af6
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/8ffa5af6
Branch: refs/heads/tp32
Commit: 8ffa5af6ff56933c1955e88e8aa42c06cb69162b
Parents: a06072b
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Mar 9 10:30:17 2017 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Mar 10 11:13:03 2017 -0500
----------------------------------------------------------------------
CHANGELOG.asciidoc | 2 +
.../jsr223/GremlinGroovyScriptEngine.java | 122 ++++++++++++++++++-
...roovyScriptEngineCompilationOptionsTest.java | 8 +-
.../jsr223/GremlinGroovyScriptEngineTest.java | 70 ++++++++++-
4 files changed, 193 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ffa5af6/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 9c3313e..3729271 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,7 +26,9 @@ image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
TinkerPop 3.2.5 (Release Date: NOT OFFICIALLY RELEASED YET)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Added various metrics to the `GremlinGroovyScriptEngine` around script compilation.
* 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.
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ffa5af6/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 3bcb06c..0ed8d84 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
@@ -164,7 +164,10 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
/**
* Script to generated Class map.
*/
- private final LoadingCache<String, Future<Class>> classMap = Caffeine.newBuilder().softValues().build(new CacheLoader<String, Future<Class>>() {
+ private final LoadingCache<String, Future<Class>> classMap = Caffeine.newBuilder().
+ softValues().
+ recordStats().
+ build(new CacheLoader<String, Future<Class>>() {
@Override
public Future<Class> load(final String script) throws Exception {
final long start = System.currentTimeMillis();
@@ -175,6 +178,7 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
} catch (CompilationFailedException e) {
final long finish = System.currentTimeMillis();
log.error("Script compilation FAILED {} took {}ms {}", script, finish - start, e);
+ failedCompilationCount.incrementAndGet();
throw e;
} finally {
final long time = System.currentTimeMillis() - start;
@@ -208,6 +212,13 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
private final AtomicLong longRunCompilationCount = new AtomicLong(0L);
/**
+ * A counter for the instance that tracks the number of failed compilations. Note that the failures need to be
+ * tracked outside of cache failure load stats because the loading mechanism will always successfully return
+ * a future and won't trigger a failure.
+ */
+ private final AtomicLong failedCompilationCount = new AtomicLong(0L);
+
+ /**
* The list of loaded plugins for the console.
*/
private final Set<String> loadedPlugins = new HashSet<>();
@@ -589,10 +600,117 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl
/**
* Gets the number of compilations that extended beyond the {@link #expectedCompilationTime}.
*/
- public long getLongRunCompilationCount() {
+ public long getClassCacheLongRunCompilationCount() {
return longRunCompilationCount.longValue();
}
+ /**
+ * Gets the estimated size of the class cache for compiled scripts.
+ */
+ public long getClassCacheEstimatedSize() {
+ return classMap.estimatedSize();
+ }
+
+ /**
+ * Gets the average time spent compiling new scripts.
+ */
+ public double getClassCacheAverageLoadPenalty() {
+ return classMap.stats().averageLoadPenalty();
+ }
+
+ /**
+ * Gets the number of times a script compiled to a class has been evicted from the cache.
+ */
+ public long getClassCacheEvictionCount() {
+ return classMap.stats().evictionCount();
+ }
+
+ /**
+ * Gets the sum of the weights of evicted entries from the class cache.
+ */
+ public long getClassCacheEvictionWeight() {
+ return classMap.stats().evictionWeight();
+ }
+
+ /**
+ * Gets the number of times cache look up for a compiled script returned a cached value.
+ */
+ public long getClassCacheHitCount() {
+ return classMap.stats().hitCount();
+ }
+
+ /**
+ * Gets the hit rate of the class cache.
+ */
+ public double getClassCacheHitRate() {
+ return classMap.stats().hitRate();
+ }
+
+ /**
+ * Gets the total number of times the cache lookup method attempted to compile new scripts.
+ */
+ public long getClassCacheLoadCount() {
+ return classMap.stats().loadCount();
+ }
+
+ /**
+ * Gets the total number of times the cache lookup method failed to compile a new script.
+ */
+ public long getClassCacheLoadFailureCount() {
+ // don't use classMap.stats().loadFailureCount() because the load mechanism always succeeds with a future
+ // that will in turn contain the success or failure
+ return failedCompilationCount.longValue();
+ }
+
+ /**
+ * Gets the ratio of script compilation attempts that failed.
+ */
+ public double getClassCacheLoadFailureRate() {
+ // don't use classMap.stats().loadFailureRate() because the load mechanism always succeeds with a future
+ // that will in turn contain the success or failure
+ long totalLoadCount = classMap.stats().loadCount();
+ return (totalLoadCount == 0)
+ ? 0.0
+ : (double) failedCompilationCount.longValue() / totalLoadCount;
+ }
+
+ /**
+ * Gets the total number of times the cache lookup method succeeded to compile a new script.
+ */
+ public long getClassCacheLoadSuccessCount() {
+ // don't use classMap.stats().loadSuccessCount() because the load mechanism always succeeds with a future
+ // that will in turn contain the success or failure
+ return classMap.stats().loadCount() - failedCompilationCount.longValue();
+ }
+
+ /**
+ * Gets the total number of times the cache lookup method returned a newly compiled script.
+ */
+ public long getClassCacheMissCount() {
+ return classMap.stats().missCount();
+ }
+
+ /**
+ * Gets the ratio of script compilation attempts that were misses.
+ */
+ public double getClassCacheMissRate() {
+ return classMap.stats().missRate();
+ }
+
+ /**
+ * Gets the total number of times the cache lookup method returned a cached or uncached value.
+ */
+ public long getClassCacheRequestCount() {
+ return classMap.stats().missCount();
+ }
+
+ /**
+ * Gets the total number of nanoseconds that the cache spent compiling scripts.
+ */
+ public long getClassCacheTotalLoadTime() {
+ return classMap.stats().totalLoadTime();
+ }
+
Class getScriptClass(final String script) throws CompilationFailedException {
try {
return classMap.get(script).get();
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ffa5af6/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompilationOptionsTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompilationOptionsTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompilationOptionsTest.java
index f5dd9c5..b87d0ac 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompilationOptionsTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineCompilationOptionsTest.java
@@ -47,11 +47,11 @@ public class GremlinGroovyScriptEngineCompilationOptionsTest {
b.put("x" + ix, ix);
}
- assertEquals(0, engine.getLongRunCompilationCount());
+ assertEquals(0, engine.getClassCacheLongRunCompilationCount());
engine.eval(script, b);
- assertEquals(1, engine.getLongRunCompilationCount());
+ assertEquals(1, engine.getClassCacheLongRunCompilationCount());
}
@Test
@@ -71,10 +71,10 @@ public class GremlinGroovyScriptEngineCompilationOptionsTest {
b.put("x" + ix, ix);
}
- assertEquals(0, engine.getLongRunCompilationCount());
+ assertEquals(0, engine.getClassCacheLongRunCompilationCount());
engine.eval(script, b);
- assertEquals(1, engine.getLongRunCompilationCount());
+ assertEquals(1, engine.getClassCacheLongRunCompilationCount());
}
}
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/8ffa5af6/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
index eb0a44b..0606721 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -497,7 +497,7 @@ public class GremlinGroovyScriptEngineTest {
}
@Test
- public void testInvokeFunctionRedirectsOutputToContextOut() throws Exception {
+ public void shouldInvokeFunctionRedirectsOutputToContextOut() throws Exception {
final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
StringWriter writer = new StringWriter();
final StringWriter unusedWriter = new StringWriter();
@@ -520,7 +520,7 @@ public class GremlinGroovyScriptEngineTest {
}
@Test
- public void testEngineContextAccessibleToScript() throws Exception {
+ public void shouldEnableEngineContextAccessibleToScript() throws Exception {
final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
final ScriptContext engineContext = engine.getContext();
engine.put("theEngineContext", engineContext);
@@ -529,7 +529,7 @@ public class GremlinGroovyScriptEngineTest {
}
@Test
- public void testContextBindingOverridesEngineContext() throws Exception {
+ public void shouldEnableContextBindingOverridesEngineContext() throws Exception {
final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
final ScriptContext engineContext = engine.getContext();
final Map<String,Object> otherContext = new HashMap<>();
@@ -539,4 +539,68 @@ public class GremlinGroovyScriptEngineTest {
final String code = "[answer: context.is(theEngineContext) ? \"wrong\" : context.foo]";
assertEquals("bar", ((Map) engine.eval(code)).get("answer"));
}
+
+ @Test
+ public void shouldGetClassMapCacheBasicStats() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+ assertEquals(0, engine.getClassCacheEstimatedSize());
+ assertEquals(0, engine.getClassCacheHitCount());
+ assertEquals(0, engine.getClassCacheLoadCount());
+ assertEquals(0, engine.getClassCacheLoadFailureCount());
+ assertEquals(0, engine.getClassCacheLoadSuccessCount());
+
+ engine.eval("1+1");
+
+ assertEquals(1, engine.getClassCacheEstimatedSize());
+ assertEquals(0, engine.getClassCacheHitCount());
+ assertEquals(1, engine.getClassCacheLoadCount());
+ assertEquals(0, engine.getClassCacheLoadFailureCount());
+ assertEquals(1, engine.getClassCacheLoadSuccessCount());
+
+ for (int ix = 0; ix < 100; ix++) {
+ engine.eval("1+1");
+ }
+
+ assertEquals(1, engine.getClassCacheEstimatedSize());
+ assertEquals(100, engine.getClassCacheHitCount());
+ assertEquals(1, engine.getClassCacheLoadCount());
+ assertEquals(0, engine.getClassCacheLoadFailureCount());
+ assertEquals(1, engine.getClassCacheLoadSuccessCount());
+
+ for (int ix = 0; ix < 100; ix++) {
+ engine.eval("1+" + ix);
+ }
+
+ assertEquals(100, engine.getClassCacheEstimatedSize());
+ assertEquals(101, engine.getClassCacheHitCount());
+ assertEquals(100, engine.getClassCacheLoadCount());
+ assertEquals(0, engine.getClassCacheLoadFailureCount());
+ assertEquals(100, engine.getClassCacheLoadSuccessCount());
+
+ try {
+ engine.eval("(me broken");
+ fail("Should have tanked with compilation error");
+ } catch (Exception ex) {
+ assertThat(ex, instanceOf(ScriptException.class));
+ }
+
+ assertEquals(101, engine.getClassCacheEstimatedSize());
+ assertEquals(101, engine.getClassCacheHitCount());
+ assertEquals(101, engine.getClassCacheLoadCount());
+ assertEquals(1, engine.getClassCacheLoadFailureCount());
+ assertEquals(100, engine.getClassCacheLoadSuccessCount());
+
+ try {
+ engine.eval("(me broken");
+ fail("Should have tanked with compilation error");
+ } catch (Exception ex) {
+ assertThat(ex, instanceOf(ScriptException.class));
+ }
+
+ assertEquals(101, engine.getClassCacheEstimatedSize());
+ assertEquals(102, engine.getClassCacheHitCount());
+ assertEquals(101, engine.getClassCacheLoadCount());
+ assertEquals(1, engine.getClassCacheLoadFailureCount());
+ assertEquals(100, engine.getClassCacheLoadSuccessCount());
+ }
}
\ No newline at end of file