Merge lp:~mmcm/akiban-server/script-invoker-pool into lp:~akiban-technologies/akiban-server/trunk

Proposed by Mike McMahon
Status: Merged
Approved by: Nathan Williams
Approved revision: 2620
Merged at revision: 2620
Proposed branch: lp:~mmcm/akiban-server/script-invoker-pool
Merge into: lp:~akiban-technologies/akiban-server/trunk
Diff against target: 460 lines (+171/-79)
8 files modified
src/main/java/com/akiban/server/service/restdml/DirectServiceImpl.java (+23/-6)
src/main/java/com/akiban/server/service/routines/RoutineLoader.java (+1/-0)
src/main/java/com/akiban/server/service/routines/RoutineLoaderImpl.java (+5/-0)
src/main/java/com/akiban/server/service/routines/ScriptCache.java (+107/-68)
src/main/java/com/akiban/server/service/routines/ScriptInvoker.java (+1/-3)
src/main/java/com/akiban/server/service/routines/ScriptLibrary.java (+25/-0)
src/main/java/com/akiban/sql/script/ScriptFunctionJavaRoutine.java (+4/-2)
src/test/java/com/akiban/server/service/routines/MockRoutineLoader.java (+5/-0)
To merge this branch: bzr merge lp:~mmcm/akiban-server/script-invoker-pool
Reviewer Review Type Date Requested Status
Nathan Williams Approve
Review via email: mp+158507@code.launchpad.net

Description of the change

Clean up ScriptInvoker as mentioned in lp:~pbeaman/akiban-server/direct-param-handling/+merge/156711/comments/343411

Now distinguishes the invoker proper from the library from which it comes. There are still no cases where more than one routine comes from the same library (a functional calling convention has one and a direct module has zero), but the pool itself now supports it, pooling the big ScriptEngine/Invocable once for all.

To post a comment you must log in.
Revision history for this message
Nathan Williams (nwilliams) wrote :

Looks plausible.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/main/java/com/akiban/server/service/restdml/DirectServiceImpl.java'
--- src/main/java/com/akiban/server/service/restdml/DirectServiceImpl.java 2013-04-11 00:14:28 +0000
+++ src/main/java/com/akiban/server/service/restdml/DirectServiceImpl.java 2013-04-11 23:35:24 +0000
@@ -62,7 +62,8 @@
62import com.akiban.server.service.restdml.EndpointMetadata.ParamMetadata;62import com.akiban.server.service.restdml.EndpointMetadata.ParamMetadata;
63import com.akiban.server.service.restdml.EndpointMetadata.Tokenizer;63import com.akiban.server.service.restdml.EndpointMetadata.Tokenizer;
64import com.akiban.server.service.routines.RoutineLoader;64import com.akiban.server.service.routines.RoutineLoader;
65import com.akiban.server.service.routines.ScriptInvoker;65import com.akiban.server.service.routines.ScriptLibrary;
66import com.akiban.server.service.routines.ScriptPool;
66import com.akiban.server.service.security.SecurityService;67import com.akiban.server.service.security.SecurityService;
67import com.akiban.server.service.session.Session;68import com.akiban.server.service.session.Session;
68import com.akiban.server.types3.Attribute;69import com.akiban.server.types3.Attribute;
@@ -394,9 +395,19 @@
394395
395 final Object[] args = createArgsArray(pathParams, queryParameters, content, cache, md);396 final Object[] args = createArgsArray(pathParams, queryParameters, content, cache, md);
396397
397 final ScriptInvoker invoker = conn.getRoutineLoader()398 final ScriptPool<ScriptLibrary> libraryPool = conn.getRoutineLoader()
398 .getScriptInvoker(conn.getSession(), new TableName(procName.getSchemaName(), md.routineName)).get();399 .getScriptLibrary(conn.getSession(), new TableName(procName.getSchemaName(),
399 Object result = invoker.invokeNamedFunction(md.function, args);400 md.routineName));
401 final ScriptLibrary library = libraryPool.get();
402 boolean success = false;
403 Object result;
404 try {
405 result = library.invoke(md.function, args);
406 success = true;
407 }
408 finally {
409 libraryPool.put(library, success);
410 }
400411
401 switch (md.outParam.type) {412 switch (md.outParam.type) {
402413
@@ -529,9 +540,11 @@
529 for (final Routine routine : ais.getRoutines().values()) {540 for (final Routine routine : ais.getRoutines().values()) {
530 if (routine.getCallingConvention().equals(CallingConvention.SCRIPT_LIBRARY)541 if (routine.getCallingConvention().equals(CallingConvention.SCRIPT_LIBRARY)
531 && routine.getDynamicResultSets() == 0 && routine.getParameters().isEmpty()) {542 && routine.getDynamicResultSets() == 0 && routine.getParameters().isEmpty()) {
543 final ScriptPool<ScriptLibrary> libraryPool = routineLoader.getScriptLibrary(session, routine.getName());
544 final ScriptLibrary library = libraryPool.get();
545 boolean success = false;
532 try {546 try {
533 final ScriptInvoker invoker = routineLoader.getScriptInvoker(session, routine.getName()).get();547 library.invoke(DISTINGUISHED_REGISTRATION_METHOD_NAME,
534 invoker.invokeNamedFunction(DISTINGUISHED_REGISTRATION_METHOD_NAME,
535 new Object[] { new RestFunctionRegistrar() {548 new Object[] { new RestFunctionRegistrar() {
536 @Override549 @Override
537 public void register(String specification) throws Exception {550 public void register(String specification) throws Exception {
@@ -539,9 +552,11 @@
539 .getTableName(), specification);552 .getTableName(), specification);
540 }553 }
541 } });554 } });
555 success = true;
542 } catch (ExternalRoutineInvocationException e) {556 } catch (ExternalRoutineInvocationException e) {
543 if (e.getCause() instanceof NoSuchMethodException) {557 if (e.getCause() instanceof NoSuchMethodException) {
544 LOG.warn("Script library " + routine.getName() + " has no _register function");558 LOG.warn("Script library " + routine.getName() + " has no _register function");
559 success = true;
545 return;560 return;
546 }561 }
547 Throwable previous = e;562 Throwable previous = e;
@@ -557,6 +572,8 @@
557 throw e;572 throw e;
558 } catch (Exception e) {573 } catch (Exception e) {
559 throw new RegistrationException(e);574 throw new RegistrationException(e);
575 } finally {
576 libraryPool.put(library, success);
560 }577 }
561 }578 }
562 }579 }
563580
=== modified file 'src/main/java/com/akiban/server/service/routines/RoutineLoader.java'
--- src/main/java/com/akiban/server/service/routines/RoutineLoader.java 2013-03-22 20:05:57 +0000
+++ src/main/java/com/akiban/server/service/routines/RoutineLoader.java 2013-04-11 23:35:24 +0000
@@ -33,5 +33,6 @@
33 public boolean isScriptLanguage(Session session, String language);33 public boolean isScriptLanguage(Session session, String language);
34 public ScriptPool<ScriptEvaluator> getScriptEvaluator(Session session, TableName routineName);34 public ScriptPool<ScriptEvaluator> getScriptEvaluator(Session session, TableName routineName);
35 public ScriptPool<ScriptInvoker> getScriptInvoker(Session session, TableName routineName);35 public ScriptPool<ScriptInvoker> getScriptInvoker(Session session, TableName routineName);
36 public ScriptPool<ScriptLibrary> getScriptLibrary(Session session, TableName routineName);
36 public void unloadRoutine(Session session, TableName routineName);37 public void unloadRoutine(Session session, TableName routineName);
37}38}
3839
=== modified file 'src/main/java/com/akiban/server/service/routines/RoutineLoaderImpl.java'
--- src/main/java/com/akiban/server/service/routines/RoutineLoaderImpl.java 2013-03-22 20:05:57 +0000
+++ src/main/java/com/akiban/server/service/routines/RoutineLoaderImpl.java 2013-04-11 23:35:24 +0000
@@ -194,6 +194,11 @@
194 }194 }
195195
196 @Override196 @Override
197 public ScriptPool<ScriptLibrary> getScriptLibrary(Session session, TableName routineName) {
198 return scripts.getScriptLibrary(session, routineName);
199 }
200
201 @Override
197 public void unloadRoutine(Session session, TableName routineName) {202 public void unloadRoutine(Session session, TableName routineName) {
198 synchronized (loadablePlans) {203 synchronized (loadablePlans) {
199 loadablePlans.remove(routineName);204 loadablePlans.remove(routineName);
200205
=== modified file 'src/main/java/com/akiban/server/service/routines/ScriptCache.java'
--- src/main/java/com/akiban/server/service/routines/ScriptCache.java 2013-04-03 13:41:34 +0000
+++ src/main/java/com/akiban/server/service/routines/ScriptCache.java 2013-04-11 23:35:24 +0000
@@ -61,8 +61,12 @@
61 return getEntry(session, routineName).getScriptEvaluator();61 return getEntry(session, routineName).getScriptEvaluator();
62 }62 }
6363
64 public ScriptPool<ScriptLibrary> getScriptLibrary(Session session, TableName routineName) {
65 return getEntry(session, routineName).getScriptLibrary();
66 }
67
64 public ScriptPool<ScriptInvoker> getScriptInvoker(Session session, TableName routineName) {68 public ScriptPool<ScriptInvoker> getScriptInvoker(Session session, TableName routineName) {
65 return getEntry(session, routineName).getScriptInvoker();69 return getEntry(session, routineName).getScriptInvoker(this, session);
66 }70 }
6771
68 protected ScriptEngineManager getManager(Session session) {72 protected ScriptEngineManager getManager(Session session) {
@@ -85,23 +89,25 @@
85 return entry;89 return entry;
86 }90 }
8791
88 static class CacheEntry {92 class CacheEntry {
89 private TableName routineName;93 private TableName routineName;
90 private String script;94 private String script;
95 private TableName libraryName;
91 private String function;96 private String function;
92 private ScriptEngineFactory factory;97 private ScriptEngineFactory factory;
93 private String threading;98 private String threading;
94 private boolean invocable, compilable;99 private boolean invocable, compilable;
95 private ScriptPool<ScriptEvaluator> sharedEvaluatorPool;100 private ScriptPool<ScriptEvaluator> sharedEvaluatorPool;
96 private ScriptPool<ScriptInvoker> sharedInvokerPool;101 private ScriptPool<ScriptLibrary> sharedLibraryPool;
97 private ScriptEngine spareEngine;102 private ScriptEngine spareEngine;
98103
99 public CacheEntry(Routine routine, ScriptEngine engine) {104 public CacheEntry(Routine routine, ScriptEngine engine) {
100 routineName = routine.getName();105 routineName = routine.getName();
101 script = routine.getDefinition();106 script = routine.getDefinition();
107 libraryName = routineName; // TODO: Until qualified EXTERNAL NAME supported.
102 function = routine.getMethodName();108 function = routine.getMethodName();
103 factory = engine.getFactory();109 factory = engine.getFactory();
104 threading = (String) factory.getParameter("THREADING");110 threading = (String)factory.getParameter("THREADING");
105 invocable = (engine instanceof Invocable);111 invocable = (engine instanceof Invocable);
106 compilable = (engine instanceof Compilable);112 compilable = (engine instanceof Compilable);
107 spareEngine = engine;113 spareEngine = engine;
@@ -127,9 +133,8 @@
127 }133 }
128 }134 }
129135
130 // Otherwise, every caller gets a new pool which only has the scope136 // Otherwise, every caller gets a new pool which only has
131 // of the137 // the scope of the prepared statement, etc.
132 // prepared statement, etc.
133 ScriptEngine engine;138 ScriptEngine engine;
134 synchronized (this) {139 synchronized (this) {
135 engine = spareEngine;140 engine = spareEngine;
@@ -149,42 +154,54 @@
149 }154 }
150 }155 }
151156
152 public ScriptPool<ScriptInvoker> getScriptInvoker() {157 public ScriptPool<ScriptLibrary> getScriptLibrary() {
153 // TODO - talk with Mike about having a CacheEntry without a function -158 assert invocable;
154 // needed for the LIBRARY param styl159 // Can share if at multi-threaded (or stronger), since we
155 assert invocable ; //&& (function != null);160 // are invoking the function.
156 // Can share if at multi-threaded (or stronger), since we are161 if ("MULTITHREADED".equals(threading) ||
157 // invoking162 "THREAD-ISOLATED".equals(threading) ||
158 // the function.163 "STATELESS".equals(threading)) {
159 if ("MULTITHREADED".equals(threading) || "THREAD-ISOLATED".equals(threading)
160 || "STATELESS".equals(threading)) {
161 synchronized (this) {164 synchronized (this) {
162 if (sharedInvokerPool == null) {165 if (sharedLibraryPool == null) {
163 ScriptEngine engine = spareEngine;166 ScriptEngine engine = spareEngine;
164 if (engine != null)167 if (engine != null)
165 spareEngine = null;168 spareEngine = null;
166 else169 else
167 engine = factory.getScriptEngine();170 engine = factory.getScriptEngine();
168 ScriptInvoker invoker = new Invoker(routineName, engine, script, function);171 ScriptLibrary library = new Library(routineName, engine, script);
169 sharedInvokerPool = new SharedPool<>(invoker);172 sharedLibraryPool = new SharedPool<>(library);
170 }173 }
171 return sharedInvokerPool;174 return sharedLibraryPool;
172 }175 }
173 }176 }
174177
175 // Otherwise, every caller gets a new pool which only has the scope178 // Otherwise, every caller gets a new pool which only has
176 // of the179 // the scope of the prepared statement, etc.
177 // prepared statement, etc.
178 ScriptEngine engine;180 ScriptEngine engine;
179 synchronized (this) {181 synchronized (this) {
180 engine = spareEngine;182 engine = spareEngine;
181 if (engine != null)183 if (engine != null)
182 spareEngine = null;184 spareEngine = null;
183 }185 }
184 Invoker invoker = null;186 Library library = null;
185 if (engine != null)187 if (engine != null)
186 invoker = new Invoker(routineName, engine, script, function);188 library = new Library(routineName, engine, script);
187 return new InvokerPool(routineName, factory, script, function, invoker);189 return new LibraryPool(routineName, factory, script, library);
190 }
191
192 public ScriptPool<ScriptInvoker> getScriptInvoker(ScriptCache cache, Session session) {
193 assert invocable && (function != null);
194 ScriptPool<ScriptLibrary> libraryPool;
195 if (routineName.equals(libraryName)) {
196 libraryPool = getScriptLibrary();
197 }
198 else {
199 synchronized (this) {
200 spareEngine = null;
201 }
202 libraryPool = cache.getScriptLibrary(session, libraryName);
203 }
204 return new InvokerPool(libraryPool, function);
188 }205 }
189 }206 }
190207
@@ -277,18 +294,14 @@
277 }294 }
278 }295 }
279296
280 static class InvokerPool extends BasePool<ScriptInvoker> {297 static class LibraryPool extends BasePool<ScriptLibrary> {
281 private final String function;298 public LibraryPool(TableName routineName, ScriptEngineFactory factory, String script, Library initial) {
282
283 public InvokerPool(TableName routineName, ScriptEngineFactory factory, String script, String function,
284 Invoker initial) {
285 super(routineName, factory, script, initial);299 super(routineName, factory, script, initial);
286 this.function = function;
287 }300 }
288301
289 @Override302 @Override
290 protected Invoker create() {303 protected Library create() {
291 return new Invoker(routineName, factory.getScriptEngine(), script, function);304 return new Library(routineName, factory.getScriptEngine(), script);
292 }305 }
293 }306 }
294307
@@ -396,14 +409,12 @@
396 }409 }
397 }410 }
398411
399 static class Invoker implements ScriptInvoker {412 static class Library implements ScriptLibrary {
400 private final TableName routineName;413 private final TableName routineName;
401 private final String function;
402 private final Invocable invocable;414 private final Invocable invocable;
403415
404 public Invoker(TableName routineName, ScriptEngine engine, String script, String function) {416 public Library(TableName routineName, ScriptEngine engine, String script) {
405 this.routineName = routineName;417 this.routineName = routineName;
406 this.function = function;
407 setScriptName(routineName, engine);418 setScriptName(routineName, engine);
408 try {419 try {
409 if (engine instanceof Compilable) {420 if (engine instanceof Compilable) {
@@ -420,42 +431,70 @@
420 }431 }
421432
422 @Override433 @Override
434 public String getEngineName() {
435 return ((ScriptEngine) invocable).getFactory().getEngineName();
436 }
437
438 @Override
439 public boolean isCompiled() {
440 return (invocable instanceof Compilable);
441 }
442
443 @Override
444 public Object invoke(String function, Object[] args) {
445 logger.debug("Calling {} in {}", function, routineName);
446 try {
447 return invocable.invokeFunction(function, args);
448 } catch (ScriptException ex) {
449 throw new ExternalRoutineInvocationException(routineName, ex);
450 } catch (NoSuchMethodException ex) {
451 throw new ExternalRoutineInvocationException(routineName, ex);
452 }
453 }
454 }
455
456 static class InvokerPool implements ScriptPool<ScriptInvoker> {
457 private final ScriptPool<ScriptLibrary> libraryPool;
458 private final String function;
459
460 public InvokerPool(ScriptPool<ScriptLibrary> libraryPool, String function) {
461 this.libraryPool = libraryPool;
462 this.function = function;
463 }
464
465 @Override
466 public ScriptInvoker get() {
467 return new Invoker(libraryPool.get(), function);
468 }
469
470 @Override
471 public void put(ScriptInvoker elem, boolean success) {
472 libraryPool.put(elem.getLibrary(), success);
473 }
474 }
475
476 static class Invoker implements ScriptInvoker {
477 private final ScriptLibrary library;
478 private final String function;
479
480 public Invoker(ScriptLibrary library, String function) {
481 this.library = library;
482 this.function = function;
483 }
484
485 @Override
486 public ScriptLibrary getLibrary() {
487 return library;
488 }
489
490 @Override
423 public String getFunctionName() {491 public String getFunctionName() {
424 return function;492 return function;
425 }493 }
426494
427 @Override495 @Override
428 public String getEngineName() {
429 return ((ScriptEngine) invocable).getFactory().getEngineName();
430 }
431
432 @Override
433 public boolean isCompiled() {
434 return (invocable instanceof Compilable);
435 }
436
437 @Override
438 public Object invoke(Object[] args) {496 public Object invoke(Object[] args) {
439 logger.debug("Calling {} in {}", function, routineName);497 return library.invoke(function, args);
440 try {
441 return invocable.invokeFunction(function, args);
442 } catch (ScriptException ex) {
443 throw new ExternalRoutineInvocationException(routineName, ex);
444 } catch (NoSuchMethodException ex) {
445 throw new ExternalRoutineInvocationException(routineName, ex);
446 }
447 }
448
449 @Override
450 public Object invokeNamedFunction(String functionName, Object[] args) {
451 logger.debug("Calling {} in {}", function, routineName);
452 try {
453 return invocable.invokeFunction(functionName, args);
454 } catch (ScriptException ex) {
455 throw new ExternalRoutineInvocationException(routineName, ex);
456 } catch (NoSuchMethodException ex) {
457 throw new ExternalRoutineInvocationException(routineName, ex);
458 }
459 }498 }
460 }499 }
461}500}
462501
=== modified file 'src/main/java/com/akiban/server/service/routines/ScriptInvoker.java'
--- src/main/java/com/akiban/server/service/routines/ScriptInvoker.java 2013-03-28 21:05:55 +0000
+++ src/main/java/com/akiban/server/service/routines/ScriptInvoker.java 2013-04-11 23:35:24 +0000
@@ -19,9 +19,7 @@
1919
20public interface ScriptInvoker20public interface ScriptInvoker
21{21{
22 public String getEngineName();22 public ScriptLibrary getLibrary();
23 public String getFunctionName();23 public String getFunctionName();
24 public boolean isCompiled();
25 public Object invoke(Object[] args);24 public Object invoke(Object[] args);
26 public Object invokeNamedFunction(String functionName, Object[] args);
27}25}
2826
=== added file 'src/main/java/com/akiban/server/service/routines/ScriptLibrary.java'
--- src/main/java/com/akiban/server/service/routines/ScriptLibrary.java 1970-01-01 00:00:00 +0000
+++ src/main/java/com/akiban/server/service/routines/ScriptLibrary.java 2013-04-11 23:35:24 +0000
@@ -0,0 +1,25 @@
1/**
2 * Copyright (C) 2009-2013 Akiban Technologies, Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18package com.akiban.server.service.routines;
19
20public interface ScriptLibrary
21{
22 public String getEngineName();
23 public boolean isCompiled();
24 public Object invoke(String function, Object[] args);
25}
026
=== modified file 'src/main/java/com/akiban/sql/script/ScriptFunctionJavaRoutine.java'
--- src/main/java/com/akiban/sql/script/ScriptFunctionJavaRoutine.java 2013-03-22 20:05:57 +0000
+++ src/main/java/com/akiban/sql/script/ScriptFunctionJavaRoutine.java 2013-04-11 23:35:24 +0000
@@ -32,6 +32,7 @@
32import com.akiban.server.explain.Label;32import com.akiban.server.explain.Label;
33import com.akiban.server.explain.PrimitiveExplainer;33import com.akiban.server.explain.PrimitiveExplainer;
34import com.akiban.server.service.routines.ScriptInvoker;34import com.akiban.server.service.routines.ScriptInvoker;
35import com.akiban.server.service.routines.ScriptLibrary;
35import com.akiban.server.service.routines.ScriptPool;36import com.akiban.server.service.routines.ScriptPool;
3637
37import java.sql.ResultSet;38import java.sql.ResultSet;
@@ -129,11 +130,12 @@
129 public CompoundExplainer getExplainer(ExplainContext context) {130 public CompoundExplainer getExplainer(ExplainContext context) {
130 Attributes atts = new Attributes();131 Attributes atts = new Attributes();
131 ScriptInvoker invoker = pool.get();132 ScriptInvoker invoker = pool.get();
133 ScriptLibrary library = invoker.getLibrary();
132 atts.put(Label.PROCEDURE_IMPLEMENTATION,134 atts.put(Label.PROCEDURE_IMPLEMENTATION,
133 PrimitiveExplainer.getInstance(invoker.getEngineName()));135 PrimitiveExplainer.getInstance(library.getEngineName()));
134 atts.put(Label.PROCEDURE_IMPLEMENTATION, 136 atts.put(Label.PROCEDURE_IMPLEMENTATION,
135 PrimitiveExplainer.getInstance(invoker.getFunctionName()));137 PrimitiveExplainer.getInstance(invoker.getFunctionName()));
136 if (invoker.isCompiled())138 if (library.isCompiled())
137 atts.put(Label.PROCEDURE_IMPLEMENTATION, 139 atts.put(Label.PROCEDURE_IMPLEMENTATION,
138 PrimitiveExplainer.getInstance("compiled"));140 PrimitiveExplainer.getInstance("compiled"));
139 pool.put(invoker, true); 141 pool.put(invoker, true);
140142
=== modified file 'src/test/java/com/akiban/server/service/routines/MockRoutineLoader.java'
--- src/test/java/com/akiban/server/service/routines/MockRoutineLoader.java 2013-03-22 20:05:57 +0000
+++ src/test/java/com/akiban/server/service/routines/MockRoutineLoader.java 2013-04-11 23:35:24 +0000
@@ -62,6 +62,11 @@
62 }62 }
6363
64 @Override64 @Override
65 public ScriptPool<ScriptLibrary> getScriptLibrary(Session session, TableName routineName) {
66 throw new UnsupportedOperationException();
67 }
68
69 @Override
65 public void unloadRoutine(Session session, TableName routineName) {70 public void unloadRoutine(Session session, TableName routineName) {
66 throw new UnsupportedOperationException();71 throw new UnsupportedOperationException();
67 }72 }

Subscribers

People subscribed via source and target branches